diff options
author | Michele Calgaro <michele.calgaro@yahoo.it> | 2022-12-04 19:16:43 +0900 |
---|---|---|
committer | Michele Calgaro <michele.calgaro@yahoo.it> | 2022-12-04 19:38:30 +0900 |
commit | fdcd72088371b3d8dfd31f2a5159861ce0be5535 (patch) | |
tree | 06c160cc34157344f62b6c19af297858a0e57157 /debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src | |
parent | a5d7db3b2c6171ea9e76b84155d2dfb66c243e5a (diff) | |
download | extra-dependencies-fdcd72088371b3d8dfd31f2a5159861ce0be5535.tar.gz extra-dependencies-fdcd72088371b3d8dfd31f2a5159861ce0be5535.zip |
uncrustify-trinity: updated based on upstream version 0.76.0
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
Diffstat (limited to 'debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src')
187 files changed, 71288 insertions, 0 deletions
diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/.kateconfig b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/.kateconfig new file mode 100644 index 00000000..4d9024f0 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/.kateconfig @@ -0,0 +1 @@ +kate: indent-width 3; diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/ChunkStack.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/ChunkStack.cpp new file mode 100644 index 00000000..dfa0f888 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/ChunkStack.cpp @@ -0,0 +1,120 @@ +/** + * @file ChunkStack.cpp + * Manages a chunk stack + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "ChunkStack.h" + + +void ChunkStack::Set(const ChunkStack &cs) +{ + m_cse.resize(cs.m_cse.size()); + + for (size_t idx = 0; idx < m_cse.size(); idx++) + { + m_cse[idx].m_pc = cs.m_cse[idx].m_pc; + m_cse[idx].m_seqnum = cs.m_cse[idx].m_seqnum; + } + + m_seqnum = cs.m_seqnum; +} + + +const ChunkStack::Entry *ChunkStack::Top() const +{ + if (!m_cse.empty()) + { + return(&m_cse[m_cse.size() - 1]); + } + return(nullptr); +} + + +const ChunkStack::Entry *ChunkStack::Get(size_t idx) const +{ + if (idx < m_cse.size()) + { + return(&m_cse[idx]); + } + return(nullptr); +} + + +Chunk *ChunkStack::GetChunk(size_t idx) const +{ + if (idx < m_cse.size()) + { + return(m_cse[idx].m_pc); + } + return(nullptr); +} + + +Chunk *ChunkStack::Pop_Front() +{ + Chunk *pc = nullptr; + + if (!m_cse.empty()) + { + pc = m_cse[0].m_pc; + m_cse.pop_front(); + } + return(pc); +} + + +Chunk *ChunkStack::Pop_Back() +{ + Chunk *pc = nullptr; + + if (!m_cse.empty()) + { + pc = m_cse[m_cse.size() - 1].m_pc; + m_cse.pop_back(); + } + return(pc); +} + + +void ChunkStack::Push_Back(Chunk *pc, size_t seqnum) +{ + m_cse.push_back(Entry(seqnum, pc)); + + if (m_seqnum < seqnum) + { + m_seqnum = seqnum; + } +} + + +void ChunkStack::Zap(size_t idx) +{ + if (idx < m_cse.size()) + { + m_cse[idx].m_pc = nullptr; + } +} + + +void ChunkStack::Collapse() +{ + size_t wr_idx = 0; + + for (size_t rd_idx = 0; rd_idx < m_cse.size(); rd_idx++) + { + if (m_cse[rd_idx].m_pc != nullptr) + { + if (rd_idx != wr_idx) + { + m_cse[wr_idx].m_pc = m_cse[rd_idx].m_pc; + m_cse[wr_idx].m_seqnum = m_cse[rd_idx].m_seqnum; + } + wr_idx++; + } + } + + m_cse.resize(wr_idx); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/ChunkStack.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/ChunkStack.h new file mode 100644 index 00000000..b33e1dd5 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/ChunkStack.h @@ -0,0 +1,123 @@ +/** + * @file ChunkStack.h + * Manages a simple stack of chunks + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef CHUNKSTACK_H_INCLUDED +#define CHUNKSTACK_H_INCLUDED + +#include "uncrustify_types.h" + +class ChunkStack +{ +public: + struct Entry + { + Entry() + : m_seqnum(0) + , m_pc(0) + { + } + + + Entry(const Entry &ref) + : m_seqnum(ref.m_seqnum) + , m_pc(ref.m_pc) + { + } + + + Entry(size_t sn, Chunk *pc) + : m_seqnum(sn) + , m_pc(pc) + { + } + + + size_t m_seqnum; + Chunk *m_pc; + }; + +protected: + std::deque<Entry> m_cse; + size_t m_seqnum; //! current sequence number + +public: + ChunkStack() + : m_seqnum(0) + { + } + + + ChunkStack(const ChunkStack &cs) + { + Set(cs); + } + + + virtual ~ChunkStack() + { + } + + + void Set(const ChunkStack &cs); + + + void Push_Back(Chunk *pc) + { + Push_Back(pc, ++m_seqnum); + } + + + bool Empty() const + { + return(m_cse.empty()); + } + + + size_t Len() const + { + return(m_cse.size()); + } + + + const Entry *Top() const; + + + const Entry *Get(size_t idx) const; + + + Chunk *GetChunk(size_t idx) const; + + + Chunk *Pop_Back(); + + + void Push_Back(Chunk *pc, size_t seqnum); + + + Chunk *Pop_Front(); + + + void Reset() + { + m_cse.clear(); + } + + + /** + * Mark an entry to be removed by Collapse() + * + * @param idx The item to remove + */ + void Zap(size_t idx); + + + //! Compresses down the stack by removing dead entries + void Collapse(); +}; + + +#endif /* CHUNKSTACK_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/EnumStructUnionParser.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/EnumStructUnionParser.cpp new file mode 100644 index 00000000..d1c7bc67 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/EnumStructUnionParser.cpp @@ -0,0 +1,2968 @@ +/** + * @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(E_Token); + + +/** + * Forward declarations + */ +static std::pair<Chunk *, Chunk *> match_variable_end(Chunk *, std::size_t); +static std::pair<Chunk *, Chunk *> match_variable_start(Chunk *, std::size_t); +static Chunk *skip_scope_resolution_and_nested_name_specifiers(Chunk *); +static Chunk *skip_scope_resolution_and_nested_name_specifiers_rev(Chunk *); + + +/** + * 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 *prev, Chunk *next) +{ + LOG_FUNC_ENTRY(); + + if ( prev != nullptr + && next != nullptr) + { + auto prev_token_type = prev->GetType(); + auto next_token_type = next->GetType(); + + 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(prev->GetClosingParen(E_Scope::PREPROC)->IsNotNullChunk()); + + 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 *prev, Chunk *next) +{ + LOG_FUNC_ENTRY(); + + if ( prev != nullptr + && next != nullptr) + { + auto prev_token_type = prev->GetType(); + auto next_token_type = next->GetType(); + + 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( next->IsPointerOrReference() + || 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(prev->GetClosingParen(E_Scope::PREPROC)->IsNotNullChunk()); + + 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( next->IsPointerOrReference() + || 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(prev->GetClosingParen(E_Scope::PREPROC)->IsNotNullChunk()); + + 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) + && ( next->IsPointerOrReference() + || 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( next->IsPointerOrReference() + || 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 = prev->GetClosingParen(E_Scope::PREPROC); + + if (next->IsNotNullChunk()) + { + next_token_type = next->GetType(); + } + 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( next->IsPointerOrReference() + || 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( next->IsPointerOrReference() + || 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(prev->GetClosingParen(E_Scope::PREPROC)->IsNotNullChunk()); + + 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( next->IsPointerOrReference() + || 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( next->IsPointerOrReference() + || 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 *pc, Chunk *after, bool test_equal = true) +{ + LOG_FUNC_ENTRY(); + + if ( pc != nullptr + && pc->IsNotNullChunk()) + { + if ( test_equal + && pc == after) + { + return(true); + } + else if (after != nullptr) + { + auto pc_column = pc->GetOrigCol(); + auto pc_line = pc->GetOrigLine(); + auto after_column = after->GetOrigCol(); + auto after_line = after->GetOrigLine(); + + 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 *pc, Chunk *before, bool test_equal = true) +{ + LOG_FUNC_ENTRY(); + + if ( pc != nullptr + && pc->IsNotNullChunk()) + { + if ( test_equal + && pc == before) + { + return(true); + } + else if (before != nullptr) + { + auto pc_column = pc->GetOrigCol(); + auto pc_line = pc->GetOrigLine(); + auto before_column = before->GetOrigCol(); + auto before_line = before->GetOrigLine(); + + 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 *pc, Chunk *after, Chunk *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 *pc) +{ + LOG_FUNC_ENTRY(); + + Chunk *next = Chunk::GetHead(); + + if ( ( language_is_set(LANG_CPP) + || language_is_set(LANG_C)) + && pc->Is(CT_WORD) + && !pc->TestFlags(PCF_IN_PREPROC)) + { + while (next->IsNotNullChunk()) + { + if ( next->TestFlags(PCF_IN_PREPROC) + && std::strcmp(pc->GetStr().c_str(), next->GetStr().c_str()) == 0) + { + return(true); + } + next = next->GetNextType(CT_MACRO); + } + } + return(false); +} // chunk_is_macro_reference + + +bool Chunk::IsPointerReferenceOrQualifier() const +{ + LOG_FUNC_ENTRY(); + + return( IsPointerOrReference() + || ( Is(CT_QUALIFIER) + && !IsCppInheritanceAccessSpecifier())); +} + + +/** + * 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 *, Chunk *> match_qualified_identifier(Chunk *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 = start->GetNextType(CT_DC_MEMBER); + + if ( double_colon->IsNotNullChunk() + && 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 *, Chunk *, Chunk *> match_variable(Chunk *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->IsNotNullChunk() + && start->IsNotNullChunk() + && ( end != nullptr + || identifier->GetPrevNcNnlNi()->Is(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 *, Chunk *> match_variable_end(Chunk *pc, std::size_t level) +{ + LOG_FUNC_ENTRY(); + + Chunk *identifier = nullptr; + + while ( pc != nullptr + && pc->IsNotNullChunk()) + { + /** + * skip any right-hand side assignments + */ + Chunk *rhs_exp_end = nullptr; + + if (pc->Is(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->IsNotNullChunk() + && pc->GetLevel() > level) + { + pc = pc->GetNextNcNnl(); + } + + /** + * skip to any following match for angle brackets, braces, parens, + * or square brackets + */ + if ( pc->Is(CT_ANGLE_OPEN) + || pc->Is(CT_BRACE_OPEN) + || pc->IsParenOpen() + || pc->Is(CT_SQUARE_OPEN)) + { + pc = pc->GetClosingParen(E_Scope::PREPROC); + } + /** + * call a separate function to validate adjacent tokens as potentially + * matching a variable declaration/definition + */ + + Chunk *next = pc->GetNextNcNnl(); + + if ( next->IsNot(CT_COMMA) + && next->IsNot(CT_FPAREN_CLOSE) + && !next->IsSemicolon() + && !adj_tokens_match_var_def_pattern(pc, next)) + { + /** + * error, pattern is not consistent with a variable declaration/definition + */ + break; + } + + if ( pc->Is(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 ( next->Is(CT_COMMA) + || next->Is(CT_FPAREN_CLOSE) + || next->IsSemicolon()) + { + 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 *, Chunk *> match_variable_start(Chunk *pc, std::size_t level) +{ + LOG_FUNC_ENTRY(); + + Chunk *identifier = Chunk::NullChunkPtr; + + if (pc == nullptr) + { + pc = Chunk::NullChunkPtr; + } + + while (pc->IsNotNullChunk()) + { + /** + * skip any right-hand side assignments + */ + Chunk *before_rhs_exp_start = skip_expression_rev(pc); + Chunk *prev = Chunk::NullChunkPtr; + Chunk *next = pc; + + while ( chunk_is_after(next, before_rhs_exp_start) + && pc != prev) + { + next = prev; + prev = next->GetPrevNcNnlNi(); + + if (next->Is(CT_ASSIGN)) + { + pc = prev; + } + } + /** + * skip current and preceding chunks if at a higher brace level + */ + + while ( pc->IsNotNullChunk() + && pc->GetLevel() > level) + { + pc = pc->GetPrevNcNnlNi(); + } + + /** + * skip to any preceding match for angle brackets, braces, parens, + * or square brackets + */ + if ( pc->Is(CT_ANGLE_CLOSE) + || pc->Is(CT_BRACE_CLOSE) + || pc->IsParenClose() + || pc->Is(CT_SQUARE_CLOSE)) + { + pc = pc->GetOpeningParen(E_Scope::PREPROC); + } + /** + * call a separate function to validate adjacent tokens as potentially + * matching a variable declaration/definition + */ + + prev = pc->GetPrevNcNnlNi(); + + 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 ( prev->IsNot(CT_WORD) + || ( !pc->IsPointerOrReference() + && pc->IsNot(CT_WORD))) + { + /** + * error, pattern is not consistent with a variable declaration/definition + */ + + break; + } + } + + if ( identifier->IsNullChunk() + && pc->Is(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 ( prev->Is(CT_ANGLE_CLOSE) + || prev->Is(CT_BRACE_CLOSE) + || prev->Is(CT_COMMA) + || prev->Is(CT_TYPE) + || prev->Is(CT_WORD)) + { + return(std::make_pair(pc, identifier)); + } + pc = prev; + } + return(std::make_pair(Chunk::NullChunkPtr, Chunk::NullChunkPtr)); +} // 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 *skip_scope_resolution_and_nested_name_specifiers(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + if ( ( pc != nullptr + && pc->TestFlags(PCF_IN_TEMPLATE)) + || pc->Is(CT_DC_MEMBER) + || pc->Is(CT_TYPE) + || pc->Is(CT_WORD)) + { + while (pc->IsNotNullChunk()) + { + /** + * skip to any following match for angle brackets + */ + if (pc->Is(CT_ANGLE_OPEN)) + { + pc = pc->GetClosingParen(E_Scope::PREPROC); + } + Chunk *next = pc->GetNextNcNnl(); + + /** + * 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 *skip_scope_resolution_and_nested_name_specifiers_rev(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + if (pc == nullptr) + { + pc = Chunk::NullChunkPtr; + } + + if ( ( pc->IsNotNullChunk() + && pc->TestFlags(PCF_IN_TEMPLATE)) + || pc->Is(CT_DC_MEMBER) + || pc->Is(CT_TYPE) + || pc->Is(CT_WORD)) + { + while (pc->IsNotNullChunk()) + { + /** + * skip to any preceding match for angle brackets + */ + if (pc->Is(CT_ANGLE_CLOSE)) + { + pc = pc->GetOpeningParen(E_Scope::PREPROC); + } + Chunk *prev = pc->GetPrevNcNnlNi(); + + /** + * 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 *template_end = get_template_end(); + auto *body_end = get_body_end(); + auto *body_start = get_body_start(); + T_PcfFlags flags = PCF_VAR_1ST_DEF; + auto *inheritance_start = get_inheritance_start(); + Chunk *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 (pc == nullptr) + { + pc = Chunk::NullChunkPtr; + } + + if (pc->GetNextNcNnl() == m_end) + { + /** + * we're likely at the end of a class/enum/struct/union body which lacks + * any trailing inline definitions + */ + + pc = m_end->GetNextNcNnl(); + } + + if ( type_identified() + || pc->IsClassEnumStructOrUnion() + || 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 = pc->GetNextNcNnl(); + } + + 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 *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->GetLevel()); + 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 = pc->GetNextNcNnl(); + + /** + * skip any right-hand side assignments + */ + if (pc->Is(CT_ASSIGN)) + { + pc = skip_to_expression_end(pc); + } + + /** + * if we're sitting at a comma or semicolon, skip it + */ + if ( pc->IsSemicolon() + || ( pc->Is(CT_COMMA) + && !pc->GetFlags().test_any(PCF_IN_FCN_DEF | PCF_IN_FCN_CALL | PCF_IN_TEMPLATE) + && !chunk_is_between(pc, inheritance_start, body_start))) + { + pc = pc->GetNextNcNnl(); + } + } + /** + * 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 ( m_start->IsClassOrStruct() + && ( m_start->IsNot(CT_STRUCT) + || !language_is_set(LANG_C))) + { + /** + * if a type has been identified, 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 + */ + m_type->SetFlagBits(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 *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 *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 *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 *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 *EnumStructUnionParser::get_inheritance_end() const +{ + LOG_FUNC_ENTRY(); + + Chunk *brace_open = nullptr; + auto *inheritance_start = get_inheritance_start(); + + if (inheritance_start != nullptr) + { + brace_open = get_body_start(); + + if (brace_open == nullptr) + { + brace_open = inheritance_start->GetNextType(CT_BRACE_OPEN, m_start->GetLevel(), E_Scope::ALL); + } + } + return(brace_open); +} // EnumStructUnionParser::get_inheritance_end + + +Chunk *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 *> 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 *>()); +} // EnumStructUnionParser::get_question_operators + + +Chunk *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 *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 *> 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 *>()); +} // EnumStructUnionParser::get_top_level_commas + + +Chunk *EnumStructUnionParser::get_where_end() const +{ + LOG_FUNC_ENTRY(); + + Chunk *brace_open = nullptr; + auto *where_start = get_where_start(); + + if (where_start != nullptr) + { + brace_open = get_body_start(); + + if (brace_open == nullptr) + { + brace_open = where_start->GetNextType(CT_BRACE_OPEN, m_start->GetLevel(), E_Scope::ALL); + } + } + return(brace_open); +} // EnumStructUnionParser::get_where_end + + +Chunk *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 *pc) +{ + LOG_FUNC_ENTRY(); + + parse_error_detected(false); + m_chunk_map.clear(); + + m_start = pc; + m_type = nullptr; + pc = try_find_end_chunk(pc); + + if (parse_error_detected()) + { + return; + } + m_end = refine_end_chunk(pc); +} // EnumStructUnionParser::initialize + + +bool EnumStructUnionParser::is_potential_end_chunk(Chunk *pc) const +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LFTOR, "%s(%d): orig line is %zu, orig col is %zu, type is %s\n", + __unqualified_func__, __LINE__, + pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + + /** + * test for a semicolon or closing brace at the level of the starting chunk + */ + if ( pc->IsNullChunk() + || parse_error_detected() + || ( ( pc->IsSemicolon() + || pc->Is(CT_BRACE_CLOSE)) + && pc->GetLevel() == m_start->GetLevel())) + { + LOG_FMT(LFTOR, "%s(%d): orig line is %zu, orig col is %zu, type is %s\n", + __unqualified_func__, __LINE__, + pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + 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->GetFlags() & PCF_IN_FCN_DEF; + auto const pc_in_preproc = pc->GetFlags() & PCF_IN_PREPROC; + auto const start_in_funcdef = m_start->GetFlags() & PCF_IN_FCN_DEF; + auto const start_in_preproc = m_start->GetFlags() & PCF_IN_PREPROC; + + /** + * the following may identify cases where we've reached the + * end of a cast terminated by a closing paren + */ + if ( ( pc->IsParenClose() // Issue #3538 + && pc->GetLevel() < m_start->GetLevel()) + || (start_in_funcdef ^ pc_in_funcdef).test_any() + || (start_in_preproc ^ pc_in_preproc).test_any()) + { + LOG_FMT(LFTOR, "%s(%d): orig line is %zu, orig col is %zu, type is %s\n", + __unqualified_func__, __LINE__, + pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + 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) + { + LOG_FMT(LFTOR, "%s(%d): orig line is %zu, orig col is %zu, type is %s\n", + __unqualified_func__, __LINE__, + pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + 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->GetFlags() & PCF_IN_FCN_CALL; + auto const start_in_funccall = m_start->GetFlags() & PCF_IN_FCN_CALL; + + if ( ( pc_in_funccall.test_any() + && start_in_funccall.test_any() + && pc->Is(CT_COMMA) + && pc->GetLevel() == m_start->GetLevel()) + || ( pc_in_funcdef.test_any() + && ( ( pc->Is(CT_FPAREN_CLOSE) + && pc->GetLevel() < m_start->GetLevel()) + || ( ( pc->Is(CT_ASSIGN) + || pc->Is(CT_COMMA)) + && pc->GetLevel() == m_start->GetLevel())))) + { + LOG_FMT(LFTOR, "%s(%d): orig line is %zu, orig col is %zu, type is %s\n", + __unqualified_func__, __LINE__, + pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + return(true); + } + LOG_FMT(LFTOR, "%s(%d): orig line is %zu, orig col is %zu, type is %s\n", + __unqualified_func__, __LINE__, + pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + return(false); +} // EnumStructUnionParser::is_potential_end_chunk + + +bool EnumStructUnionParser::is_within_conditional(Chunk *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 *pc) const +{ + LOG_FUNC_ENTRY(); + + if ( pc != nullptr + && pc->TestFlags(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 *pc) const +{ + LOG_FUNC_ENTRY(); + + if ( pc != nullptr + && pc->TestFlags(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 *pc) +{ + LOG_FUNC_ENTRY(); + + T_PcfFlags flags = PCF_VAR_1ST_DEF; + + while ( pc != nullptr + && pc->IsNotNullChunk()) + { + pc->SetFlagBits(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->ResetFlagBits(PCF_VAR_TYPE); + + Chunk *next = pc->GetNextNcNnl(E_Scope::PREPROC); + + if (next->Is(CT_DC_MEMBER)) + { + /** + * just in case it's a templated type + */ + pc = skip_template_prev(pc); + + if (pc->Is(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! + */ + pc->SetType(CT_TYPE); + } + } + else if ( ( next->Is(CT_BRACE_OPEN) + || ( next->Is(CT_COMMA) + && !is_within_where_clause(next))) + && next->GetLevel() == m_start->GetLevel()) + { + /** + * just in case it's a templated type + */ + pc = skip_template_prev(pc); + + if (pc->Is(CT_WORD)) + { + pc->SetFlagBits(flags); + + if (flags & PCF_VAR_1ST) + { + flags &= ~PCF_VAR_1ST; // clear the first flag for the next items + } + } + + if (next->Is(CT_BRACE_OPEN)) + { + break; + } + } + pc = next; + } + pc->SetFlagBits(PCF_IN_CLASS_BASE); +} // EnumStructUnionParser::mark_base_classes + + +void EnumStructUnionParser::mark_braces(Chunk *brace_open) +{ + LOG_FUNC_ENTRY(); + + T_PcfFlags flags = PCF_NONE; + + if (m_start->Is(CT_CLASS)) + { + flags = PCF_IN_CLASS; + } + else if (m_start->IsEnum()) + { + flags = PCF_IN_ENUM; + } + else if (m_start->Is(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 (m_start->IsClassStructOrUnion()) + { + 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); + } + } + brace_open->SetParentType(m_start->GetType()); + + auto *brace_close = brace_open->GetClosingParen(E_Scope::PREPROC); + + if (brace_close->IsNotNullChunk()) + { + brace_close->SetParentType(m_start->GetType()); + } +} // EnumStructUnionParser::mark_braces + + +void EnumStructUnionParser::mark_class_colon(Chunk *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->GetOrigLine(), + colon->GetOrigCol()); + + colon->SetType(CT_CLASS_COLON); + colon->SetParentType(m_start->GetType()); +} // EnumStructUnionParser::mark_class_colon + + +void EnumStructUnionParser::mark_conditional_colon(Chunk *colon) +{ + colon->SetType(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() + && m_start->IsClassOrStruct()) + { + 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->GetOrigLine(), + m_start->GetOrigCol(), + m_start->Text(), + get_token_name(m_start->GetParentType())); + + log_pcf_flags(LFTOR, m_start->GetFlags()); + + /** + * 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->GetFlags()); + + Chunk *next = Chunk::NullChunkPtr; + std::size_t level = m_type->GetBraceLevel() + 1; + + for (auto *prev = body_start; next != body_end; prev = next) + { + prev->SetFlagBits(PCF_IN_CLASS); + + next = skip_template_next(prev->GetNextNcNnl(E_Scope::PREPROC)); // Issue #3368 + + /** + * find a chunk within the class/struct body that + */ + if ( prev->IsNotNullChunk() + && std::strcmp(prev->Text(), name) == 0 + && prev->GetLevel() == level + && next->IsParenOpen()) + { + prev->SetType(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->GetOrigLine(), + prev->GetOrigCol(), + get_token_name(prev->GetType())); + + mark_cpp_constructor(prev); + } + } + + next->SetFlagBits(PCF_IN_CLASS); + } +} // EnumStructUnionParser::mark_constructor + + +void EnumStructUnionParser::mark_enum_integral_type(Chunk *colon) +{ + LOG_FUNC_ENTRY(); + + colon->SetType(CT_BIT_COLON); + colon->SetParentType(m_start->GetType()); + + auto *body_start = get_body_start(); + auto *pc = colon->GetNextNcNnl(); + + /** + * 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 + && pc->IsNot(CT_BRACE_OPEN) + && !pc->IsSemicolon()) + { + /** + * 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 + */ + if (pc->IsNot(CT_DC_MEMBER)) // Issue #3198 + { + pc->ResetFlagBits(PCF_VAR_TYPE); + pc->SetType(CT_TYPE); + pc->SetParentType(colon->GetType()); + } + pc = pc->GetNextNcNnl(); + } +} // 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 *next = m_start; + Chunk *prev = Chunk::NullChunkPtr; + + /** + * 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 (next->GetParentType() == CT_TEMPLATE) + { + while (true) + { + prev = next->GetPrevNcNnlNi(); + + if ( prev->IsNullChunk() + || ( !prev->TestFlags(PCF_IN_TEMPLATE) + && prev->IsNot(CT_TEMPLATE))) + { + break; + } + next = prev; + } + } + Chunk *body_end = get_body_end(); + Chunk *body_start = get_body_start(); + + while (next != m_end) + { + if ( !chunk_is_between(next, body_start, body_end) + && next->TestFlags(PCF_LVALUE)) + { + next->ResetFlagBits(PCF_LVALUE); + } + else if ( ( next->Is(CT_ASSIGN) + || next->Is(CT_BRACE_OPEN)) + && prev->Is(CT_WORD) + && prev->GetFlags().test_any(PCF_VAR_DEF | PCF_VAR_1ST | PCF_VAR_INLINE)) + { + prev->SetFlagBits(PCF_LVALUE); + } + prev = next; + next = next->GetNextNcNnl(); + } +} // EnumStructUnionParser::mark_extracorporeal_lavlues + + +void EnumStructUnionParser::mark_nested_name_specifiers(Chunk *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 = pc->GetNextNcNnl()) + { + if (pc->Is(CT_WORD)) + { + /** + * if the next token is an opening angle, then we can safely + * mark the current identifier as a type + */ + auto *next = pc->GetNextNcNnl(); + + if (next->Is(CT_ANGLE_OPEN)) + { + /** + * the template may have already been previously marked elsewhere... + */ + auto *angle_open = next; + auto *angle_close = angle_open->GetClosingParen(E_Scope::PREPROC); + + if (angle_close->IsNullChunk()) + { + // 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->GetOrigLine(), + angle_open->GetOrigCol()); + + break; + } + pc->SetType(CT_TYPE); + mark_template(next); + pc = angle_close; + } + else if ( is_within_inheritance_list(pc) + && ( next->Is(CT_COMMA) + || next->Is(CT_BRACE_OPEN))) + { + pc->SetType(CT_TYPE); + } + } + } +} // EnumStructUnionParser::mark_nested_name_specifiers + + +void EnumStructUnionParser::mark_pointer_types(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + if (pc->Is(CT_WORD)) + { + do + { + // TODO: should there be a CT_BYREF_TYPE? + pc = pc->GetPrevNcNnlNi(); + + if (pc->IsPointerOperator()) + { + pc->SetParentType(m_start->GetType()); + pc->SetType(CT_PTR_TYPE); + } + } while (pc->IsPointerReferenceOrQualifier()); + } +} // EnumStructUnionParser::mark_pointer_types + + +void EnumStructUnionParser::mark_template(Chunk *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->GetOrigLine(), + start->GetOrigCol()); + } + start->SetParentType(CT_TEMPLATE); + + auto *end = start->GetClosingParen(E_Scope::PREPROC); + + if (end->IsNotNullChunk()) + { + end->SetParentType(CT_TEMPLATE); + + mark_template_args(start, end); + } +} // EnumStructUnionParser::mark_template + + +void EnumStructUnionParser::mark_template_args(Chunk *start, Chunk *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->GetOrigLine(), + start->GetOrigCol()); + + T_PcfFlags flags = PCF_IN_TEMPLATE; + Chunk *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 = next->GetNextNcNnl(); + + if (next == end) + { + break; + } + next->SetFlagBits(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->GetOrigLine(), + end->GetOrigCol()); + } +} // EnumStructUnionParser::mark_template_args + + +void EnumStructUnionParser::mark_type(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + if (pc != nullptr) + { + m_type = pc; + + do + { + make_type(pc); + pc->SetParentType(m_start->GetType()); + pc = pc->GetNextNcNnl(E_Scope::PREPROC); + } while (pc->IsPointerOrReference()); + } +} // EnumStructUnionParser::mark_type + + +void EnumStructUnionParser::mark_variable(Chunk *variable, T_PcfFlags 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->GetOrigLine(), + variable->GetOrigCol(), + flags & PCF_VAR_1ST_DEF ? "PCF_VAR_1ST_DEF" : "PCF_VAR_1ST"); + + variable->SetFlagBits(flags); + variable->SetType(CT_WORD); + mark_pointer_types(variable); + } +} // EnumStructUnionParser::mark_variable + + +void EnumStructUnionParser::mark_where_clause(Chunk *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->GetOrigLine(), + where->GetOrigCol()); + } + set_where_start(where); + + auto *where_end = get_where_end(); + auto *where_start = get_where_start(); + + set_where_end(where_end); + + T_PcfFlags flags; + + for (auto *pc = where_start; pc != where_end; pc = pc->GetNextNcNnl()) + { + flags = mark_where_chunk(pc, m_start->GetType(), flags); + } +} // EnumStructUnionParser::mark_where_clause + + +void EnumStructUnionParser::mark_where_colon(Chunk *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->GetOrigLine(), + colon->GetOrigCol()); + } + colon->SetType(CT_WHERE_COLON); + colon->SetParentType(m_start->GetType()); +} // EnumStructUnionParser::mark_where_colon + + +void EnumStructUnionParser::parse(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + initialize(pc); + + if (parse_error_detected()) + { + return; + } + + /** + * make sure this wasn't a cast, and also make sure we're + * actually dealing with a class/enum/struct/union type + */ + if ( m_start->GetParentType() == CT_C_CAST + || !m_start->IsClassEnumStructOrUnion()) + { + return; + } + Chunk *prev = m_start; + Chunk *next = prev->GetNextNcNnl(); + + /** + * the enum-key might be enum, enum class or enum struct + */ + if (next->IsEnum()) + { + prev = next; + next = prev->GetNextNcNnl(); + } + else if (prev->IsEnum()) + { + Chunk *prev_prev = prev->GetPrevNcNnlNi(); + + if ( prev_prev->IsEnum() + && prev->IsEnum()) + { + 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 (next->Is(CT_ASSIGN)) + { + next = skip_to_expression_end(next); + } + + if ( next->Is(CT_ANGLE_OPEN) + && !template_detected()) + { + next = parse_angles(next); + } + else if ( next->Is(CT_BRACE_OPEN) + && !body_detected()) + { + next = parse_braces(next); + } + else if (next->IsColon()) + { + parse_colon(next); + } + else if (next->Is(CT_COMMA)) + { + record_top_level_comma(next); + } + else if (next->Is(CT_DC_MEMBER)) + { + next = parse_double_colon(next); + } + else if ( next->IsParenOpen() + && ( language_is_set(LANG_D) + || ( language_is_set(LANG_PAWN) + && m_start->IsEnum()))) + { + set_paren_parent(next, m_start->GetType()); + + if ( prev->Is(CT_WORD) + && language_is_set(LANG_D)) + { + mark_template(next); + } + next = next->GetClosingParen(E_Scope::PREPROC); + } + else if ( next->Is(CT_QUALIFIER) + && language_is_set(LANG_JAVA) + && std::strncmp(next->GetStr().c_str(), "implements", 10) == 0) + { + mark_base_classes(next); + } + else if (next->Is(CT_QUESTION)) + { + record_question_operator(next); + } + else if ( next->Is(CT_WHERE) + && !where_clause_detected()) + { + mark_where_clause(next); + } + prev = next; + + do + { + next = next->GetNextNcNnl(); + } while ( next->IsNotNullChunk() + && next->GetLevel() > m_start->GetLevel()); + } + /** + * identify the type and/or variable(s) + */ + analyze_identifiers(); + + /** + * identify and mark lvalues occurring outside the body definition + */ + mark_extracorporeal_lvalues(); + + if ( prev->IsNotNullChunk() + && prev->IsSemicolon() + && prev->GetLevel() == m_start->GetLevel() + && !prev->TestFlags(PCF_IN_FOR)) + { + prev->SetParentType(m_start->GetType()); + } +} // EnumStructUnionParser::parse + + +Chunk *EnumStructUnionParser::parse_angles(Chunk *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 = angle_open->GetClosingParen(E_Scope::PREPROC); + + if (angle_close->IsNullChunk()) + { + // 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->GetOrigLine(), + angle_open->GetOrigCol()); + } + else + { + /** + * check to make sure that the template is the final chunk in a list + * of scope-resolution qualifications + */ + auto *next = angle_close->GetNextNcNnl(); + + if (next->IsNot(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 = angle_open->GetPrevNcNnlNi(); + + if (prev->IsNot(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->GetOrigLine(), + angle_open->GetOrigCol()); + } + 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 *EnumStructUnionParser::parse_braces(Chunk *brace_open) +{ + LOG_FUNC_ENTRY(); + + /** + * check to see if there's a matching closing brace + */ + + auto *pc = brace_open; + auto *brace_close = pc->GetClosingParen(E_Scope::PREPROC); + + if (brace_close->IsNotNullChunk()) + { + /** + * 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 = pc->GetPrevNcNnlNi(); + + /** + * 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 + */ + bool is_potential_function_definition = false; + + if ( ( language_is_set(LANG_C) + || language_is_set(LANG_CPP)) + && prev->IsParenClose()) + { + /** + * we may be dealing with a c/cpp function definition, where the 'struct' + * or 'class' keywords appear as the return type preceding a pair of braces + * and therefore may be associated with a function definition body + */ + auto *paren_close = prev; + + // skip in reverse to the matching open paren + auto *paren_open = paren_close->GetOpeningParen(); + + if (paren_open->IsNotNullChunk()) + { + /** + * determine if there's an identifier preceding the open paren; + * if so, the identifier is very likely to be associated with + * a function definition + */ + auto *type = m_start->GetNextNcNnl(); + auto *identifier = paren_open->GetPrevNcNnlNi(E_Scope::PREPROC); + is_potential_function_definition = ( ( identifier->Is(CT_FUNCTION) + || identifier->Is(CT_FUNC_DEF) + || identifier->Is(CT_WORD)) + && type != identifier); + } + } + + if ( language_is_set(LANG_D) + || language_is_set(LANG_PAWN) + || !prev->IsParenClose() + || is_potential_function_definition + || 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) + && m_start->IsEnum()) + { + 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->GetOrigLine(), + brace_open->GetOrigCol()); + + // parse error + parse_error_detected(true); + } + } + return(pc); +} // EnumStructUnionParser::parse_braces + + +void EnumStructUnionParser::parse_colon(Chunk *colon) +{ + LOG_FUNC_ENTRY(); + + if (m_start->Is(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->GetOrigLine(), + colon->GetOrigCol()); + + // 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 (m_start->IsClassOrStruct()) + { + /** + * the colon likely specifies an inheritance list for a struct + * or class type + */ + + set_inheritance_start(colon); + mark_class_colon(colon); + } + else if (m_start->IsEnum()) + { + set_enum_base_start(colon); + mark_enum_integral_type(colon); + } + } +} // EnumStructUnionParser::parse_colon + + +Chunk *EnumStructUnionParser::parse_double_colon(Chunk *double_colon) +{ + LOG_FUNC_ENTRY(); + + auto *pc = double_colon; + + if ( language_is_set(LANG_CPP) + && pc->Is(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 *question) +{ + LOG_FUNC_ENTRY(); + + if (question->Is(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 *comma) +{ + if ( comma != nullptr + && comma->GetLevel() == m_start->GetLevel() + && !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 *EnumStructUnionParser::refine_end_chunk(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + if ( ( language_is_set(LANG_C) + || language_is_set(LANG_CPP)) + && pc->Is(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 = pc->GetNextNcNnl(); + + while (true) + { + if (next->IsSemicolon()) + { + pc = next; + + break; + } + else + { + /** + * if we're sitting at a comma, skip it + */ + if (next->Is(CT_COMMA)) + { + next = next->GetNextNcNnl(); + } + auto match = match_variable(next, m_start->GetLevel()); + 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 = end->GetNextNcNnl(); + + /** + * skip any right-hand side assignments + */ + if (pc->Is(CT_ASSIGN)) + { + pc = skip_to_expression_end(pc); + } + next = pc; + } + } + } + } + return(pc); +} // EnumStructUnionParser::refine_end_chunk + + +void EnumStructUnionParser::set_body_end(Chunk *body_end) +{ + LOG_FUNC_ENTRY(); + + if (body_end->Is(CT_BRACE_CLOSE)) + { + m_chunk_map[CT_BRACE_CLOSE][0] = body_end; + } +} // EnumStructUnionParser::set_body_end + + +void EnumStructUnionParser::set_body_start(Chunk *body_start) +{ + LOG_FUNC_ENTRY(); + + if (body_start->Is(CT_BRACE_OPEN)) + { + m_chunk_map[CT_BRACE_OPEN][0] = body_start; + } +} // EnumStructUnionParser::set_body_start + + +void EnumStructUnionParser::set_enum_base_start(Chunk *enum_base_start) +{ + LOG_FUNC_ENTRY(); + + if (enum_base_start->IsColon()) + { + m_chunk_map[CT_BIT_COLON][0] = enum_base_start; + } +} // EnumStructUnionParser::set_enum_base_start + + +void EnumStructUnionParser::set_inheritance_start(Chunk *inheritance_start) +{ + LOG_FUNC_ENTRY(); + + if (inheritance_start->IsColon()) + { + m_chunk_map[CT_COLON][0] = inheritance_start; + } +} // EnumStructUnionParser::set_inheritance_start + + +void EnumStructUnionParser::set_template_end(Chunk *template_end) +{ + LOG_FUNC_ENTRY(); + + if (template_end->Is(CT_ANGLE_CLOSE)) + { + m_chunk_map[CT_ANGLE_CLOSE][0] = template_end; + } +} // EnumStructUnionParser::set_template_end + + +void EnumStructUnionParser::set_template_start(Chunk *template_start) +{ + LOG_FUNC_ENTRY(); + + if (template_start->Is(CT_ANGLE_OPEN)) + { + m_chunk_map[CT_ANGLE_OPEN][0] = template_start; + } +} // EnumStructUnionParser::set_template_start + + +void EnumStructUnionParser::set_where_end(Chunk *where_end) +{ + LOG_FUNC_ENTRY(); + + if (where_end->Is(CT_BRACE_OPEN)) + { + m_chunk_map[CT_WHERE][0] = where_end; + } +} // EnumStructUnionParser::set_where_end + + +void EnumStructUnionParser::set_where_start(Chunk *where_start) +{ + LOG_FUNC_ENTRY(); + + if (where_start->Is(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 *EnumStructUnionParser::try_find_end_chunk(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LFTOR, "%s(%d): orig line is %zu, orig col is %zu, type is %s\n", + __unqualified_func__, __LINE__, + pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + + do + { + LOG_FMT(LFTOR, "%s(%d): orig line is %zu, orig col is %zu, type is %s\n", + __unqualified_func__, __LINE__, + pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + + /** + * 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 ( pc->Is(CT_TYPE) + || pc->Is(CT_WORD)) + { + pc->SetType(CT_WORD); + pc->SetParentType(CT_NONE); + } + LOG_FMT(LFTOR, "%s(%d): orig line is %zu, orig col is %zu, type is %s\n", + __unqualified_func__, __LINE__, + pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + + do + { + pc = pc->GetNextNcNnl(E_Scope::PREPROC); + LOG_FMT(LFTOR, "%s(%d): orig line is %zu, orig col is %zu, type is %s\n", + __unqualified_func__, __LINE__, + pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + } while ( pc->IsNotNullChunk() + && pc->GetLevel() > m_start->GetLevel()); + + if (pc->IsNullChunk()) + { + LOG_FMT(LFTOR, "%s(%d): IsNullChunk\n", + __unqualified_func__, __LINE__); + // parse error + parse_error_detected(true); + return(Chunk::NullChunkPtr); + } + else + { + LOG_FMT(LFTOR, "%s(%d): orig line is %zu, orig col is %zu, type is %s\n", + __unqualified_func__, __LINE__, + pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + } + } 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 *pc = m_start; + Chunk *prev = Chunk::NullChunkPtr; + + do + { + if ( !chunk_is_between(prev, inheritance_start, body_start) + && ( prev->Is(CT_WORD) + || prev->Is(CT_FUNCTION) + || prev->Is(CT_FUNC_DEF)) + && !prev->GetFlags().test_any(PCF_VAR_DEF | PCF_VAR_1ST | PCF_VAR_INLINE) + && prev->GetLevel() == m_start->GetLevel()) + { + if (pc->IsParenOpen()) + { + auto *paren_open = pc; + auto *paren_close = paren_open->GetClosingParen(E_Scope::PREPROC); + + if (paren_close->IsNotNullChunk()) + { + paren_open->SetType(CT_FPAREN_OPEN); + paren_open->SetParentType(CT_MACRO_FUNC_CALL); + paren_close->SetType(CT_FPAREN_CLOSE); + paren_close->SetParentType(CT_MACRO_FUNC_CALL); + prev->SetType(CT_MACRO_FUNC_CALL); + } + } + } + prev = pc; + pc = prev->GetNextNcNnl(); + } 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 *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 *type = nullptr; + Chunk *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->GetFlags().test_any(PCF_VAR_DEF | PCF_VAR_1ST | PCF_VAR_INLINE)) + { + break; + } + else if ( pc->Is(CT_WORD) + || pc->Is(CT_ANGLE_CLOSE)) + { + type = skip_template_prev(pc); + } + pc = pc->GetNextNcNnl(); + } 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 *pc = get_body_start(); + + if ( language_is_set(LANG_PAWN) + && m_start->IsEnum()) + { + set_paren_parent(pc, m_start->GetType()); + } + 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 (m_start->Is(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->GetOrigLine(), + m_start->GetOrigCol()); + + parse_error_detected(true); + + return(false); + } + } + + if (pc == nullptr) + { + Chunk *next = m_start->GetNextNcNnl(); + + /** + * 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 *next_next = next->GetNextNcNnl(); + + /** + * 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->IsNotNullChunk() + && next->Is(CT_WORD) + && next_next->Is(CT_WORD) + && m_end->GetPrevNcNnlNi() == 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) + || m_start->GetParentType() == CT_TEMPLATE) + { + pc = m_end; + } + else + { + pc = next_next; + } + } + else + { + /** + * search for some common patterns that may indicate a type + */ + Chunk *prev = m_start; + + while ( chunk_is_between(next, m_start, m_end) + && ( ( next->IsNot(CT_ASSIGN) + && next->IsNot(CT_COMMA)) + || next->GetLevel() != m_start->GetLevel()) + && !next->IsSemicolon()) + { + prev = next; + next = next->GetNextNcNnl(); + + /** + * 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); + + /** + * skip array brackets, as the type cannot be located within; + * also skip a set of parens - there may be a type embedded within, + * but it's not the type with which we're concerned + */ + if ( next->IsSquareBracket() // Issue #3601 + || next->IsParenOpen()) + { + prev = next->GetClosingParen(E_Scope::PREPROC); + next = prev->GetNextNcNnl(E_Scope::PREPROC); + } + + if ( prev->Is(CT_WORD) + && next->IsPointerOrReference()) + { + pc = next; + + break; + } + } + } + } + + if ( pc != nullptr + && pc->IsNotNullChunk()) + { + /** + * the chunk preceding the previously selected chunk should indicate the type + */ + + pc = pc->GetPrevNcNnlNi(E_Scope::PREPROC); + + if ( pc->Is(CT_QUALIFIER) + && std::strncmp(pc->GetStr().c_str(), "final", 5) == 0) + { + pc = pc->GetPrevNcNnlNi(E_Scope::PREPROC); + } + + if ( language_is_set(LANG_D) + && pc->IsParenClose()) + { + pc = pc->GetOpeningParen(); + pc = pc->GetPrevNcNnlNi(); + } + + if (pc->Is(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 diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/EnumStructUnionParser.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/EnumStructUnionParser.h new file mode 100644 index 00000000..15536e67 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/EnumStructUnionParser.h @@ -0,0 +1,497 @@ +/** + * @file combine_fix_mark_enum_struct_union.h + * + * @author Joshua Parker + * @license GPL v2+ + * extract from combine_fix_mark.h + */ + +#ifndef ENUM_STRUCT_UNION_PARSER_H_INCLUDED +#define ENUM_STRUCT_UNION_PARSER_H_INCLUDED + +#include "pcf_flags.h" +#include "token_enum.h" +#include "uncrustify_types.h" +#include <map> + + +/** + * Class EnumStructUnionParser : This class facilitates the parsing and interpretation + * of ALL instances of the class, enum, union, and + * struct keywords, including user-defined types with + * a body {} and any trailing inline variable declarations + * that may follow the definition (as permitted by + * the coding language in question). The class also + * interprets variable declarations preceded by one + * of those keywords, as well as any C/C++ forward + * declarations + */ +class EnumStructUnionParser +{ +public: + /** + * Constructor + */ + EnumStructUnionParser(); + + + /** + * Destructor + */ + ~EnumStructUnionParser(); + + +private: + /** + * Analyzes all identifiers (marked as CT_WORD) between the starting and + * ending chunks and changes CT_WORD to one of CT_TYPE, CT_MACRO_FUNC_CALL, + * etc. and sets flags (PCF_VAR_1ST, PCF_VAR_1ST_DEF, PCF_VAR_INLINE, etc.) + * for variable identifiers accordingly. Flags C++ forward declarations as + * PCF_INCOMPLETE + */ + void analyze_identifiers(); + + + /** + * Returns true if a pair of braces were both detected AND determined to be + * part of a class/enum/struct/union body + */ + bool body_detected() const; + + + /** + * Returns true if comma-separated values were detected during parsing + */ + bool comma_separated_values_detected() const; + + + /** + * Returns true if an enumerated integral type was detected during parsing + */ + bool enum_base_detected() const; + + + /** + * Returns the end chunk of a class/enum/struct/union body, if detected + * during parsing + */ + Chunk *get_body_end() const; + + + /** + * Returns the starting chunk of a class/enum/struct/union body, if detected + * during parsing + */ + Chunk *get_body_start() const; + + + /** + * Returns the starting chunk associated with an enumerated type's base + * specifier statement, if detected during parsing + */ + Chunk *get_enum_base_start() const; + + + /** + * Returns the first comma encountered at the level of the starting chunk, + * if detected during parsing + */ + Chunk *get_first_top_level_comma() const; + + + /** + * Returns the ending chunk associated with an class/struct inheritance + * list, if detected during parsing + */ + Chunk *get_inheritance_end() const; + + + /** + * Returns the starting chunk associated with an class/struct inheritance + * list, if detected during parsing + */ + Chunk *get_inheritance_start() const; + + + /** + * Returns a numerically-indexed map of all question operators encountered + * during parsing + */ + std::map<std::size_t, Chunk *> get_question_operators() const; + + + /** + * Returns the end chunk associated with a template parameter list, if + * detected during parsing + */ + Chunk *get_template_end() const; + + + /** + * Return the starting chunk associated with a template parameter list, if + * detected during parsing + */ + Chunk *get_template_start() const; + + + /** + * Returns a numerically-indexed map of all top-level commas encountered + * during parsing + */ + std::map<std::size_t, Chunk *> get_top_level_commas() const; + + + /** + * Return the starting chunk associated with a where clause, if + * detected during parsing + */ + Chunk *get_where_end() const; + + + /** + * Return the starting chunk associated with a where clause, if + * detected during parsing + */ + Chunk *get_where_start() const; + + + /** + * Returns true if an inheritance list associated with a class or struct was + * discovered during parsing + */ + bool inheritance_detected() const; + + +public: + /** + * Performs object initialization prior to parsing + */ + void initialize(Chunk *pc); + + +private: + /** + * Returns true if the chunk under test represents a potential end chunk past + * which further parsing is not likely warranted + */ + bool is_potential_end_chunk(Chunk *pc) const; + + + /** + * Returns true if the chunk under test is deemed to be located within a + * conditional/ternary statement + */ + bool is_within_conditional(Chunk *pc) const; + + + /** + * Returns true if the chunk under test is deemed to be located within an + * inheritance list + */ + bool is_within_inheritance_list(Chunk *pc) const; + + + /** + * Returns true if the chunk under test is deemed to be located within a + * where clause + */ + bool is_within_where_clause(Chunk *pc) const; + + + /** + * Marks all base classes that appear as part of an inheritance list + */ + void mark_base_classes(Chunk *pc); + + + /** + * Marks pairs of braces associated with the body of a class/enum/struct/union, + * and additionally calls a separate routine to mark any base classes for that + * may precede the opening brace + */ + void mark_braces(Chunk *start); + + + /** + * Marks the beginning chunk of an inheritance list + */ + void mark_class_colon(Chunk *colon); + + + /** + * Mark a colon as a conditional + */ + void mark_conditional_colon(Chunk *colon); + + + /** + * Mark any struct/class constructor declarations/definitions + */ + void mark_constructors(); + + + /** + * Marks the beginning chunk of an enumerated integral type specification + */ + void mark_enum_integral_type(Chunk *colon); + + + /** + * Scan chunks outside the definition body and mark lvalues accordingly + */ + void mark_extracorporeal_lvalues(); + + + /** + * Mark nested name specifiers preceding qualified identifiers + */ + void mark_nested_name_specifiers(Chunk *pc); + + + /** + * Marks pointer operators preceding a variable identifier + */ + void mark_pointer_types(Chunk *pc); + + + /** + * Marks the beginning and ending chunks associated with a template + * (templates may appear after the identifier type name as part of a class + * specialization) + */ + void mark_template(Chunk *start) const; + + + /** + * Marks the arguments within a template argument list bounded by the + * starting and ending chunks + */ + void mark_template_args(Chunk *start, Chunk *end) const; + + + /** + * Marks the type identifier associated with the class/enum/struct/union, + * if not anonymously defined + */ + void mark_type(Chunk *pc); + + + /** + * Marks all variable identifiers associated with the class/enum/struct/union + */ + void mark_variable(Chunk *variable, T_PcfFlags flags); + + + /** + * Marks all chunks belonging to a c# where clause + */ + void mark_where_clause(Chunk *where); + + + /** + * Marks the beginning of a where clause + */ + void mark_where_colon(Chunk *colon); + + +public: + /** + * Parses the class/enum/struct/union and all associated chunks + */ + void parse(Chunk *pc); + + +private: + /** + * Parses closing and opening angle brackets + */ + Chunk *parse_angles(Chunk *angle_open); + + + /** + * Parses closing and opening braces + */ + Chunk *parse_braces(Chunk *brace_open); + + + /** + * Parses a single colon, which may precede an inheritance list or + * enumerated integral type specification + */ + void parse_colon(Chunk *colon); + + + /** + * Parses a double colon, which may indicate a scope resolution chain + */ + Chunk *parse_double_colon(Chunk *double_colon); + + + /** + * Returns the parsing error status + */ + bool parse_error_detected() const; + + + /** + * Sets the parsing error status + */ + void parse_error_detected(bool status); + + + /** + * Records all question operators encountered during parsing + */ + void record_question_operator(Chunk *question); + + + /** + * Records a comma chunk given one the following conditions are satisfied: + * 1) it is encountered at the level of the starting chunk + * 2) it is not part of a right-hand side assignment + * 3) it is not part of an inheritance list + * 4) it is not part of a conditional/ternary expression + */ + void record_top_level_comma(Chunk *comma); + + + /** + * Adjusts the end chunk returned by the try_find_end_chunk() function + * for any potential trailing inline variable declarations that may follow + * the body of a class/enum/struct/union definition + */ + Chunk *refine_end_chunk(Chunk *pc); + + + /** + * Sets the chunk associated with the end of a class/enum/struct/union + * body + */ + void set_body_end(Chunk *body_end); + + + /** + * Sets the chunk associated with the start of a class/enum/struct/union + * body + */ + void set_body_start(Chunk *body_start); + + + /** + * Sets the chunk associated with the start of an enumerated integral + * base type specification + */ + void set_enum_base_start(Chunk *enum_base_start); + + + /** + * Sets the chunk associated with the start of an inheritance list + */ + void set_inheritance_start(Chunk *inheritance_start); + + + /** + * Sets the chunk associated with the end of a template + */ + void set_template_end(Chunk *template_end); + + + /** + * Sets the chunk associated with the start of a template + */ + void set_template_start(Chunk *template_start); + + + /** + * Return the ending chunk associated with a where clause, if + * detected during parsing + */ + void set_where_end(Chunk *where_end); + + + /** + * Return the starting chunk associated with a where clause, if + * detected during parsing + */ + void set_where_start(Chunk *where_start); + + + /** + * Returns true if a template was detected during parsing + */ + bool template_detected() const; + + + /** + * Attempts to find the last chunk associated with the class/enum/struct/union + */ + Chunk *try_find_end_chunk(Chunk *pc); + + + /** + * Attempts to identify any function-like macro calls which may precede the + * actual type identifier + */ + void try_post_identify_macro_calls(); + + + /** + * Attempts to find the identifier type name (if not anonymously-defined) post + * variable identifier interpretation + */ + void try_post_identify_type(); + + + /** + * Attempts to find the identifier type name prior to variable identifier + * interpretation + */ + bool try_pre_identify_type(); + + + /** + * Returns true if a corresponding type was identified for the class/enum/struct/union + */ + bool type_identified() const; + + + /** + * Returns true if a where clause was detected during parsing + */ + bool where_clause_detected() const; + + + /** + * Map of token-type, chunk pairs + */ + std::map<E_Token, std::map<std::size_t, Chunk *> > m_chunk_map; + + + /** + * Indicates the last chunk associated with the class/enum/struct/union keyword + */ + Chunk *m_end; + + + /** + * Indicates whether or not a parse error has occurred + */ + bool m_parse_error; + + + /** + * Stores a pointer to the class/enum/struct/union keyword chunk with which the + * parse() routine was invoked + */ + Chunk *m_start; + + + /** + * Stores a pointer to the type identifier associated with the class/enum/struct/union, + * if not anonymously defined + */ + Chunk *m_type; +}; + + +#endif diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/ListManager.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/ListManager.h new file mode 100644 index 00000000..64bc5fd8 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/ListManager.h @@ -0,0 +1,216 @@ +/** + * @file ListManager.h + * Template class that manages items in a double-linked list. + * If C++ could do it, this would just be a class that worked on an interface. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef LIST_MANAGER_H_INCLUDED +#define LIST_MANAGER_H_INCLUDED + +#include "chunk.h" + +/** + * A simple list manager for a double-linked list of Chunk items. + */ +class ChunkListManager +{ +protected: + Chunk *m_head; // pointer to the head of list + Chunk *m_tail; // pointer to tail of list + +public: + ChunkListManager() + { + m_head = Chunk::NullChunkPtr; + m_tail = Chunk::NullChunkPtr; + } + + + /** + * @return pointer to first element of the linked list + */ + Chunk *GetHead() const + { + return(m_head); + } + + + /** + * @return pointer to last element of the linked list + */ + Chunk *GetTail() const + { + return(m_tail); + } + + + /** + * @brief remove an element from a linked list + * @param[in] obj chunk to remove from the list + */ + void Remove(Chunk *obj) + { + if (obj != Chunk::NullChunkPtr) + { + if (m_head == obj) + { + m_head = obj->m_next; + } + + if (m_tail == obj) + { + m_tail = obj->m_prev; + } + + if (obj->m_next != Chunk::NullChunkPtr) + { + obj->m_next->m_prev = obj->m_prev; + } + + if (obj->m_prev != Chunk::NullChunkPtr) + { + obj->m_prev->m_next = obj->m_next; + } + obj->m_next = Chunk::NullChunkPtr; + obj->m_prev = Chunk::NullChunkPtr; + } + } + + + //! swap two elements of a list + void Swap(Chunk *obj1, Chunk *obj2) + { + if ( obj1 != Chunk::NullChunkPtr + && obj2 != Chunk::NullChunkPtr) + { + if (obj1->m_prev == obj2) + { + Remove(obj1); + AddBefore(obj1, obj2); + } + else if (obj2->m_prev == obj1) + { + Remove(obj2); + AddBefore(obj2, obj1); + } + else + { + Chunk *m_prev1 = obj1->m_prev; + Remove(obj1); + + Chunk *m_prev2 = obj2->m_prev; + Remove(obj2); + + AddAfter(obj1, m_prev2); + AddAfter(obj2, m_prev1); + } + } + } + + + /** + * @brief add a new element after a reference position in a list + * + * @param obj new element to add to list + * @param ref chunk after which to insert new object + */ + void AddAfter(Chunk *obj, Chunk *ref) + { + if ( obj != Chunk::NullChunkPtr + && ref != Chunk::NullChunkPtr) + { + obj->m_next = ref->m_next; + obj->m_prev = ref; + + if (ref->m_next != Chunk::NullChunkPtr) + { + ref->m_next->m_prev = obj; + } + else + { + m_tail = obj; + } + ref->m_next = obj; + } + } + + + /** + * @brief add a new element before a reference position in a list + * + * @param obj new element to add to list + * @param ref chunk before to insert new object + */ + void AddBefore(Chunk *obj, Chunk *ref) + { + if ( obj != Chunk::NullChunkPtr + && ref != Chunk::NullChunkPtr) + { + Remove(obj); + obj->m_next = ref; + obj->m_prev = ref->m_prev; + + if (ref->m_prev != Chunk::NullChunkPtr) + { + ref->m_prev->m_next = obj; + } + else + { + m_head = obj; + } + ref->m_prev = obj; + } + } + + + /** + * @brief add a new element to the tail of a lis + * + * @param obj new element to add to the list + */ + void AddTail(Chunk *obj) + { + obj->m_next = Chunk::NullChunkPtr; + obj->m_prev = m_tail; + + if (m_tail == Chunk::NullChunkPtr) + { + m_tail = obj; + m_head = obj; + } + else + { + m_tail->m_next = obj; + } + m_tail = obj; + } + + + /** + * @brief add a new element to the head of a list + * + * @param obj new element to add to the list + */ + void AddHead(Chunk *obj) + { + obj->m_next = m_head; + obj->m_prev = Chunk::NullChunkPtr; + + if (m_head == Chunk::NullChunkPtr) + { + m_tail = obj; + m_head = obj; + } + else + { + m_head->m_prev = obj; + } + m_head = obj; + } +}; + + +#endif /* LIST_MANAGER_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/ParseFrame.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/ParseFrame.cpp new file mode 100644 index 00000000..837871cb --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/ParseFrame.cpp @@ -0,0 +1,352 @@ +/** + * @file ParseFrame.cpp + * + * Container that holds data needed for indenting and brace parsing + * + * @author Daniel Chumak + * @license GPL v2+ + */ + +#include "ParseFrame.h" + +#include "chunk.h" +#include "uncrustify.h" + +#include <stdexcept> // to get std::logic_error + + +using std::string; +using std::to_string; +using std::invalid_argument; + +using ContainerType = paren_stack_entry_t; +using Container = std::vector<ContainerType>; + + +//! amount of elements for which memory is going to be pre-initialized +static constexpr const int CONTAINER_INIT_SIZE = 16; + + +static ContainerType genDummy() +{ + ContainerType tmp_dummy{}; + + tmp_dummy.indent = 1; + tmp_dummy.indent_tmp = 1; + tmp_dummy.indent_tab = 1; + tmp_dummy.type = CT_EOF; + tmp_dummy.pc = Chunk::NullChunkPtr; + tmp_dummy.pop_pc = Chunk::NullChunkPtr; + + return(tmp_dummy); +} + + +void ParseFrame::clear() +{ + last_poped = genDummy(); + + pse = Container{}; + pse.reserve(CONTAINER_INIT_SIZE); + pse.push_back(genDummy()); + + ref_no = 0; + level = 0; + brace_level = 0; + pp_level = 0; + sparen_count = 0; + paren_count = 0; + in_ifdef = E_Token::CT_NONE; + stmt_count = 0; + expr_count = 0; +} + + +ParseFrame::ParseFrame() +{ + ParseFrame::clear(); +} + + +bool ParseFrame::empty() const +{ + // always at least one (dummy) element inside pse guaranteed + return(false); +// return(pse.empty()); +} + + +ContainerType &ParseFrame::at(size_t idx) +{ + return(pse.at(idx)); +} + + +const ContainerType &ParseFrame::at(size_t idx) const +{ + return(pse.at(idx)); +} + + +ContainerType &ParseFrame::prev(size_t idx) +{ + LOG_FUNC_ENTRY(); + + if (idx == 0) + { + throw invalid_argument(string(__FILE__) + ":" + to_string(__LINE__) + + " idx can't be zero"); + } + + if (idx >= pse.size()) + { + LOG_FMT(LINDPSE, "%s(%d): idx is %zu, size is %zu\n", + __func__, __LINE__, idx, pse.size()); + throw invalid_argument(string(__FILE__) + ":" + to_string(__LINE__) + + " idx can't be >= size()"); + } + return(*std::prev(std::end(pse), idx + 1)); +} + + +const ContainerType &ParseFrame::prev(size_t idx) const +{ + LOG_FUNC_ENTRY(); + + if ( idx == 0 + || idx >= pse.size()) + { + throw invalid_argument(string(__FILE__) + ":" + to_string(__LINE__) + + " idx can't be zero or >= size()"); + } + return(*std::prev(std::end(pse), idx + 1)); +} + + +ContainerType &ParseFrame::top() +{ + // always at least one (dummy) element inside pse guaranteed +// if (pse.empty()) +// { +// throw logic_error(string(__FILE__) + ":" + to_string(__LINE__) +// + " called top on an empty stack"); +// } + return(*std::prev(std::end(pse))); +} + + +const ContainerType &ParseFrame::top() const +{ + // always at least one (dummy) element inside pse guaranteed +// if (pse.empty()) +// { +// throw logic_error(string(__FILE__) + ":" + to_string(__LINE__) +// + " called top on an empty stack"); +// } + return(*std::prev(std::end(pse))); +} + + +void ParseFrame::push(std::nullptr_t, brace_stage_e stage) +{ + static Chunk dummy; + + push(&dummy, __func__, __LINE__, stage); + top().pc = Chunk::NullChunkPtr; +} + + +void ParseFrame::push(Chunk *pc, const char *func, int line, brace_stage_e stage) +{ + LOG_FUNC_ENTRY(); + + ContainerType new_entry = {}; + + new_entry.type = pc->GetType(); + new_entry.level = pc->GetLevel(); + new_entry.open_line = pc->GetOrigLine(); + new_entry.open_colu = pc->GetOrigCol(); + new_entry.pc = pc; + + new_entry.indent_tab = top().indent_tab; + new_entry.indent_cont = top().indent_cont; + new_entry.stage = stage; + + new_entry.in_preproc = pc->TestFlags(PCF_IN_PREPROC); + new_entry.non_vardef = false; + new_entry.ip = top().ip; + new_entry.pop_pc = Chunk::NullChunkPtr; + + pse.push_back(new_entry); + +// uncomment the line below to get the address of the pse +// #define DEBUG_PUSH_POP +#ifdef DEBUG_PUSH_POP + LOG_FMT(LINDPSE, "ParseFrame::push(%s:%d) Add is %4zu: orig line is %4zu, orig col is %4zu, type is %12s, " + "brace level is %2zu, level is %2zu, pse_tos: %2zu -> %2zu\n", + func, line, (size_t)this, pc->GetOrigLine(), pc->GetOrigCol(), + get_token_name(pc->GetType()), pc->GetBraceLevel(), pc->GetLevel(), + (pse.size() - 2), (pse.size() - 1)); +#else /* DEBUG_PUSH_POP */ + LOG_FMT(LINDPSE, "ParseFrame::push(%s:%d): orig line is %4zu, orig col is %4zu, type is %12s, " + "brace level is %2zu, level is %2zu, pse_tos: %2zu -> %2zu\n", + func, line, pc->GetOrigLine(), pc->GetOrigCol(), + get_token_name(pc->GetType()), pc->GetBraceLevel(), pc->GetLevel(), + (pse.size() - 2), (pse.size() - 1)); +#endif /* DEBUG_PUSH_POP */ +} + + +void ParseFrame::pop(const char *func, int line, Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + // always at least one (dummy) element inside pse guaranteed +// if (pse.empty()) +// { +// throw logic_error(string(__FILE__) + ":" + to_string(__LINE__) +// + "the stack index is already zero"); +// } + + if ( pc->GetType() == CT_PAREN_CLOSE + || pc->GetType() == CT_BRACE_CLOSE + || pc->GetType() == CT_VBRACE_CLOSE + || pc->GetType() == CT_FPAREN_CLOSE + || pc->GetType() == CT_LPAREN_CLOSE + || pc->GetType() == CT_SPAREN_CLOSE + || pc->GetType() == CT_TPAREN_CLOSE + || pc->GetType() == CT_CLASS_COLON + || pc->GetType() == CT_ANGLE_CLOSE + || pc->GetType() == CT_SEMICOLON + || pc->GetType() == CT_SQUARE_CLOSE) + { + LOG_FMT(LINDPSE, "ParseFrame::pop (%s:%d): orig line is %4zu, orig col is %4zu, type is %12s, pushed with\n", + func, line, pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + } + else if ( pc->GetType() == CT_ACCESS + || pc->GetType() == CT_ASSIGN + || pc->GetType() == CT_BRACE_OPEN + || pc->GetType() == CT_BOOL + || pc->GetType() == CT_CASE + || pc->GetType() == CT_COMMA + || pc->GetType() == CT_COMMENT + || pc->GetType() == CT_COMMENT_CPP + || pc->GetType() == CT_COMMENT_MULTI + || pc->GetType() == CT_COND_COLON + || pc->GetType() == CT_FPAREN_OPEN + || pc->GetType() == CT_PAREN_OPEN + || pc->GetType() == CT_TPAREN_OPEN + || pc->GetType() == CT_MACRO_CLOSE + || pc->GetType() == CT_MACRO_OPEN + || pc->GetType() == CT_NEWLINE + || pc->GetType() == CT_NONE + || pc->GetType() == CT_OC_END + || pc->GetType() == CT_OC_MSG_NAME + || pc->GetType() == CT_OC_SCOPE + || pc->GetType() == CT_OC_PROPERTY + || pc->GetType() == CT_PREPROC + || pc->GetType() == CT_SQUARE_OPEN + || pc->GetType() == CT_SQL_END + || pc->GetType() == CT_TYPEDEF + || pc->GetType() == CT_VSEMICOLON + || pc->GetType() == CT_WORD) + { + LOG_FMT(LINDPSE, "ParseFrame::pop (%s:%d): orig line is %4zu, orig col is %4zu, type is %12s\n", + func, line, pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + } + else + { + LOG_FMT(LINDPSE, "ParseFrame::pop (%s:%d): orig line is %4zu, orig col is %4zu, type is %12s,\n", + func, line, pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + LOG_FMT(LINDPSE, "ParseFrame::pop (%s:%d): the type is %s, is not coded. Please make a call.\n", + func, line, get_token_name(pc->GetType())); + log_flush(true); + exit(EX_SOFTWARE); + } +#ifdef DEBUG_PUSH_POP + LOG_FMT(LINDPSE, "ParseFrame::pop (%s:%d) Add is %4zu: open_line is %4zu, clos_col is %4zu, type is %12s, " + "cpd.level is %2d, level is %2zu, pse_tos: %2zu -> %2zu\n", + func, line, (size_t)this, pse.back().open_line, pse.back().open_colu, + get_token_name(pse.back().type), cpd.pp_level, pse.back().level, + (pse.size() - 1), (pse.size() - 2)); +#else /* DEBUG_PUSH_POP */ + LOG_FMT(LINDPSE, "ParseFrame::pop (%s:%d): open_line is %4zu, clos_col is %4zu, type is %12s, " + "cpd.level is %2d, level is %2zu, pse_tos: %2zu -> %2zu\n", + func, line, pse.back().open_line, pse.back().open_colu, + get_token_name(pse.back().type), cpd.pp_level, pse.back().level, + (pse.size() - 1), (pse.size() - 2)); +#endif /* DEBUG_PUSH_POP */ + + last_poped = *std::prev(std::end(pse)); + + if (pse.size() == 1) + { + *std::begin(pse) = genDummy(); + } + else + { + pse.pop_back(); + } +} // ParseFrame::pop + + +size_t ParseFrame::size() const +{ + // always at least one (dummy) element inside pse guaranteed + return(pse.size()); +} + + +const paren_stack_entry_t &ParseFrame::poped() const +{ + return(last_poped); +} + + +// TODO C++14: see abstract versions: std::rend, std::cend, std::crend ... +ParseFrame::iterator ParseFrame::begin() +{ + return(std::begin(pse)); +} + + +ParseFrame::const_iterator ParseFrame::begin() const +{ + return(std::begin(pse)); +} + + +ParseFrame::reverse_iterator ParseFrame::rbegin() +{ + return(pse.rbegin()); +} + + +ParseFrame::const_reverse_iterator ParseFrame::rbegin() const +{ + return(pse.rbegin()); +} + + +ParseFrame::iterator ParseFrame::end() +{ + return(std::end(pse)); +} + + +ParseFrame::const_iterator ParseFrame::end() const +{ + return(std::end(pse)); +} + + +ParseFrame::reverse_iterator ParseFrame::rend() +{ + return(pse.rend()); +} + + +ParseFrame::const_reverse_iterator ParseFrame::rend() const +{ + return(pse.rend()); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/ParseFrame.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/ParseFrame.h new file mode 100644 index 00000000..1ca0e2d5 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/ParseFrame.h @@ -0,0 +1,99 @@ +/** + * @file ParseFrame.h + * + * Container that holds data needed for indenting and brace parsing + * + * @author Daniel Chumak + * @license GPL v2+ + */ + +#ifndef SRC_PARSEFRAME_H_ +#define SRC_PARSEFRAME_H_ + +#include "uncrustify_types.h" + +#include <memory> + + +//! Structure for counting nested level +struct paren_stack_entry_t +{ + E_Token type; //! the type that opened the entry + size_t level; //! Level of opening type + size_t open_line; //! line that open symbol is on, only for logging purposes + size_t open_colu; //! column that open symbol is on, only for logging purposes + Chunk *pc; //! Chunk that opened the level, TODO: make const + size_t brace_indent; //! indent for braces - may not relate to indent + size_t indent; //! indent level (depends on use) + size_t indent_tmp; //! temporary indent level (depends on use) + size_t indent_tab; //! the 'tab' indent (always <= real column) + bool indent_cont; //! indent_continue was applied + E_Token parent; //! if, for, function, etc + brace_stage_e stage; //! used to check progression of complex statements. + bool in_preproc; //! whether this was created in a preprocessor + size_t ns_cnt; //! Number of consecutive namespace levels + bool non_vardef; //! Hit a non-vardef line + T_IndentData ip; + Chunk *pop_pc; +}; + +class ParseFrame +{ +private: + std::vector<paren_stack_entry_t> pse; + paren_stack_entry_t last_poped; + + void clear(); + +public: + size_t ref_no; + size_t level; //! level of parens/square/angle/brace + size_t brace_level; //! level of brace/vbrace + size_t pp_level; //! level of preproc #if stuff + size_t sparen_count; + size_t paren_count; + E_Token in_ifdef; + size_t stmt_count; + size_t expr_count; + + + ParseFrame(); + virtual ~ParseFrame() = default; + + bool empty() const; + + paren_stack_entry_t &at(size_t idx); + const paren_stack_entry_t &at(size_t idx) const; + + paren_stack_entry_t &prev(size_t idx = 1); + const paren_stack_entry_t &prev(size_t idx = 1) const; + + paren_stack_entry_t &top(); + const paren_stack_entry_t &top() const; + + const paren_stack_entry_t &poped() const; + + void push(Chunk *pc, const char *func, int line, brace_stage_e stage = brace_stage_e::NONE); + void push(std::nullptr_t, brace_stage_e stage = brace_stage_e::NONE); + void pop(const char *func, int line, Chunk *pc); + + size_t size() const; + + using iterator = std::vector<paren_stack_entry_t>::iterator; + iterator begin(); + iterator end(); + + using const_iterator = std::vector<paren_stack_entry_t>::const_iterator; + const_iterator begin() const; + const_iterator end() const; + + using reverse_iterator = std::vector<paren_stack_entry_t>::reverse_iterator; + reverse_iterator rbegin(); + reverse_iterator rend(); + + using const_reverse_iterator = std::vector<paren_stack_entry_t>::const_reverse_iterator; + const_reverse_iterator rbegin() const; + const_reverse_iterator rend() const; +}; + +#endif /* SRC_PARSEFRAME_H_ */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/add_space_table.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/add_space_table.h new file mode 100644 index 00000000..d9c89388 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/add_space_table.h @@ -0,0 +1,366 @@ +// *INDENT-OFF* + +#include "token_enum.h" + +//! type that stores two chunks between those no space shall occur +struct no_space_table_t +{ + E_Token first; //! first chunk + E_Token second; //! second chunk +}; + +/** + * this table lists out all combos where a space MUST be present + * CT_UNKNOWN is a wildcard. + * + * TODO: some of these are no longer needed. + */ +const no_space_table_t add_space_table[] = +{ + { CT_ACCESS, CT_TYPE }, + { CT_ACCESS, CT_WORD }, + { CT_ALIGN, CT_PAREN_OPEN }, + { CT_AMP, CT_WORD }, + { CT_ANGLE_CLOSE, CT_BRACE_OPEN }, + { CT_ANNOTATION, CT_ANNOTATION }, + { CT_ANNOTATION, CT_TYPE }, + { CT_ASM_COLON, CT_ASM_COLON }, + { CT_ASM_COLON, CT_STRING }, + { CT_ASM, CT_FUNC_CALL }, + { CT_ASM, CT_PAREN_OPEN }, + { CT_ASM, CT_QUALIFIER }, + { CT_ASSERT, CT_PAREN_OPEN }, + { CT_ASSIGN_FUNC_PROTO, CT_DEFAULT }, + { CT_ASSIGN_FUNC_PROTO, CT_DELETE }, + { CT_ASSIGN_FUNC_PROTO, CT_NUMBER }, + { CT_ATTRIBUTE, CT_ATTRIBUTE }, + { CT_ATTRIBUTE, CT_BRACE_OPEN }, + { CT_ATTRIBUTE, CT_CASE }, + { CT_ATTRIBUTE, CT_QUALIFIER }, + { CT_ATTRIBUTE, CT_TYPE }, + { CT_ATTRIBUTE, CT_WORD }, + { CT_AUTORELEASEPOOL, CT_BRACE_OPEN }, + { CT_BIT_COLON, CT_NUMBER }, + { CT_BIT_COLON, CT_SIZEOF }, + { CT_BIT_COLON, CT_TYPE }, + { CT_BIT_COLON, CT_WORD }, + { CT_BODY, CT_BRACE_OPEN }, + { CT_BRACE_CLOSE, CT_BRACE_OPEN }, + { CT_BRACE_CLOSE, CT_CLASS }, + { CT_BRACE_CLOSE, CT_FUNC_CALL }, + { CT_BRACE_CLOSE, CT_GETSET }, + { CT_BRACE_CLOSE, CT_IF }, + { CT_BRACE_CLOSE, CT_OC_MSG_NAME }, + { CT_BRACE_CLOSE, CT_PAREN_OPEN }, + { CT_BRACE_CLOSE, CT_QUALIFIER }, + { CT_BRACE_CLOSE, CT_RETURN }, + { CT_BRACE_CLOSE, CT_TYPE }, + { CT_BRACE_CLOSE, CT_WORD }, + { CT_BREAK, CT_WORD }, + { CT_BYREF, CT_INV }, + { CT_CASE_COLON, CT_ATTRIBUTE }, + { CT_CASE_COLON, CT_BRACE_OPEN }, + { CT_CASE_COLON, CT_BREAK }, + { CT_CASE_COLON, CT_RETURN }, + { CT_CASE_COLON, CT_WORD }, + { CT_CASE, CT_NEG }, + { CT_CASE, CT_PAREN_OPEN }, + { CT_CASE, CT_STRING }, + { CT_CATCH, CT_FUNC_CALL }, + { CT_CLASS_COLON, CT_FUNC_CALL }, + { CT_CLASS_COLON, CT_QUALIFIER }, + { CT_CLASS_COLON, CT_TYPE }, + { CT_CLASS_COLON, CT_WORD }, + { CT_COLON, CT_COLON }, + { CT_COLON, CT_NUMBER }, + { CT_COLON, CT_QUALIFIER }, + { CT_COLON, CT_STRING }, + { CT_COLON, CT_TYPE }, + { CT_COLON, CT_WORD }, + { CT_COMMENT_EMBED, CT_FUNC_CLASS_PROTO }, + { CT_COMMENT_MULTI, CT_ELSE }, + { CT_CONCAT, CT_STRING }, + { CT_CONCAT, CT_WORD }, + { CT_COND_COLON, CT_FUNC_CALL }, + { CT_COND_COLON, CT_STRING }, + { CT_COND_COLON, CT_WORD }, + { CT_CONSTRUCT, CT_TYPE }, + { CT_CONTINUE, CT_WORD }, + { CT_CS_PROPERTY, CT_BRACE_OPEN }, + { CT_DEFAULT, CT_STRING }, + { CT_DEFAULT, CT_WORD }, + { CT_DELEGATE, CT_BRACE_OPEN }, + { CT_D_MODULE, CT_WORD }, + { CT_ELLIPSIS, CT_NUMBER }, + { CT_ELSE, CT_FOR }, + { CT_ELSE, CT_IF }, + { CT_ELSE, CT_PAREN_OPEN }, + { CT_ELSE, CT_WORD }, + { CT_ELSEIF, CT_CONSTEXPR }, + { CT_ENUM_CLASS, CT_ATTRIBUTE }, + { CT_ENUM_CLASS, CT_TYPE }, + { CT_ENUM, CT_ATTRIBUTE }, + { CT_ENUM, CT_BIT_COLON }, + { CT_ENUM, CT_BRACE_OPEN }, + { CT_ENUM, CT_ENUM_CLASS }, + { CT_ENUM, CT_FPAREN_OPEN }, + { CT_ENUM, CT_FUNCTION }, + { CT_ENUM, CT_TYPE }, + { CT_ENUM, CT_WORD }, + { CT_EXECUTION_CONTEXT, CT_EXECUTION_CONTEXT }, + { CT_EXECUTION_CONTEXT, CT_FPAREN_OPEN }, + { CT_EXTERN, CT_STRING }, + { CT_FPAREN_CLOSE, CT_ASSIGN_FUNC_PROTO }, + { CT_FPAREN_CLOSE, CT_ATTRIBUTE }, + { CT_FPAREN_CLOSE, CT_CLASS_COLON }, + { CT_FPAREN_CLOSE, CT_COND_COLON }, + { CT_FPAREN_CLOSE, CT_DEFAULT }, + { CT_FPAREN_CLOSE, CT_FUNC_CALL }, + { CT_FPAREN_CLOSE, CT_NEG }, + { CT_FPAREN_CLOSE, CT_NOT }, + { CT_FPAREN_CLOSE, CT_OC_MSG_NAME }, + { CT_FPAREN_CLOSE, CT_QUESTION }, + { CT_FPAREN_CLOSE, CT_STRING }, + { CT_FPAREN_CLOSE, CT_THROW }, + { CT_FPAREN_CLOSE, CT_TYPE }, + { CT_FPAREN_CLOSE, CT_WHERE_SPEC }, + { CT_FPAREN_CLOSE, CT_WORD }, + { CT_FRIEND, CT_CLASS }, + { CT_FRIEND, CT_STRUCT }, + { CT_FRIEND, CT_TYPE }, + { CT_FUNCTION, CT_PAREN_OPEN }, + { CT_FUNC_VAR, CT_PPAREN_CLOSE }, + { CT_GOTO, CT_WORD }, + { CT_IF, CT_CONSTEXPR }, + { CT_IGNORED, CT_IGNORED }, + { CT_IMPORT, CT_WORD }, + { CT_INCDEC_AFTER, CT_DEREF }, + { CT_IN, CT_TYPE }, + { CT_IN, CT_WORD }, + { CT_LABEL_COLON, CT_CS_PROPERTY }, + { CT_LABEL_COLON, CT_FUNC_CALL }, + { CT_LABEL_COLON, CT_NEW }, + { CT_LABEL_COLON, CT_PAREN_OPEN }, + { CT_LABEL_COLON, CT_RETURN }, + { CT_LABEL_COLON, CT_STRING }, + { CT_LABEL_COLON, CT_TYPE }, + { CT_LABEL_COLON, CT_WORD }, + { CT_LOCK, CT_PAREN_OPEN }, + { CT_NAMESPACE, CT_BRACE_OPEN }, + { CT_NAMESPACE, CT_TYPE }, + { CT_NAMESPACE, CT_WORD }, + { CT_NATIVE, CT_TAG }, + { CT_NUMBER, CT_CHAR }, + { CT_NUMBER, CT_COLON }, + { CT_NUMBER, CT_ELLIPSIS }, + { CT_NUMBER, CT_OC_MSG_NAME }, + { CT_NUMBER, CT_PAREN_OPEN }, + { CT_NUMBER, CT_WORD }, + { CT_NUMBER_FP, CT_NUMBER }, + { CT_NUMBER_FP, CT_OC_MSG_NAME }, + { CT_NUMBER_FP, CT_WORD }, + { CT_OC_CLASS, CT_CLASS_COLON }, + { CT_OC_CLASS, CT_PAREN_OPEN }, + { CT_OC_DYNAMIC, CT_WORD }, + { CT_OC_IMPL, CT_OC_CLASS }, + { CT_OC_INTF, CT_OC_CLASS }, + { CT_OC_MSG_DECL, CT_BRACE_OPEN }, + { CT_OC_PROTOCOL, CT_OC_CLASS }, + { CT_PACKAGE, CT_WORD }, + { CT_PAREN_CLOSE, CT_ASM_COLON }, + { CT_PAREN_CLOSE, CT_COLON }, + { CT_PAREN_CLOSE, CT_COND_COLON }, + { CT_PAREN_CLOSE, CT_CS_PROPERTY }, + { CT_PAREN_CLOSE, CT_DEREF }, + { CT_PAREN_CLOSE, CT_NOT }, + { CT_PAREN_CLOSE, CT_NUMBER }, + { CT_PAREN_CLOSE, CT_OC_MSG_NAME }, + { CT_PAREN_CLOSE, CT_POS }, + { CT_PAREN_CLOSE, CT_QUALIFIER }, + { CT_PAREN_CLOSE, CT_TYPE }, + { CT_PP_DEFINE, CT_MACRO }, + { CT_PP_DEFINE, CT_MACRO_FUNC }, + { CT_PP_DEFINE, CT_NUMBER }, + { CT_PP_DEFINE, CT_PP_IGNORE }, + { CT_PP_DEFINED, CT_TYPE }, + { CT_PP_DEFINED, CT_WORD }, + { CT_PP_ELSE, CT_FUNC_CALL }, + { CT_PP_ELSE, CT_NOT }, + { CT_PP_ELSE, CT_NUMBER }, + { CT_PP_ELSE, CT_PAREN_OPEN }, + { CT_PP_ELSE, CT_PP_DEFINED }, + { CT_PP_ELSE, CT_WORD }, + { CT_PP_EMIT, CT_MACRO }, + { CT_PP_ENDIF, CT_WORD }, + { CT_PP_ENDREGION, CT_PREPROC_BODY }, + { CT_PP_IF, CT_CNG_HASINC }, + { CT_PP_IF, CT_FUNC_CALL }, + { CT_PP_IF, CT_NOT }, + { CT_PP_IF, CT_NUMBER }, + { CT_PP_IF, CT_PAREN_OPEN }, + { CT_PP_IF, CT_PP_ASM }, + { CT_PP_IF, CT_PP_DEFINE }, + { CT_PP_IF, CT_PP_DEFINED }, + { CT_PP_IF, CT_TYPE }, + { CT_PP_IF, CT_WORD }, + { CT_PP_INCLUDE, CT_STRING }, + { CT_PP_INCLUDE, CT_WORD }, + { CT_PP_OTHER, CT_PREPROC_BODY }, + { CT_PP_PRAGMA, CT_PP_ENDASM }, + { CT_PP_PRAGMA, CT_PP_ENDREGION }, + { CT_PP_PRAGMA, CT_PP_REGION }, + { CT_PP_PROPERTY, CT_WORD }, + { CT_PP_REGION, CT_IGNORED }, + { CT_PP_REGION, CT_PREPROC_BODY }, + { CT_PP_UNDEF, CT_TYPE }, + { CT_PP_UNDEF, CT_WORD }, + { CT_Q_EMIT, CT_FUNC_CALL }, + { CT_Q_FOREVER, CT_BRACE_OPEN }, + { CT_QUESTION, CT_FUNC_CALL }, + { CT_QUESTION, CT_PAREN_OPEN }, + { CT_QUESTION, CT_STRING }, + { CT_QUESTION, CT_WORD }, + { CT_SBOOL, CT_TYPE }, + { CT_SCOMPARE, CT_WORD }, + { CT_SPAREN_CLOSE, CT_ATTRIBUTE }, + { CT_SPAREN_CLOSE, CT_AUTORELEASEPOOL }, + { CT_SPAREN_CLOSE, CT_BRACE_OPEN }, + { CT_SPAREN_CLOSE, CT_FUNC_CALL }, + { CT_SPAREN_CLOSE, CT_WORD }, + { CT_SQL_ASSIGN, CT_FUNC_CALL }, + { CT_SQL_ASSIGN, CT_WORD }, + { CT_SQL_BEGIN, CT_SQL_WORD }, + { CT_SQL_END, CT_SQL_WORD }, + { CT_SQL_EXEC, CT_SQL_WORD }, + { CT_SQL_WORD, CT_COLON }, + { CT_SQL_WORD, CT_PAREN_OPEN }, + { CT_SQL_WORD, CT_SQL_WORD }, + { CT_SQUARE_CLOSE, CT_ATTRIBUTE }, + { CT_SQUARE_CLOSE, CT_BRACE_OPEN }, + { CT_SQUARE_CLOSE, CT_COLON }, + { CT_SQUARE_CLOSE, CT_EXECUTION_CONTEXT }, + { CT_SQUARE_CLOSE, CT_OC_MSG_NAME }, + { CT_SQUARE_CLOSE, CT_STRING }, + { CT_SQUARE_CLOSE, CT_WORD }, + { CT_STATE, CT_TYPE }, + { CT_STOCK, CT_QUALIFIER }, + { CT_STOCK, CT_TAG }, + { CT_STRING, CT_ATTRIBUTE }, + { CT_STRING, CT_BRACE_OPEN }, + { CT_STRING, CT_COLON }, + { CT_STRING, CT_CONCAT }, + { CT_STRING, CT_OC_MSG_NAME }, + { CT_STRING, CT_PAREN_OPEN }, + { CT_STRING, CT_STRING }, + { CT_STRING, CT_STRUCT }, + { CT_STRING, CT_TYPE }, + { CT_STRING, CT_WORD }, + { CT_STRUCT, CT_BRACE_OPEN }, + { CT_STRUCT, CT_CLASS_COLON }, + { CT_STRUCT, CT_MACRO_FUNC_CALL }, + { CT_STRUCT, CT_TYPE }, + { CT_STRUCT, CT_WORD }, + { CT_TEMPLATE, CT_CLASS }, + { CT_TEMPLATE, CT_TYPE }, + { CT_THIS, CT_OC_MSG_NAME }, + { CT_THIS, CT_TYPE }, + { CT_TSQUARE, CT_BRACE_OPEN }, + { CT_TSQUARE, CT_PAREN_OPEN }, + { CT_TSQUARE, CT_WORD }, + { CT_TYPEDEF, CT_ENUM }, + { CT_TYPEDEF, CT_FUNC_TYPE }, + { CT_TYPEDEF, CT_PAREN_OPEN }, + { CT_TYPEDEF, CT_QUALIFIER }, + { CT_TYPEDEF, CT_STRUCT }, + { CT_TYPEDEF, CT_TYPE }, + { CT_TYPEDEF, CT_TYPENAME }, + { CT_TYPEDEF, CT_UNION }, + { CT_TYPENAME, CT_ELLIPSIS }, + { CT_TYPENAME, CT_WORD }, + { CT_UNION, CT_BRACE_OPEN }, + { CT_UNION, CT_TYPE }, + { CT_UNION, CT_WORD }, + { CT_USING, CT_NAMESPACE }, + { CT_USING, CT_TYPE }, + { CT_USING, CT_WORD }, + { CT_USING_STMT, CT_PAREN_OPEN }, + { CT_VOLATILE, CT_BRACE_OPEN }, + { CT_WHERE_COLON, CT_CS_PROPERTY }, + { CT_WHERE_COLON, CT_NEW }, + { CT_WHERE_COLON, CT_TYPE }, + { CT_WHERE_COLON, CT_WORD }, + { CT_WHERE_SPEC, CT_WORD }, + { CT_WORD, CT_ATTRIBUTE }, + { CT_WORD, CT_BIT_COLON }, + { CT_WORD, CT_BRACE_OPEN }, + { CT_WORD, CT_CLASS_COLON }, + { CT_WORD, CT_COLON }, + { CT_WORD, CT_COMMENT_CPP }, + { CT_WORD, CT_CONCAT }, + { CT_WORD, CT_ELLIPSIS }, + { CT_WORD, CT_IN }, + { CT_WORD, CT_NEW }, + { CT_WORD, CT_NOT }, + { CT_WORD, CT_NUMBER }, + { CT_WORD, CT_NUMBER_FP }, + { CT_WORD, CT_OPERATOR }, + { CT_WORD, CT_QUALIFIER }, + { CT_WORD, CT_QUESTION }, + { CT_WORD, CT_SCOMPARE }, + { CT_WORD, CT_SQL_ASSIGN }, + { CT_WORD, CT_STRING }, + { CT_WORD, CT_STRUCT }, + { CT_WORD, CT_TYPE }, + { CT_WORD, CT_TYPE_CAST }, + { CT_WORD, CT_TYPEDEF }, + { CT_WORD, CT_WHERE_COLON }, + { CT_WORD, CT_WHERE_SPEC }, + { CT_WORD, CT_WORD }, +}; + +/** + * this table lists out all combos where a space should NOT be present + * CT_UNKNOWN is a wildcard. + * + * TODO: some of these are no longer needed. + */ +const no_space_table_t no_space_table[] = +{ + { CT_OC_AT, CT_UNKNOWN }, + { CT_INCDEC_BEFORE, CT_WORD }, + { CT_UNKNOWN, CT_INCDEC_AFTER }, + { CT_UNKNOWN, CT_LABEL_COLON }, + { CT_UNKNOWN, CT_ACCESS_COLON }, + { CT_UNKNOWN, CT_SEMICOLON }, + { CT_UNKNOWN, CT_D_TEMPLATE }, + { CT_D_TEMPLATE, CT_UNKNOWN }, + { CT_MACRO_FUNC, CT_FPAREN_OPEN }, + { CT_PAREN_OPEN, CT_UNKNOWN }, + { CT_UNKNOWN, CT_PAREN_CLOSE }, + { CT_FPAREN_OPEN, CT_UNKNOWN }, + { CT_UNKNOWN, CT_SPAREN_CLOSE }, + { CT_SPAREN_OPEN, CT_UNKNOWN }, + { CT_UNKNOWN, CT_FPAREN_CLOSE }, + { CT_UNKNOWN, CT_COMMA }, + { CT_POS, CT_UNKNOWN }, + { CT_STAR, CT_UNKNOWN }, + { CT_VBRACE_CLOSE, CT_UNKNOWN }, + { CT_VBRACE_OPEN, CT_UNKNOWN }, + { CT_UNKNOWN, CT_VBRACE_CLOSE }, + { CT_UNKNOWN, CT_VBRACE_OPEN }, + { CT_PREPROC, CT_UNKNOWN }, + { CT_PREPROC_INDENT, CT_UNKNOWN }, + { CT_NEG, CT_UNKNOWN }, + { CT_UNKNOWN, CT_SQUARE_OPEN }, + { CT_UNKNOWN, CT_SQUARE_CLOSE }, + { CT_SQUARE_OPEN, CT_UNKNOWN }, + { CT_PAREN_CLOSE, CT_WORD }, + { CT_PAREN_CLOSE, CT_FUNC_DEF }, + { CT_PAREN_CLOSE, CT_FUNC_CALL }, + { CT_PAREN_CLOSE, CT_ADDR }, + { CT_PAREN_CLOSE, CT_FPAREN_OPEN }, + { CT_OC_SEL_NAME, CT_OC_SEL_NAME }, + { CT_TYPENAME, CT_TYPE }, +}; + +// *INDENT-ON* diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align.cpp new file mode 100644 index 00000000..66e5af3f --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align.cpp @@ -0,0 +1,231 @@ +/** + * @file align.cpp + * Does all the aligning stuff. + * + * @author Ben Gardner + * @author Guy Maurel since version 0.62 for uncrustify4Qt + * October 2015, 2016 + * @license GPL v2+ + */ + +#include "align.h" + +#include "align_asm_colon.h" +#include "align_assign.h" +#include "align_braced_init_list.h" +#include "align_eigen_comma_init.h" +#include "align_func_params.h" +#include "align_func_proto.h" +#include "align_init_brace.h" +#include "align_left_shift.h" +#include "align_oc_decl_colon.h" +#include "align_oc_msg_colons.h" +#include "align_oc_msg_spec.h" +#include "align_preprocessor.h" +#include "align_same_func_call_params.h" +#include "align_stack.h" +#include "align_struct_initializers.h" +#include "align_trailing_comments.h" +#include "align_typedefs.h" +#include "align_var_def_brace.h" +#include "log_rules.h" +#include "quick_align_again.h" + +constexpr static auto LCURRENT = LALIGN; + +using namespace uncrustify; + + +/* + * Here are the items aligned: + * + * - enum value assignments + * enum { + * cat = 1, + * fred = 2, + * }; + * + * - struct/union variable & bit definitions + * struct foo { + * char cat; + * int id : 5; + * int name_len : 6; + * int height : 12; + * }; + * + * - variable definitions & assignments in normal code + * const char *cat = "feline"; + * int id = 4; + * a = 5; + * bat = 14; + * + * - simple array initializers + * int a[] = { + * 1, 2, 3, 4, 5, + * 6, 7, 8, 9, 10 + * }; + * + * - c99 array initializers + * const char *name[] = { + * [FRED] = "fred", + * [JOE] = "joe", + * [PETER] = "peter", + * }; + * struct foo b[] = { + * { .id = 1, .name = "text 1" }, + * { .id = 567, .name = "text 2" }, + * }; + * struct foo_t bars[] = + * { + * [0] = { .name = "bar", + * .age = 21 }, + * [1] = { .name = "barley", + * .age = 55 }, + * }; + * + * - compact array initializers + * struct foo b[] = { + * { 3, "dog" }, { 6, "spider" }, + * { 8, "elephant" }, { 3, "cat" }, + * }; + * + * - multiline array initializers (2nd line indented, not aligned) + * struct foo b[] = { + * { AD_NOT_ALLOWED, "Sorry, you failed to guess the password.", + * "Try again?", "Yes", "No" }, + * { AD_SW_ERROR, "A software error has occurred.", "Bye!", NULL, NULL }, + * }; + * + * - Trailing comments + * + * - Back-slash newline groups + * + * - Function prototypes + * int foo(); + * void bar(); + * + * - Preprocessors + * #define FOO_VAL 15 + * #define MAX_TIMEOUT 60 + * #define FOO(x) ((x) * 65) + * + * - typedefs + * typedef uint8_t BYTE; + * typedef int32_t INT32; + * typedef uint32_t UINT32; + */ +void align_all() +{ + LOG_FUNC_ENTRY(); + + log_rule_B("align_typedef_span"); + + if (options::align_typedef_span() > 0) + { + align_typedefs(options::align_typedef_span()); + } + log_rule_B("align_left_shift"); + + if (options::align_left_shift()) + { + align_left_shift(); + } + log_rule_B("align_eigen_comma_init"); + + if (options::align_eigen_comma_init()) + { + align_eigen_comma_init(); + } + log_rule_B("align_oc_msg_colon_span"); + + if (options::align_oc_msg_colon_span() > 0) + { + align_oc_msg_colons(); + } + // Align variable definitions + log_rule_B("align_var_def_span"); + log_rule_B("align_var_struct_span"); + log_rule_B("align_var_class_span"); + + if ( (options::align_var_def_span() > 0) + || (options::align_var_struct_span() > 0) + || (options::align_var_class_span() > 0)) + { + align_var_def_brace(Chunk::GetHead(), options::align_var_def_span(), nullptr); + } + // Align assignments + log_rule_B("align_enum_equ_span"); + log_rule_B("align_assign_span"); + log_rule_B("align_assign_thresh"); + + if ( (options::align_enum_equ_span() > 0) + || (options::align_assign_span() > 0)) + { + align_assign(Chunk::GetHead(), + options::align_assign_span(), + options::align_assign_thresh(), + nullptr); + } + + if ( (options::align_braced_init_list_span() > 0) // Issue #750 + || (options::align_braced_init_list_thresh() > 0)) + { + align_braced_init_list(Chunk::GetHead(), + options::align_braced_init_list_span(), + options::align_braced_init_list_thresh(), + nullptr); + } + // Align structure initializers + log_rule_B("align_struct_init_span"); + + if (options::align_struct_init_span() > 0) + { + align_struct_initializers(); + } + // Align function prototypes + log_rule_B("align_func_proto_span"); + log_rule_B("align_mix_var_proto"); + + if ( (options::align_func_proto_span() > 0) + && !options::align_mix_var_proto()) + { + align_func_proto(options::align_func_proto_span()); + } + // Align function prototypes + log_rule_B("align_oc_msg_spec_span"); + + if (options::align_oc_msg_spec_span() > 0) + { + align_oc_msg_spec(options::align_oc_msg_spec_span()); + } + // Align OC colons + log_rule_B("align_oc_decl_colon"); + + if (options::align_oc_decl_colon()) + { + align_oc_decl_colon(); + } + log_rule_B("align_asm_colon"); + + if (options::align_asm_colon()) + { + align_asm_colon(); + } + // Align variable definitions in function prototypes + log_rule_B("align_func_params"); + log_rule_B("align_func_params_span"); + + if ( options::align_func_params() + || options::align_func_params_span() > 0) + { + align_func_params(); + } + log_rule_B("align_same_func_call_params"); + + if (options::align_same_func_call_params()) + { + align_same_func_call_params(); + } + // Just in case something was aligned out of order... do it again + quick_align_again(); +} // align_all diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align.h new file mode 100644 index 00000000..91e87f25 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align.h @@ -0,0 +1,16 @@ +/** + * @file align.h + * prototypes for align.c + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef ALIGN_H_INCLUDED +#define ALIGN_H_INCLUDED + +#include "uncrustify_types.h" + + +void align_all(); + +#endif /* ALIGN_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_add.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_add.cpp new file mode 100644 index 00000000..48d20a05 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_add.cpp @@ -0,0 +1,58 @@ +/** + * @file align_add.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_add.h" +#include "uncrustify.h" + + +void align_add(ChunkStack &cs, Chunk *pc, size_t &max_col) +{ + LOG_FUNC_ENTRY(); + + size_t min_col; + Chunk *prev = Chunk::NullChunkPtr; + + if (pc != nullptr) + { + prev = pc->GetPrev(); + } + + if ( prev->IsNullChunk() + || prev->IsNewline()) + { + min_col = 1; + LOG_FMT(LALADD, "%s(%d): pc orig line=%zu, pc->col=%zu max_col=%zu min_col=%zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetColumn(), max_col, min_col); + } + else + { + if (prev->Is(CT_COMMENT_MULTI)) + { + min_col = prev->GetOrigColEnd() + 1; + } + else + { + min_col = prev->GetColumn() + prev->Len() + 1; + } + LOG_FMT(LALADD, "%s(%d): pc orig line=%zu, pc->col=%zu max_col=%zu min_col=%zu multi:%s prev->col=%zu prev->Len()=%zu %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetColumn(), max_col, min_col, (prev->Is(CT_COMMENT_MULTI)) ? "Y" : "N", + (prev->Is(CT_COMMENT_MULTI)) ? prev->GetOrigColEnd() : (UINT32)prev->GetColumn(), prev->Len(), get_token_name(prev->GetType())); + } + + if (cs.Empty()) + { + max_col = 0; + } + cs.Push_Back(pc); + + if (min_col > max_col) + { + max_col = min_col; + } +} // align_add diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_add.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_add.h new file mode 100644 index 00000000..e178b5bd --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_add.h @@ -0,0 +1,18 @@ +/** + * @file align_add.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_ADD_H_INCLUDED +#define ALIGN_ADD_H_INCLUDED + +#include "chunk.h" +#include "ChunkStack.h" + +void align_add(ChunkStack &cs, Chunk *pc, size_t &max_col); + +#endif /* ALIGN_ADD_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_asm_colon.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_asm_colon.cpp new file mode 100644 index 00000000..4eaca4f3 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_asm_colon.cpp @@ -0,0 +1,62 @@ +/** + * @file align_asm_colon.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_asm_colon.h" + +#include "align_stack.h" +#include "chunk.h" + + +void align_asm_colon() +{ + LOG_FUNC_ENTRY(); + + bool did_nl; + AlignStack cas; // for the colons + + cas.Start(4); + + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + if (pc->IsNot(CT_ASM_COLON)) + { + pc = pc->GetNext(); + continue; + } + cas.Reset(); + + pc = pc->GetNextNcNnl(E_Scope::PREPROC); + size_t level = pc->IsNotNullChunk() ? pc->GetLevel() : 0; + did_nl = true; + + while ( pc->IsNotNullChunk() + && pc->GetLevel() >= level) + { + if (pc->IsNewline()) + { + cas.NewLines(pc->GetNlCount()); + did_nl = true; + } + else if (pc->Is(CT_ASM_COLON)) + { + cas.Flush(); + did_nl = true; + } + else if (did_nl) + { + did_nl = false; + cas.Add(pc); + } + pc = pc->GetNextNc(E_Scope::PREPROC); + } + cas.End(); + } +} // align_asm_colon diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_asm_colon.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_asm_colon.h new file mode 100644 index 00000000..2b0d3738 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_asm_colon.h @@ -0,0 +1,25 @@ +/** + * @file align_asm_colon.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_ASM_COLON_H_INCLUDED +#define ALIGN_ASM_COLON_H_INCLUDED + + +/** + * Aligns asm declarations on the colon + * asm volatile ( + * "xxx" + * : "x"(h), + * "y"(l), + * : "z"(h) + * ); + */ +void align_asm_colon(); + +#endif /* ALIGN_ASM_COLON_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_assign.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_assign.cpp new file mode 100644 index 00000000..1943e353 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_assign.cpp @@ -0,0 +1,290 @@ +/** + * @file align_assign.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_assign.h" + +#include "align_stack.h" +#include "log_rules.h" + +constexpr static auto LCURRENT = LALASS; + +using namespace uncrustify; + + +Chunk *align_assign(Chunk *first, size_t span, size_t thresh, size_t *p_nl_count) +{ + LOG_FUNC_ENTRY(); + + if ( first == nullptr + || first->IsNullChunk()) + { + // coveralls will complain here. There are no example for that. + // see https://en.wikipedia.org/wiki/Robustness_principle + return(nullptr); + } + size_t my_level = first->GetLevel(); + + char copy[1000]; + + LOG_FMT(LALASS, "%s(%d): [my_level is %zu]: start checking with '%s', on orig line %zu, span is %zu, thresh is %zu\n", + __func__, __LINE__, my_level, first->ElidedText(copy), first->GetOrigLine(), span, thresh); + + // If we are aligning on a tabstop, we shouldn't right-align + AlignStack as; // regular assigns + + as.Start(span, thresh); + log_rule_B("align_on_tabstop"); + as.m_right_align = !options::align_on_tabstop(); + + AlignStack vdas; // variable def assigns + + vdas.Start(span, thresh); + vdas.m_right_align = as.m_right_align; + + std::deque<AlignStack> fcnDefault(1); + + fcnDefault.back().Start(span, thresh); + fcnDefault.back().m_right_align = as.m_right_align; + + AlignStack fcnProto; + + fcnProto.Start(span, thresh); + fcnProto.m_right_align = as.m_right_align; + + size_t var_def_cnt = 0; + size_t equ_count = 0; + size_t nl_count = 0; + size_t fcn_idx = 0; + size_t tmp; + Chunk *pc = first; + Chunk *vdas_pc = nullptr; + + while (pc->IsNotNullChunk()) + { + LOG_FMT(LALASS, "%s(%d): orig line is %zu, check pc->Text() is '%s', type is %s, m_parentType is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->ElidedText(copy), get_token_name(pc->GetType()), get_token_name(pc->GetParentType())); + + if (nl_count != 0) + { + if (vdas_pc != nullptr) + { + LOG_FMT(LALASS, "%s(%d): vdas.Add on '%s' on orig line %zu, orig col is %zu\n", + __func__, __LINE__, vdas_pc->Text(), vdas_pc->GetOrigLine(), vdas_pc->GetOrigCol()); + vdas.Add(vdas_pc); + vdas_pc = nullptr; + } + + if (p_nl_count != nullptr) + { + *p_nl_count += nl_count; + } + as.NewLines(nl_count); + vdas.NewLines(nl_count); + fcnProto.NewLines(nl_count); + + for (auto &fcn : fcnDefault) + { + fcn.NewLines(nl_count); + } + + fcn_idx = 0; + nl_count = 0; + var_def_cnt = 0; + equ_count = 0; + } + + // Don't check inside SPAREN, PAREN or SQUARE groups + if ( pc->Is(CT_SPAREN_OPEN) + // || pc->Is(CT_FPAREN_OPEN) Issue #1340 + || pc->Is(CT_SQUARE_OPEN) + || pc->Is(CT_PAREN_OPEN)) + { + LOG_FMT(LALASS, "%s(%d): Don't check inside SPAREN, PAREN or SQUARE groups, type is %s\n", + __func__, __LINE__, get_token_name(pc->GetType())); + tmp = pc->GetOrigLine(); + pc = pc->GetClosingParen(); + + if (pc->IsNotNullChunk()) + { + nl_count = pc->GetOrigLine() - tmp; + } + continue; + } + + // Recurse if a brace set is found + if ( ( pc->Is(CT_BRACE_OPEN) + || pc->Is(CT_VBRACE_OPEN)) + && !(pc->GetParentType() == CT_BRACED_INIT_LIST)) + { + size_t myspan; + size_t mythresh; + + if (pc->GetParentType() == CT_ENUM) + { + log_rule_B("align_enum_equ_span"); + myspan = options::align_enum_equ_span(); + log_rule_B("align_enum_equ_thresh"); + mythresh = options::align_enum_equ_thresh(); + } + else + { + log_rule_B("align_assign_span"); + myspan = options::align_assign_span(); + log_rule_B("align_assign_thresh"); + mythresh = options::align_assign_thresh(); + } + pc = align_assign(pc->GetNext(), myspan, mythresh, &nl_count); + continue; + } + + // Done with this brace set? + if ( ( pc->Is(CT_BRACE_CLOSE) + || pc->Is(CT_VBRACE_CLOSE)) + && !(pc->GetParentType() == CT_BRACED_INIT_LIST)) + { + pc = pc->GetNext(); + break; + } + + if (pc->IsNewline()) + { + nl_count = pc->GetNlCount(); + } + else if ( pc->TestFlags(PCF_VAR_DEF) + && !pc->TestFlags(PCF_IN_CONST_ARGS) // Issue #1717 + && !pc->TestFlags(PCF_IN_FCN_DEF) // Issue #1717 + && !pc->TestFlags(PCF_IN_FCN_CALL)) // Issue #1717 + { + // produces much more log output. Use it only debugging purpose + //LOG_FMT(LALASS, "%s(%d): log_pcf_flags pc->GetFlags():\n ", __func__, __LINE__); + //log_pcf_flags(LALASS, pc->GetFlags()); + var_def_cnt++; + } + else if ( var_def_cnt > 1 + && !options::align_assign_on_multi_var_defs()) + { + // we hit the second variable def and align was not requested - don't look for assigns, don't align + LOG_FMT(LALASS, "%s(%d): multiple var defs found and alignment was not requested\n", + __func__, __LINE__); + vdas_pc = nullptr; + } + else if ( equ_count == 0 // indent only if first '=' in line + && !pc->TestFlags(PCF_IN_TEMPLATE) // and it is not inside a template #999 + && ( pc->Is(CT_ASSIGN) + || pc->Is(CT_ASSIGN_DEFAULT_ARG) + || pc->Is(CT_ASSIGN_FUNC_PROTO))) + { + if (pc->Is(CT_ASSIGN)) // Issue #2236 + { + equ_count++; + } + LOG_FMT(LALASS, "%s(%d): align_assign_decl_func() is %d\n", + __func__, __LINE__, options::align_assign_decl_func()); + // produces much more log output. Use it only debugging purpose + //LOG_FMT(LALASS, "%s(%d): log_pcf_flags pc->GetFlags(): ", __func__, __LINE__); + //log_pcf_flags(LALASS, pc->GetFlags()); + + log_rule_B("align_assign_decl_func"); + + if ( options::align_assign_decl_func() == 0 // Align with other assignments (default) + && ( pc->Is(CT_ASSIGN_DEFAULT_ARG) // Foo( int bar = 777 ); + || pc->Is(CT_ASSIGN_FUNC_PROTO))) // Foo( const Foo & ) = delete; + { + LOG_FMT(LALASS, "%s(%d): fcnDefault[%zu].Add on '%s' on orig line %zu, orig col is %zu\n", + __func__, __LINE__, fcn_idx, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + + if (++fcn_idx == fcnDefault.size()) + { + fcnDefault.emplace_back(); + fcnDefault.back().Start(span, thresh); + fcnDefault.back().m_right_align = as.m_right_align; + } + fcnDefault[fcn_idx].Add(pc); + } + else if (options::align_assign_decl_func() == 1) // Align with each other + { + log_rule_B("align_assign_decl_func"); + + if (pc->Is(CT_ASSIGN_DEFAULT_ARG)) // Foo( int bar = 777 ); + { + LOG_FMT(LALASS, "%s(%d): default: fcnDefault[%zu].Add on '%s' on orig line %zu, orig col is %zu\n", + __func__, __LINE__, fcn_idx, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + + if (++fcn_idx == fcnDefault.size()) + { + fcnDefault.emplace_back(); + fcnDefault.back().Start(span, thresh); + fcnDefault.back().m_right_align = as.m_right_align; + } + fcnDefault[fcn_idx].Add(pc); + } + else if (pc->Is(CT_ASSIGN_FUNC_PROTO)) // Foo( const Foo & ) = delete; + { + LOG_FMT(LALASS, "%s(%d): proto: fcnProto.Add on '%s' on orig line %zu, orig col is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + fcnProto.Add(pc); + } + else if (pc->Is(CT_ASSIGN)) // Issue #2197 + { + vdas_pc = pc; + } + } + else if ( options::align_assign_decl_func() == 2 // Don't align + && ( pc->Is(CT_ASSIGN_DEFAULT_ARG) // Foo( int bar = 777 ); + || pc->Is(CT_ASSIGN_FUNC_PROTO))) // Foo( const Foo & ) = delete; + { + log_rule_B("align_assign_decl_func"); + LOG_FMT(LALASS, "%s(%d): Don't align\n", // Issue #2236 + __func__, __LINE__); + } + else if (var_def_cnt != 0) + { + vdas_pc = pc; + } + else + { + if (pc->Is(CT_ASSIGN)) + { + LOG_FMT(LALASS, "%s(%d): as.Add on '%s' on orig line %zu, orig col is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + as.Add(pc); + } + } + } + pc = pc->GetNext(); + } + + if (vdas_pc != nullptr) + { + LOG_FMT(LALASS, "%s(%d): vdas.Add on '%s' on orig line %zu, orig col is %zu\n", + __func__, __LINE__, vdas_pc->Text(), vdas_pc->GetOrigLine(), vdas_pc->GetOrigCol()); + vdas.Add(vdas_pc); + vdas_pc = nullptr; + } + as.End(); + vdas.End(); + + for (auto &fcn : fcnDefault) + { + fcn.End(); + } + + fcnProto.End(); + + if (pc->IsNotNullChunk()) + { + LOG_FMT(LALASS, "%s(%d): done on '%s' on orig line %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine()); + } + else + { + LOG_FMT(LALASS, "%s(%d): done on NULL\n", __func__, __LINE__); + } + return(pc); +} // align_assign diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_assign.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_assign.h new file mode 100644 index 00000000..8a23d0d5 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_assign.h @@ -0,0 +1,25 @@ +/** + * @file align_assign.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_ASSIGN_H_INCLUDED +#define ALIGN_ASSIGN_H_INCLUDED + +#include "chunk.h" + +/** + * Aligns all assignment operators on the same level as first, starting with + * first. + * For variable definitions, only consider the '=' for the first variable. + * Otherwise, only look at the first '=' on the line. + * + * @param first chunk pointing to the first assignment + */ +Chunk *align_assign(Chunk *first, size_t span, size_t thresh, size_t *p_nl_count); + +#endif /* ALIGN_ASSIGN_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_braced_init_list.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_braced_init_list.cpp new file mode 100644 index 00000000..5322586b --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_braced_init_list.cpp @@ -0,0 +1,168 @@ +/** + * @file align_braced_init_list.cpp + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#include "align_braced_init_list.h" + +#include "align_stack.h" +#include "log_rules.h" + +constexpr static auto LCURRENT = LALASS; + +using namespace uncrustify; + + +Chunk *align_braced_init_list(Chunk *first, size_t span, size_t thresh, size_t *p_nl_count) +{ + LOG_FUNC_ENTRY(); + + if ( first == nullptr + || first->IsNullChunk()) + { + // coveralls will complain here. There are no example for that. + // see https://en.wikipedia.org/wiki/Robustness_principle + return(nullptr); + } + size_t my_level = first->GetLevel(); + + char copy[1000]; + + LOG_FMT(LALASS, "%s(%d): [my_level is %zu]: start checking with '%s', on orig line %zu, span is %zu, thresh is %zu\n", + __func__, __LINE__, my_level, first->ElidedText(copy), first->GetOrigLine(), span, thresh); + + // If we are aligning on a tabstop, we shouldn't right-align + + AlignStack vdas; // variable def assigns + + vdas.Start(span, thresh); + vdas.m_right_align = !options::align_on_tabstop(); + + size_t var_def_cnt = 0; + size_t equ_count = 0; + size_t tmp; + Chunk *pc = first; + + while ( pc != nullptr + && pc->IsNotNullChunk()) + { + LOG_FMT(LALASS, "%s(%d): orig line is %zu, check pc->Text() is '%s', type is %s, parent type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->ElidedText(copy), get_token_name(pc->GetType()), get_token_name(pc->GetParentType())); + + // Don't check inside SPAREN, PAREN or SQUARE groups + if ( pc->Is(CT_SPAREN_OPEN) + || pc->Is(CT_SQUARE_OPEN) + || pc->Is(CT_PAREN_OPEN)) + { + LOG_FMT(LALASS, "%s(%d)OK: Don't check inside SPAREN, PAREN or SQUARE groups, type is %s\n", + __func__, __LINE__, get_token_name(pc->GetType())); + tmp = pc->GetOrigLine(); + pc = pc->GetClosingParen(); + + if (pc->IsNotNullChunk()) + { + vdas.NewLines(pc->GetOrigLine() - tmp); + } + continue; + } + + // Recurse if a brace set is found + if ( pc->Is(CT_BRACE_OPEN) + && !(pc->GetParentType() == CT_BRACED_INIT_LIST)) + { + size_t myspan; + size_t mythresh; + + size_t sub_nl_count = 0; + + log_rule_B("align_braced_init_list_span"); + myspan = options::align_braced_init_list_span(); + log_rule_B("align_braced_init_list_thresh"); + mythresh = options::align_braced_init_list_thresh(); + pc = align_braced_init_list(pc->GetNextNcNnl(), myspan, mythresh, &sub_nl_count); + + if (sub_nl_count > 0) + { + vdas.NewLines(sub_nl_count); + + if (p_nl_count != nullptr) + { + *p_nl_count += sub_nl_count; + } + } + continue; + } + + // Done with this brace set? + if ( ( pc->Is(CT_BRACE_CLOSE) + || pc->Is(CT_VBRACE_CLOSE)) + && !(pc->GetParentType() == CT_BRACED_INIT_LIST)) + { + pc = pc->GetNext(); + break; + } + + if (pc->IsNewline()) + { + vdas.NewLines(pc->GetNlCount()); + + if (p_nl_count != nullptr) + { + *p_nl_count += pc->GetNlCount(); + } + var_def_cnt = 0; + equ_count = 0; + } + else if ( pc->TestFlags(PCF_VAR_DEF) + && !pc->TestFlags(PCF_IN_CONST_ARGS) // Issue #1717 + && !pc->TestFlags(PCF_IN_FCN_DEF) // Issue #1717 + && !pc->TestFlags(PCF_IN_FCN_CALL)) // Issue #1717 + { + // produces much more log output. Use it only debugging purpose + //LOG_FMT(LALASS, "%s(%d): log_pcf_flags pc->GetFlags():\n ", __func__, __LINE__); + //log_pcf_flags(LALASS, pc->GetFlags()); + var_def_cnt++; + } + else if (var_def_cnt > 1) + { + // we hit the second variable def - don't look, don't align + vdas.Reset(); + } + else if ( equ_count == 0 + && !pc->TestFlags(PCF_IN_TEMPLATE) + && pc->Is(CT_BRACE_OPEN) + && (pc->GetParentType() == CT_BRACED_INIT_LIST)) + + { + equ_count++; + LOG_FMT(LALASS, "%s(%d)OK: align_braced_init_list_span() is %d\n", + __func__, __LINE__, options::align_braced_init_list_span()); + // produces much more log output. Use it only debugging purpose + //LOG_FMT(LALASS, "%s(%d): log_pcf_flags pc->GetFlags(): ", __func__, __LINE__); + //log_pcf_flags(LALASS, pc->GetFlags()); + + if (var_def_cnt != 0) + { + LOG_FMT(LALASS, "%s(%d)OK: vdas.Add on '%s' on orig line %zu, orig col is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + vdas.Add(pc); + } + } + pc = pc->GetNext(); + } + vdas.End(); + + if ( pc != nullptr + && pc->IsNotNullChunk()) + { + LOG_FMT(LALASS, "%s(%d): done on '%s' on orig line %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine()); + } + else + { + LOG_FMT(LALASS, "%s(%d): done on NULL\n", __func__, __LINE__); + } + return(pc); +} // align_braced_init_list diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_braced_init_list.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_braced_init_list.h new file mode 100644 index 00000000..e29868e0 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_braced_init_list.h @@ -0,0 +1,21 @@ +/** + * @file align_braced_init_list.h + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#ifndef ALIGN_BRACED_INIT_LIST_H_INCLUDED +#define ALIGN_BRACED_INIT_LIST_H_INCLUDED + +#include "chunk.h" + +/** + * Aligns all braced init list operators on the same level as first, starting with + * first. + * + * @param first chunk pointing to the first braced init list + */ +Chunk *align_braced_init_list(Chunk *first, size_t span, size_t thresh, size_t *p_nl_count); + +#endif /* ALIGN_BRACED_INIT_LIST_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_eigen_comma_init.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_eigen_comma_init.cpp new file mode 100644 index 00000000..d096a9a7 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_eigen_comma_init.cpp @@ -0,0 +1,113 @@ +/** + * @file align_eigen_comma_init.cpp + * + * @author Matthew Woehlke + * copied/adapted from align_left_shift.cpp + * @author Guy Maurel + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_eigen_comma_init.h" + +#include "align_stack.h" +#include "indent.h" +#include "log_rules.h" + +constexpr static auto LCURRENT = LALIGN; + +using namespace uncrustify; + + +void align_eigen_comma_init() +{ + LOG_FUNC_ENTRY(); + + Chunk *start = Chunk::NullChunkPtr; + AlignStack as; + + as.Start(255); + + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + LOG_CHUNK(LTOK, pc); + + if ( start->IsNotNullChunk() + && ((pc->GetFlags() & PCF_IN_PREPROC) != (start->GetFlags() & PCF_IN_PREPROC))) + { + // a change in preproc status restarts the aligning + as.Flush(); + start = Chunk::NullChunkPtr; + } + else if (pc->IsNewline()) + { + as.NewLines(pc->GetNlCount()); + } + else if ( start->IsNotNullChunk() + && pc->GetLevel() < start->GetLevel()) + { + // A drop in level restarts the aligning + as.Flush(); + start = Chunk::NullChunkPtr; + } + else if ( start->IsNotNullChunk() + && pc->GetLevel() > start->GetLevel()) + { + // Ignore any deeper levels when aligning + } + else if (pc->Is(CT_SEMICOLON)) + { + // A semicolon at the same level flushes + as.Flush(); + start = Chunk::NullChunkPtr; + } + else if ( !pc->TestFlags(PCF_IN_ENUM) + && !pc->TestFlags(PCF_IN_TYPEDEF) + && pc->IsString("<<")) + { + if (pc->GetParentType() == CT_OPERATOR) + { + // Ignore operator<< + } + else + { + /* + * check if the first one is actually on a blank line and then + * indent it. Eg: + * + * cout + * << "something"; + */ + Chunk *prev = pc->GetPrev(); + + if ( prev->IsNotNullChunk() + && prev->IsNewline()) + { + log_rule_B("indent_columns"); + indent_to_column(pc, pc->GetColumnIndent() + options::indent_columns()); + pc->SetColumnIndent(pc->GetColumn()); + pc->SetFlagBits(PCF_DONT_INDENT); + } + // Restart alignment + as.Flush(); + as.Add(pc->GetNext()); + start = pc; + } + } + else if (!as.m_aligned.Empty()) + { + Chunk *prev = pc->GetPrev(); + + if ( prev->IsNewline() + && pc->GetPrevNcNnl()->Is(CT_COMMA)) + { + log_rule_B("align_eigen_comma_init"); + as.Add(pc); + } + } + pc = pc->GetNext(); + } + as.End(); +} // align_left_shift diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_eigen_comma_init.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_eigen_comma_init.h new file mode 100644 index 00000000..6647f030 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_eigen_comma_init.h @@ -0,0 +1,14 @@ +/** + * @file align_left_shift.h + * + * @author Matthew Woehlke + * @license GPL v2+ + */ + +#ifndef ALIGN_EIGEN_COMMA_INIT_H_INCLUDED +#define ALIGN_EIGEN_COMMA_INIT_H_INCLUDED + +//! Align comma-separated expressions following left shift operator '<<' +void align_eigen_comma_init(); + +#endif /* ALIGN_EIGEN_COMMA_INIT_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_func_params.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_func_params.cpp new file mode 100644 index 00000000..50e04d78 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_func_params.cpp @@ -0,0 +1,186 @@ +/** + * @file align_func_params.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_func_params.h" + +#include "align_stack.h" +#include "log_rules.h" + +#include <algorithm> // to get max + +constexpr static auto LCURRENT = LALIGN; + +using namespace uncrustify; + + +Chunk *align_func_param(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LAS, "AlignStack::%s(%d): Candidate is '%s': orig line is %zu, column is %zu, type is %s, level is %zu\n", + __func__, __LINE__, start->Text(), start->GetOrigLine(), start->GetColumn(), + get_token_name(start->GetType()), start->GetLevel()); + // Defaults, if the align_func_params = true + size_t myspan = 2; + size_t mythresh = 0; + size_t mygap = 0; + + // Override, if the align_func_params_span > 0 + log_rule_B("align_func_params_span"); + + if (options::align_func_params_span() > 0) + { + myspan = options::align_func_params_span(); + log_rule_B("align_func_params_thresh"); + mythresh = options::align_func_params_thresh(); + log_rule_B("align_func_params_gap"); + mygap = options::align_func_params_gap(); + } + const size_t HOW_MANY_AS = 16; // Issue #2921 + AlignStack many_as[HOW_MANY_AS + 1]; + + size_t max_level_is = 0; + + log_rule_B("align_var_def_star_style"); + log_rule_B("align_var_def_amp_style"); + + for (size_t idx = 0; idx <= HOW_MANY_AS; idx++) + { + many_as[idx].Start(myspan, mythresh); + many_as[idx].m_gap = mygap; + many_as[idx].m_star_style = static_cast<AlignStack::StarStyle>(options::align_var_def_star_style()); + many_as[idx].m_amp_style = static_cast<AlignStack::StarStyle>(options::align_var_def_amp_style()); + } + + size_t comma_count = 0; + size_t chunk_count = 0; + Chunk *pc = start; + + while ((pc = pc->GetNext())->IsNotNullChunk()) + { + chunk_count++; + LOG_CHUNK(LTOK, pc); + + if (pc->Is(CT_FUNC_VAR)) // Issue #2278 + { + // look after 'protect parenthesis' + Chunk *after = pc->GetNextNc(); + + if (after->Is(CT_PAREN_CLOSE)) + { + Chunk *before = after->GetPrevType(CT_PAREN_OPEN, after->GetLevel()); + + if (before->IsNotNullChunk()) + { + // these are 'protect parenthesis' + // change the types and the level + before->SetType(CT_PPAREN_OPEN); + after->SetType(CT_PPAREN_CLOSE); + pc->SetLevel(before->GetLevel()); + Chunk *tmp = pc->GetPrevNc(); + + if (tmp->Is(CT_PTR_TYPE)) + { + tmp->SetLevel(before->GetLevel()); + } + } + } + } + + if (pc->IsNewline()) + { + comma_count = 0; + chunk_count = 0; + many_as[pc->GetLevel()].NewLines(pc->GetNlCount()); + } + else if (pc->GetLevel() <= start->GetLevel()) + { + break; + } + else if (pc->TestFlags(PCF_VAR_DEF)) + { + if (chunk_count > 1) + { + if (pc->GetLevel() > HOW_MANY_AS) + { + fprintf(stderr, "%s(%d): Not enough memory for Stack\n", + __func__, __LINE__); + fprintf(stderr, "%s(%d): the current maximum is %zu\n", + __func__, __LINE__, HOW_MANY_AS); + log_flush(true); + exit(EX_SOFTWARE); + } + max_level_is = max(max_level_is, pc->GetLevel()); + many_as[pc->GetLevel()].Add(pc); + } + } + else if (comma_count > 0) + { + if (!pc->IsComment()) + { + comma_count = 2; + break; + } + } + else if (pc->Is(CT_COMMA)) + { + if (pc->TestFlags(PCF_IN_TEMPLATE)) // Issue #2757 + { + LOG_FMT(LFLPAREN, "%s(%d): comma is in template\n", + __func__, __LINE__); + } + else + { + Chunk *tmp_prev = pc->GetPrevNc(); + + if (!tmp_prev->IsNewline()) // don't count leading commas + { + comma_count++; + LOG_FMT(LFLPAREN, "%s(%d): comma_count is %zu\n", + __func__, __LINE__, comma_count); + } + } + } + } + + if (comma_count <= 1) + { + for (size_t idx = 1; idx <= max_level_is; idx++) + { + many_as[idx].End(); + } + } + return(pc); +} // align_func_param + + +void align_func_params() +{ + LOG_FUNC_ENTRY(); + Chunk *pc = Chunk::GetHead(); + + while ((pc = pc->GetNext())->IsNotNullChunk()) + { + LOG_FMT(LFLPAREN, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s', type is %s, parent type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), + get_token_name(pc->GetType()), get_token_name(pc->GetParentType())); + + if ( pc->IsNot(CT_FPAREN_OPEN) + || ( pc->GetParentType() != CT_FUNC_PROTO + && pc->GetParentType() != CT_FUNC_DEF + && pc->GetParentType() != CT_FUNC_CLASS_PROTO + && pc->GetParentType() != CT_FUNC_CLASS_DEF + && pc->GetParentType() != CT_TYPEDEF)) + { + continue; + } + // We are on a open parenthesis of a prototype + pc = align_func_param(pc); + } +} // void align_func_params diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_func_params.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_func_params.h new file mode 100644 index 00000000..4beb8cbf --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_func_params.h @@ -0,0 +1,19 @@ +/** + * @file align_func_params.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_FUNC_PARAMS_H_INCLUDED +#define ALIGN_FUNC_PARAMS_H_INCLUDED + +#include "chunk.h" + +void align_func_params(); + +Chunk *align_func_param(Chunk *start); + +#endif /* ALIGN_FUNC_PARAMS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_func_proto.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_func_proto.cpp new file mode 100644 index 00000000..f56cb254 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_func_proto.cpp @@ -0,0 +1,227 @@ +/** + * @file align_func_proto.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_func_proto.h" + +#include "align_stack.h" +#include "align_tools.h" +#include "log_rules.h" + +#include <algorithm> // to get max + +constexpr static auto LCURRENT = LALPROTO; + +using namespace uncrustify; + + +void align_func_proto(size_t span) +{ + LOG_FUNC_ENTRY(); + + size_t myspan = span; + size_t mythresh = 0; + + log_rule_B("align_func_proto_gap"); + size_t mygap = options::align_func_proto_gap(); + + log_rule_B("align_func_proto_thresh"); + mythresh = options::align_func_proto_thresh(); + + // Issue #2771 + // we align token-1 and token-2 if: + // token-1->GetLevel() == token-2->GetLevel() + // and + // token-1->GetBraceLevel() == token-2->GetBraceLevel() + // we don't check if token-1 and token-2 are in the same block + + log_rule_B("align_func_proto_star_style"); + size_t mystar_style = options::align_func_proto_star_style(); + + log_rule_B("align_func_proto_amp_style"); + size_t myamp_style = options::align_func_proto_amp_style(); + + + size_t num_of_column = 1; + size_t num_of_row = 1; + AlignStack *stack_init_value = nullptr; + + + // Issue #2984 + vector<vector<AlignStack *> > many_as; + // Issue #2771 + vector<vector<AlignStack *> > many_as_brace; + + // init the vector ... + many_as.resize(num_of_column, vector<AlignStack *>(num_of_row, stack_init_value)); + many_as_brace.resize(num_of_column, vector<AlignStack *>(num_of_row, stack_init_value)); + + log_rule_B("align_single_line_brace_gap"); + size_t mybr_gap = options::align_single_line_brace_gap(); + + + bool look_bro = false; + Chunk *toadd; + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + char copy[1000]; + LOG_FMT(LAS, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s', type is %s, level is %zu, brace level is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->ElidedText(copy), + get_token_name(pc->GetType()), pc->GetLevel(), pc->GetBraceLevel()); + + // make the vector larger if necessary + if ( pc->GetLevel() >= num_of_column // Issue #2960 + || pc->GetBraceLevel() >= num_of_row) + { + num_of_column = pc->GetLevel() + 1; + num_of_row = pc->GetBraceLevel() + 1; + + many_as.resize(num_of_column); + many_as_brace.resize(num_of_column); + + for (size_t i = 0; i < num_of_column; ++i) + { + many_as[i].resize(num_of_row); + many_as_brace[i].resize(num_of_row); + } + } + + if ( pc->IsNewline() + && !pc->TestFlags(PCF_IN_FCN_CALL)) // Issue #2831 + { + look_bro = false; + AlignStack *stack_at_l_bl = many_as.at(pc->GetLevel()).at(pc->GetBraceLevel()); + + if (stack_at_l_bl == nullptr) + { + // get a Stack + stack_at_l_bl = new AlignStack(); + // start it + stack_at_l_bl->Start(myspan, mythresh); + stack_at_l_bl->m_gap = mygap; + stack_at_l_bl->m_star_style = static_cast<AlignStack::StarStyle>(mystar_style); + stack_at_l_bl->m_amp_style = static_cast<AlignStack::StarStyle>(myamp_style); + // store + many_as.at(pc->GetLevel()).at(pc->GetBraceLevel()) = stack_at_l_bl; + } + stack_at_l_bl->Debug(); + + for (size_t idx = 0; idx < num_of_column; idx++) + { + for (size_t idx_brace = 0; idx_brace < num_of_row; idx_brace++) + { + stack_at_l_bl = many_as.at(idx).at(idx_brace); + + if (stack_at_l_bl != nullptr) + { + stack_at_l_bl->NewLines(pc->GetNlCount()); + } + } + } + + AlignStack *stack_at_l_bl_brace = many_as_brace.at(pc->GetLevel()).at(pc->GetBraceLevel()); + + if (stack_at_l_bl_brace == nullptr) + { + // get a Stack + stack_at_l_bl_brace = new AlignStack(); + // start it + stack_at_l_bl_brace->Start(myspan, mythresh); + stack_at_l_bl_brace->m_gap = mybr_gap; + // store + many_as_brace.at(pc->GetLevel()).at(pc->GetBraceLevel()) = stack_at_l_bl_brace; + } + stack_at_l_bl_brace->Debug(); + stack_at_l_bl_brace->NewLines(pc->GetNlCount()); + } + else if ( pc->Is(CT_FUNC_PROTO) + || ( pc->Is(CT_FUNC_DEF) + && options::align_single_line_func())) + { + log_rule_B("align_single_line_func"); + log_rule_B("align_on_operator"); + + if ( pc->GetParentType() == CT_OPERATOR + && options::align_on_operator()) + { + toadd = pc->GetPrevNcNnl(); + } + else + { + toadd = pc; + } + Chunk *tmp = step_back_over_member(toadd); + LOG_FMT(LAS, "%s(%d): tmp->Text() is '%s', orig line is %zu, orig col is %zu, level is %zu, brace level is %zu\n", + __func__, __LINE__, tmp->Text(), tmp->GetOrigLine(), tmp->GetOrigCol(), + tmp->GetLevel(), tmp->GetBraceLevel()); + // test the Stack + AlignStack *stack_at_l_bl = many_as.at(pc->GetLevel()).at(pc->GetBraceLevel()); + + if (stack_at_l_bl == nullptr) + { + // get a Stack + stack_at_l_bl = new AlignStack(); + // start it + stack_at_l_bl->Start(myspan, mythresh); + stack_at_l_bl->m_gap = mygap; + stack_at_l_bl->m_star_style = static_cast<AlignStack::StarStyle>(mystar_style); + stack_at_l_bl->m_amp_style = static_cast<AlignStack::StarStyle>(myamp_style); + // store + many_as.at(pc->GetLevel()).at(pc->GetBraceLevel()) = stack_at_l_bl; + } + stack_at_l_bl->Add(tmp); + log_rule_B("align_single_line_brace"); + look_bro = (pc->Is(CT_FUNC_DEF)) + && options::align_single_line_brace(); + } + else if ( look_bro + && pc->Is(CT_BRACE_OPEN) + && pc->TestFlags(PCF_ONE_LINER)) + { + AlignStack *stack_at_l_bl_brace = many_as_brace.at(pc->GetLevel()).at(pc->GetBraceLevel()); + + if (stack_at_l_bl_brace == nullptr) + { + stack_at_l_bl_brace = new AlignStack(); + stack_at_l_bl_brace->Start(myspan, mythresh); + stack_at_l_bl_brace->m_gap = mybr_gap; + many_as_brace.at(pc->GetLevel()).at(pc->GetBraceLevel()) = stack_at_l_bl_brace; + } + stack_at_l_bl_brace->Debug(); + stack_at_l_bl_brace->Add(pc); + look_bro = false; + } + } + + LOG_FMT(LAS, "%s(%d): as\n", __func__, __LINE__); + + // purge + for (size_t idx = 0; idx < num_of_column; idx++) + { + for (size_t idx_brace = 0; idx_brace < num_of_row; idx_brace++) + { + AlignStack *stack_at_l_bl = many_as.at(idx).at(idx_brace); + + if (stack_at_l_bl != nullptr) + { + stack_at_l_bl->End(); + delete stack_at_l_bl; + stack_at_l_bl = nullptr; + } + AlignStack *stack_at_l_bl_brace = many_as_brace.at(idx).at(idx_brace); + + if (stack_at_l_bl_brace != nullptr) + { + stack_at_l_bl_brace->End(); + delete stack_at_l_bl_brace; + stack_at_l_bl_brace = nullptr; + } + } + } +} // align_func_proto diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_func_proto.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_func_proto.h new file mode 100644 index 00000000..811020e0 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_func_proto.h @@ -0,0 +1,18 @@ +/** + * @file align_func_proto.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_FUNC_PROTO_H_INCLUDED +#define ALIGN_FUNC_PROTO_H_INCLUDED + +#include "chunk.h" + +//! Aligns all function prototypes in the file. +void align_func_proto(size_t span); + +#endif /* ALIGN_FUNC_PROTO_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_init_brace.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_init_brace.cpp new file mode 100644 index 00000000..02d60f17 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_init_brace.cpp @@ -0,0 +1,206 @@ +/** + * @file align_init_brace.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_init_brace.h" + +#include "align_log_al.h" +#include "align_tab_column.h" +#include "align_tools.h" +#include "indent.h" +#include "log_rules.h" + +constexpr static auto LCURRENT = LALBR; + +using namespace uncrustify; + + +void align_init_brace(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + Chunk *num_token = nullptr; + + cpd.al_cnt = 0; + cpd.al_c99_array = false; + + LOG_FMT(LALBR, "%s(%d): start @ orig line is %zu, orig col is %zu\n", + __func__, __LINE__, start->GetOrigLine(), start->GetOrigCol()); + + Chunk *pc = start->GetNextNcNnl(); + Chunk *pcSingle = scan_ib_line(pc); + + if ( pcSingle == nullptr + || ( pcSingle->Is(CT_BRACE_CLOSE) + && pcSingle->GetParentType() == CT_ASSIGN)) + { + // single line - nothing to do + LOG_FMT(LALBR, "%s(%d): single line - nothing to do\n", __func__, __LINE__); + return; + } + LOG_FMT(LALBR, "%s(%d): is not a single line\n", __func__, __LINE__); + + do + { + pc = scan_ib_line(pc); + + // debug dump the current frame + LOG_FMT(LALBR, "%s(%d): debug dump after, orig line is %zu\n", + __func__, __LINE__, pc->GetOrigLine()); + align_log_al(LALBR, pc->GetOrigLine()); + + while (pc->IsNewline()) + { + pc = pc->GetNext(); + } + } while ( pc != nullptr + && pc->IsNotNullChunk() + && pc->GetLevel() > start->GetLevel()); + + // debug dump the current frame + align_log_al(LALBR, start->GetOrigLine()); + + log_rule_B("align_on_tabstop"); + + if ( options::align_on_tabstop() + && cpd.al_cnt >= 1 + && (cpd.al[0].type == CT_ASSIGN)) + { + cpd.al[0].col = align_tab_column(cpd.al[0].col); + } + pc = start->GetNext(); + size_t idx = 0; + + do + { + Chunk *tmp; + + if ( idx == 0 + && ((tmp = skip_c99_array(pc)) != nullptr)) + { + pc = tmp; + + LOG_FMT(LALBR, " -%zu- skipped '[] =' to %s\n", + pc->GetOrigLine(), get_token_name(pc->GetType())); + continue; + } + Chunk *next = pc; + + if (idx < cpd.al_cnt) + { + LOG_FMT(LALBR, "%s(%d): (%zu) check %s vs %s -- ??\n", + __func__, __LINE__, idx, get_token_name(pc->GetType()), get_token_name(cpd.al[idx].type)); + + if (pc->Is(cpd.al[idx].type)) + { + if ( idx == 0 + && cpd.al_c99_array) + { + Chunk *prev = pc->GetPrev(); + + if (prev->IsNewline()) + { + pc->SetFlagBits(PCF_DONT_INDENT); + } + } + LOG_FMT(LALBR, "%s(%d): cpd.al[%zu].col is %zu\n", + __func__, __LINE__, idx, cpd.al[idx].col); + LOG_FMT(LALBR, "%s(%d): (idx is %zu) check %s vs %s -- [%s] to col %zu\n", + __func__, __LINE__, + idx, get_token_name(pc->GetType()), get_token_name(cpd.al[idx].type), pc->Text(), cpd.al[idx].col); + + if (num_token != nullptr) + { + int col_diff = pc->GetColumn() - num_token->GetColumn(); + + reindent_line(num_token, cpd.al[idx].col - col_diff); + //LOG_FMT(LSYS, "-= %zu =- NUM indent [%s] col=%d diff=%d\n", + // num_token->GetOrigLine(), + // num_token->Text(), cpd.al[idx - 1].col, col_diff); + + num_token->SetFlagBits(PCF_WAS_ALIGNED); + num_token = nullptr; + } + + // Comma's need to 'fall back' to the previous token + if (pc->Is(CT_COMMA)) + { + next = pc->GetNext(); + + if (!next->IsNewline()) + { + //LOG_FMT(LSYS, "-= %zu =- indent [%s] col=%d len=%d\n", + // next->GetOrigLine(), + // next->Text(), cpd.al[idx].col, cpd.al[idx].len); + + log_rule_B("align_number_right"); + + if ( (idx < (cpd.al_cnt - 1)) + && options::align_number_right() + && ( next->Is(CT_NUMBER_FP) + || next->Is(CT_NUMBER) + || next->Is(CT_POS) + || next->Is(CT_NEG))) + { + // Need to wait until the next match to indent numbers + num_token = next; + } + else if (idx < (cpd.al_cnt - 1)) + { + LOG_FMT(LALBR, "%s(%d): idx is %zu, al_cnt is %zu, cpd.al[%zu].col is %zu, cpd.al[%zu].len is %zu\n", + __func__, __LINE__, idx, cpd.al_cnt, idx, cpd.al[idx].col, idx, cpd.al[idx].len); + reindent_line(next, cpd.al[idx].col + cpd.al[idx].len); + next->SetFlagBits(PCF_WAS_ALIGNED); + } + } + } + else + { + // first item on the line + LOG_FMT(LALBR, "%s(%d): idx is %zu, cpd.al[%zu].col is %zu\n", + __func__, __LINE__, idx, idx, cpd.al[idx].col); + reindent_line(pc, cpd.al[idx].col); + pc->SetFlagBits(PCF_WAS_ALIGNED); + + // see if we need to right-align a number + log_rule_B("align_number_right"); + + if ( (idx < (cpd.al_cnt - 1)) + && options::align_number_right()) + { + next = pc->GetNext(); + + if ( !next->IsNewline() + && ( next->Is(CT_NUMBER_FP) + || next->Is(CT_NUMBER) + || next->Is(CT_POS) + || next->Is(CT_NEG))) + { + // Need to wait until the next match to indent numbers + num_token = next; + } + } + } + idx++; + } + else + { + LOG_FMT(LALBR, "%s(%d): (%zu) check %s vs %s -- no match\n", + __func__, __LINE__, idx, get_token_name(pc->GetType()), get_token_name(cpd.al[idx].type)); + } + } + + if ( pc->IsNewline() + || next->IsNewline()) + { + idx = 0; + } + pc = pc->GetNext(); + } while ( pc->IsNotNullChunk() + && pc->GetLevel() > start->GetLevel()); +} // align_init_brace diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_init_brace.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_init_brace.h new file mode 100644 index 00000000..c749eb54 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_init_brace.h @@ -0,0 +1,49 @@ +/** + * @file align_init_brace.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_INIT_BRACE_H_INCLUDED +#define ALIGN_INIT_BRACE_H_INCLUDED + +#include "uncrustify_types.h" + +/** + * Generically aligns on '=', '{', '(' and item after ',' + * It scans the first line and picks up the location of those tags. + * It then scans subsequent lines and adjusts the column. + * Finally it does a second pass to align everything. + * + * Aligns all the '=' signs in structure assignments. + * a = { + * .a = 1; + * .type = fast; + * }; + * + * And aligns on '{', numbers, strings, words. + * colors[] = { + * {"red", {255, 0, 0}}, {"blue", { 0, 255, 0}}, + * {"green", { 0, 0, 255}}, {"purple", {255, 255, 0}}, + * }; + * + * For the C99 indexed array assignment, the leading []= is skipped (no aligning) + * struct foo_t bars[] = + * { + * [0] = { .name = "bar", + * .age = 21 }, + * [1] = { .name = "barley", + * .age = 55 }, + * }; + * + * NOTE: this assumes that spacing is at the minimum correct spacing (ie force) + * if it isn't, some extra spaces will be inserted. + * + * @param start Points to the open brace chunk + */ +void align_init_brace(Chunk *start); + +#endif /* ALIGN_INIT_BRACE_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_left_shift.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_left_shift.cpp new file mode 100644 index 00000000..6ac2175c --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_left_shift.cpp @@ -0,0 +1,134 @@ +/** + * @file align_left_shift.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_left_shift.h" + +#include "align_stack.h" +#include "indent.h" +#include "log_rules.h" + +constexpr static auto LCURRENT = LALIGN; + +using namespace uncrustify; + + +void align_left_shift() +{ + LOG_FUNC_ENTRY(); + + Chunk *start = Chunk::NullChunkPtr; + AlignStack as; + + as.Start(255); + + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + if (pc->IsNewline()) + { + LOG_FMT(LALIGN, "%s(%d): orig line is %zu, <Newline>\n", __func__, __LINE__, pc->GetOrigLine()); + } + else + { + char copy[1000]; + LOG_FMT(LALIGN, "%s(%d): orig line is %zu, orig col is %zu, pc->Text() '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->ElidedText(copy)); + } + + if ( start->IsNotNullChunk() + && ((pc->GetFlags() & PCF_IN_PREPROC) != (start->GetFlags() & PCF_IN_PREPROC))) + { + // a change in preproc status restarts the aligning + as.Flush(); + start = Chunk::NullChunkPtr; + } + else if (pc->IsNewline()) + { + as.NewLines(pc->GetNlCount()); + } + else if ( start->IsNotNullChunk() + && pc->GetLevel() < start->GetLevel()) + { + // A drop in level restarts the aligning + as.Flush(); + start = Chunk::NullChunkPtr; + } + else if ( start->IsNotNullChunk() + && pc->GetLevel() > start->GetLevel()) + { + // Ignore any deeper levels when aligning + } + else if (pc->Is(CT_SEMICOLON)) + { + // A semicolon at the same level flushes + as.Flush(); + start = Chunk::NullChunkPtr; + } + else if ( !pc->TestFlags(PCF_IN_ENUM) + && !pc->TestFlags(PCF_IN_TYPEDEF) + && pc->IsString("<<")) + { + if (pc->GetParentType() == CT_OPERATOR) + { + // Ignore operator<< + } + else if (as.m_aligned.Empty()) + { + /* + * check if the first one is actually on a blank line and then + * indent it. Eg: + * + * cout + * << "something"; + */ + Chunk *prev = pc->GetPrev(); + + if ( prev->IsNotNullChunk() + && prev->IsNewline()) + { + log_rule_B("indent_columns"); + indent_to_column(pc, pc->GetColumnIndent() + options::indent_columns()); + pc->SetColumnIndent(pc->GetColumn()); + pc->SetFlagBits(PCF_DONT_INDENT); + } + // first one can be anywhere + as.Add(pc); + start = pc; + } + else if (pc->GetPrev()->IsNewline()) + { + // subsequent ones must be after a newline + as.Add(pc); + } + } + else if (!as.m_aligned.Empty()) + { + /* + * check if the given statement is on a line of its own, immediately following << + * and then it. Eg: + * + * cout << + * "something"; + */ + Chunk *prev = pc->GetPrev(); + + if ( prev->IsNotNullChunk() + && prev->IsNewline()) + { + log_rule_B("indent_columns"); + indent_to_column(pc, pc->GetColumnIndent() + options::indent_columns()); + pc->SetColumnIndent(pc->GetColumn()); + pc->SetFlagBits(PCF_DONT_INDENT); + } + } + pc = pc->GetNext(); + } + as.End(); +} // align_left_shift diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_left_shift.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_left_shift.h new file mode 100644 index 00000000..d02155b0 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_left_shift.h @@ -0,0 +1,16 @@ +/** + * @file align_left_shift.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_LEFT_SHIFT_H_INCLUDED +#define ALIGN_LEFT_SHIFT_H_INCLUDED + +//! Align left shift operators '<<' (CT_SHIFT) +void align_left_shift(); + +#endif /* ALIGN_LEFT_SHIFT_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_log_al.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_log_al.cpp new file mode 100644 index 00000000..802b0280 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_log_al.cpp @@ -0,0 +1,31 @@ +/** + * @file align_log_al.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_log_al.h" + +#include "uncrustify.h" + + +void align_log_al(log_sev_t sev, size_t line) +{ + if (log_sev_on(sev)) + { + log_fmt(sev, "%s(%d): line %zu, cpd.al_cnt is %zu\n", + __func__, __LINE__, line, cpd.al_cnt); + + for (size_t idx = 0; idx < cpd.al_cnt; idx++) + { + log_fmt(sev, " cpd.al[%2.1zu].col is %2.1zu, cpd.al[%2.1zu].len is %zu, type is %s\n", + idx, cpd.al[idx].col, idx, cpd.al[idx].len, + get_token_name(cpd.al[idx].type)); + } + + log_fmt(sev, "\n"); + } +} // align_log_al diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_log_al.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_log_al.h new file mode 100644 index 00000000..8cb2ece8 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_log_al.h @@ -0,0 +1,17 @@ +/** + * @file align_log_al.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_LOG_AL_H_INCLUDED +#define ALIGN_LOG_AL_H_INCLUDED + +#include "uncrustify_types.h" + +void align_log_al(log_sev_t sev, size_t line); + +#endif /* ALIGN_LOG_AL_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_nl_cont.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_nl_cont.cpp new file mode 100644 index 00000000..8ff71508 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_nl_cont.cpp @@ -0,0 +1,64 @@ +/** + * @file align_nl_cont.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_nl_cont.h" + +#include "align_add.h" +#include "uncrustify.h" + + +Chunk *align_nl_cont(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LALNLC, "%s(%d): start on [%s] on line %zu\n", + __func__, __LINE__, get_token_name(start->GetType()), start->GetOrigLine()); + + // Find the max column + ChunkStack cs; + size_t max_col = 0; + Chunk *pc = start; + + while ( pc->IsNotNullChunk() + && pc->IsNot(CT_NEWLINE) + && pc->IsNot(CT_COMMENT_MULTI)) + { + if (pc->Is(CT_NL_CONT)) + { + align_add(cs, pc, max_col); + } + pc = pc->GetNext(); + } + // NL_CONT is always the last thing on a line + Chunk *tmp; + + while ((tmp = cs.Pop_Back()) != nullptr) + { + tmp->SetFlagBits(PCF_WAS_ALIGNED); + tmp->SetColumn(max_col); + } + return(pc); +} // align_nl_cont + + +void align_backslash_newline() +{ + LOG_FUNC_ENTRY(); + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + if (pc->IsNot(CT_NL_CONT)) + { + pc = pc->GetNextType(CT_NL_CONT); + continue; + } + pc = align_nl_cont(pc); + } +} // align_backslash_newline diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_nl_cont.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_nl_cont.h new file mode 100644 index 00000000..05a046ec --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_nl_cont.h @@ -0,0 +1,33 @@ +/** + * @file align_nl_cont.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_NL_COUNT_H_INCLUDED +#define ALIGN_NL_COUNT_H_INCLUDED + +#include "uncrustify_types.h" + +#include "chunk.h" + +/** + * For a series of lines ending in backslash-newline, align them. + * The series ends when a newline or multi-line C comment is encountered. + * + * @param start Start point + * + * @return pointer the last item looked at (nullptr/newline/comment) + */ +Chunk *align_nl_cont(Chunk *start); + +/** + * Aligns all backslash-newline combos in the file. + * This should be done LAST. + */ +void align_backslash_newline(); + +#endif /* ALIGN_NL_COUNT_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_decl_colon.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_decl_colon.cpp new file mode 100644 index 00000000..35b4b58e --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_decl_colon.cpp @@ -0,0 +1,90 @@ +/** + * @file align_oc_decl_colon.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_oc_decl_colon.h" + +#include "align_stack.h" +#include "chunk.h" + + +using namespace uncrustify; + + +void align_oc_decl_colon() +{ + LOG_FUNC_ENTRY(); + + bool did_line; + AlignStack cas; // for the colons + AlignStack nas; // for the parameter label + + cas.Start(4); + nas.Start(4); + nas.m_right_align = !options::align_on_tabstop(); + + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + if (pc->IsNot(CT_OC_SCOPE)) + { + pc = pc->GetNext(); + continue; + } + nas.Reset(); + cas.Reset(); + + size_t level = pc->GetLevel(); + pc = pc->GetNextNcNnl(E_Scope::PREPROC); + + did_line = false; + + while ( pc->IsNotNullChunk() + && pc->GetLevel() >= level) + { + // The declaration ends with an open brace or semicolon + if ( pc->Is(CT_BRACE_OPEN) + || pc->IsSemicolon()) + { + break; + } + + if (pc->IsNewline()) + { + nas.NewLines(pc->GetNlCount()); + cas.NewLines(pc->GetNlCount()); + did_line = false; + } + else if ( !did_line + && pc->Is(CT_OC_COLON)) + { + cas.Add(pc); + + Chunk *tmp = pc->GetPrev(E_Scope::PREPROC); + Chunk *tmp2 = tmp->GetPrevNcNnl(E_Scope::PREPROC); + + // Check for an un-labeled parameter + if ( ( tmp->Is(CT_WORD) + || tmp->Is(CT_TYPE) + || tmp->Is(CT_OC_MSG_DECL) + || tmp->Is(CT_OC_MSG_SPEC)) + && ( tmp2->Is(CT_WORD) + || tmp2->Is(CT_TYPE) + || tmp2->Is(CT_PAREN_CLOSE))) + { + nas.Add(tmp); + } + did_line = true; + } + pc = pc->GetNext(E_Scope::PREPROC); + } + nas.End(); + cas.End(); + } +} // align_oc_decl_colon diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_decl_colon.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_decl_colon.h new file mode 100644 index 00000000..b44b11ee --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_decl_colon.h @@ -0,0 +1,21 @@ +/** + * @file align_oc_decl_colon.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_OC_DECL_COLON_H_INCLUDED +#define ALIGN_OC_DECL_COLON_H_INCLUDED + + +/** + * Aligns OC declarations on the colon + * -(void) doSomething: (NSString*) param1 + * with: (NSString*) param2 + */ +void align_oc_decl_colon(); + +#endif /* ALIGN_OC_DECL_COLON_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_msg_colons.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_msg_colons.cpp new file mode 100644 index 00000000..ffb6a4eb --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_msg_colons.cpp @@ -0,0 +1,182 @@ +/** + * @file align_oc_msg_colons.cpp + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#include "align_oc_msg_colons.h" + +#include "align_stack.h" +#include "log_rules.h" + +constexpr static auto LCURRENT = LOCMSG; + +using namespace uncrustify; + + +void align_oc_msg_colon(Chunk *so) +{ + LOG_FUNC_ENTRY(); + + AlignStack nas; // for the parameter tag + + nas.Start(1); + nas.Reset(); + log_rule_B("align_on_tabstop"); + nas.m_right_align = !options::align_on_tabstop(); + + AlignStack cas; // for the colons + + log_rule_B("align_oc_msg_colon_span"); + size_t span = options::align_oc_msg_colon_span(); + + cas.Start(span); + + size_t level = so->GetLevel(); + Chunk *pc = so->GetNextNcNnl(E_Scope::PREPROC); + + bool did_line = false; + bool has_colon = false; + size_t lcnt = 0; // line count with no colon for span + bool first_line = true; + + while ( pc->IsNotNullChunk() + && pc->GetLevel() > level) + { + if (pc->GetLevel() > (level + 1)) + { + // do nothing + } + else if (pc->IsNewline()) + { + if (!has_colon) + { + ++lcnt; + } + did_line = false; + + log_rule_B("align_oc_msg_colon_xcode_like"); + + if ( options::align_oc_msg_colon_xcode_like() + && first_line + && !has_colon) + { + span = 0; + } + has_colon = !has_colon; + first_line = false; + } + else if ( !did_line + && (lcnt < span + 1) + && pc->Is(CT_OC_COLON)) + { + has_colon = true; + cas.Add(pc); + Chunk *tmp = pc->GetPrev(); + + if ( tmp->IsNotNullChunk() + && ( tmp->Is(CT_OC_MSG_FUNC) + || tmp->Is(CT_OC_MSG_NAME))) + { + nas.Add(tmp); + tmp->SetFlagBits(PCF_DONT_INDENT); + } + did_line = true; + } + pc = pc->GetNext(E_Scope::PREPROC); + } + log_rule_B("align_oc_msg_colon_first"); + nas.m_skip_first = !options::align_oc_msg_colon_first(); + cas.m_skip_first = !options::align_oc_msg_colon_first(); + + // find the longest args that isn't the first one + size_t first_len = 0; + size_t mlen = 0; + Chunk *longest = nullptr; + + size_t len = nas.m_aligned.Len(); + + for (size_t idx = 0; idx < len; idx++) + { + Chunk *tmp = nas.m_aligned.GetChunk(idx); + + if (tmp != nullptr) + { + size_t tlen = tmp->GetStr().size(); + + if (tlen > mlen) + { + mlen = tlen; + + if (idx != 0) + { + longest = tmp; + } + } + + if (idx == 0) + { + first_len = tlen + 1; + } + } + } + + // add spaces before the longest arg + log_rule_B("indent_oc_msg_colon"); + len = options::indent_oc_msg_colon(); + size_t len_diff = mlen - first_len; + + log_rule_B("indent_columns"); + size_t indent_size = options::indent_columns(); + + // Align with first colon if possible by removing spaces + log_rule_B("indent_oc_msg_prioritize_first_colon"); + + if ( longest != nullptr + && options::indent_oc_msg_prioritize_first_colon() + && len_diff > 0 + && ( (longest->GetColumn() >= len_diff) + && (longest->GetColumn() - len_diff) > (longest->GetBraceLevel() * indent_size))) + { + longest->SetColumn(longest->GetColumn() - len_diff); + } + else if ( longest != nullptr + && len > 0) + { + Chunk chunk; + + chunk.SetType(CT_SPACE); + chunk.SetParentType(CT_NONE); + chunk.SetOrigLine(longest->GetOrigLine()); + chunk.SetOrigCol(longest->GetOrigCol()); + chunk.SetLevel(longest->GetLevel()); + chunk.SetBraceLevel(longest->GetBraceLevel()); + chunk.SetFlags(longest->GetFlags() & PCF_COPY_FLAGS); + + // start at one since we already indent for the '[' + for (size_t idx = 1; idx < len; idx++) + { + chunk.Str().append(' '); + } + + chunk.CopyAndAddBefore(longest); + } + nas.End(); + cas.End(); +} // align_oc_msg_colon + + +void align_oc_msg_colons() +{ + LOG_FUNC_ENTRY(); + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if ( pc->Is(CT_SQUARE_OPEN) + && pc->GetParentType() == CT_OC_MSG) + { + align_oc_msg_colon(pc); + } + } +} // align_oc_msg_colons diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_msg_colons.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_msg_colons.h new file mode 100644 index 00000000..0bbb7b6b --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_msg_colons.h @@ -0,0 +1,16 @@ +/** + * @file align_oc_msg_colons.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_OC_MSG_COLONS_H_INCLUDED +#define ALIGN_OC_MSG_COLONS_H_INCLUDED + +//! Aligns OC messages +void align_oc_msg_colons(); + +#endif /* ALIGN_OC_MSG_COLONS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_msg_spec.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_msg_spec.cpp new file mode 100644 index 00000000..88671254 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_msg_spec.cpp @@ -0,0 +1,37 @@ +/** + * @file align_oc_msg_spec.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_oc_msg_spec.h" + +#include "align_assign.h" +#include "align_stack.h" + + +void align_oc_msg_spec(size_t span) +{ + LOG_FUNC_ENTRY(); + + AlignStack as; + + as.Start(span, 0); + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if (pc->IsNewline()) + { + as.NewLines(pc->GetNlCount()); + } + else if (pc->Is(CT_OC_MSG_SPEC)) + { + as.Add(pc); + } + } + + as.End(); +} // void align_oc_msg_spec diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_msg_spec.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_msg_spec.h new file mode 100644 index 00000000..b6500a6e --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_oc_msg_spec.h @@ -0,0 +1,18 @@ +/** + * @file align_oc_msg_spec.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_OC_MSG_SPEC_H_INCLUDED +#define ALIGN_OC_MSG_SPEC_H_INCLUDED + +#include "uncrustify_types.h" + +//! Aligns all function prototypes in the file. +void align_oc_msg_spec(size_t span); + +#endif /* ALIGN_OC_MSG_SPEC_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_preprocessor.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_preprocessor.cpp new file mode 100644 index 00000000..18a853ea --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_preprocessor.cpp @@ -0,0 +1,109 @@ +/** + * @file align_preprocessor.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_preprocessor.h" + +#include "align_stack.h" +#include "log_rules.h" + +constexpr static auto LCURRENT = LALPP; + +using namespace uncrustify; + + +void align_preprocessor() +{ + LOG_FUNC_ENTRY(); + + AlignStack as; // value macros + + log_rule_B("align_pp_define_span"); + as.Start(options::align_pp_define_span()); + log_rule_B("align_pp_define_gap"); + as.m_gap = options::align_pp_define_gap(); + AlignStack *cur_as = &as; + + AlignStack asf; // function macros + + log_rule_B("align_pp_define_span"); + asf.Start(options::align_pp_define_span()); + log_rule_B("align_pp_define_gap"); + asf.m_gap = options::align_pp_define_gap(); + + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + // Note: not counting back-slash newline combos + if (pc->Is(CT_NEWLINE)) // mind the gap: pc->IsNewline() is NOT the same! + { + as.NewLines(pc->GetNlCount()); + asf.NewLines(pc->GetNlCount()); + } + + // If we aren't on a 'define', then skip to the next non-comment + if (pc->IsNot(CT_PP_DEFINE)) + { + pc = pc->GetNextNc(); + continue; + } + // step past the 'define' + pc = pc->GetNextNc(); + + if (pc->IsNullChunk()) + { + // coveralls will complain here. There are no example for that. + // see https://en.wikipedia.org/wiki/Robustness_principle + break; + } + LOG_FMT(LALPP, "%s(%d): define (%s) on line %zu col %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + + cur_as = &as; + + if (pc->Is(CT_MACRO_FUNC)) + { + log_rule_B("align_pp_define_together"); + + if (!options::align_pp_define_together()) + { + cur_as = &asf; + } + // Skip to the close parenthesis + pc = pc->GetNextNc(); // point to open ( + pc = pc->GetNextType(CT_FPAREN_CLOSE, pc->GetLevel()); + + LOG_FMT(LALPP, "%s(%d): jumped to (%s) on line %zu col %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + } + // step to the value past the close parenthesis or the macro name + pc = pc->GetNext(); + + if (pc->IsNullChunk()) + { + // coveralls will complain here. There are no example for that. + // see https://en.wikipedia.org/wiki/Robustness_principle + break; + } + + /* + * don't align anything if the first line ends with a newline before + * a value is given + */ + if (!pc->IsNewline()) + { + LOG_FMT(LALPP, "%s(%d): align on '%s', line %zu col %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + + cur_as->Add(pc); + } + } + as.End(); + asf.End(); +} // align_preprocessor diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_preprocessor.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_preprocessor.h new file mode 100644 index 00000000..1095c94e --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_preprocessor.h @@ -0,0 +1,18 @@ +/** + * @file align_preprocessor.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_PREPROCESSOR_H_INCLUDED +#define ALIGN_PREPROCESSOR_H_INCLUDED + +#include "uncrustify_types.h" + +//! Scans the whole file for #defines. Aligns all within X lines of each other +void align_preprocessor(); + +#endif /* ALIGN_PREPROCESSOR_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_same_func_call_params.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_same_func_call_params.cpp new file mode 100644 index 00000000..6b17ab90 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_same_func_call_params.cpp @@ -0,0 +1,283 @@ +/** + * @file align_same_func_call_params.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_same_func_call_params.h" + +#include "align_stack.h" +#include "log_rules.h" + +constexpr static auto LCURRENT = LASFCP; + +using namespace uncrustify; + + +void align_same_func_call_params() +{ + LOG_FUNC_ENTRY(); + + Chunk *pc; + Chunk *align_root = Chunk::NullChunkPtr; + Chunk *align_cur = Chunk::NullChunkPtr; + size_t align_len = 0; + size_t span = 3; + size_t thresh; + Chunk *align_fcn; + unc_text align_fcn_name; + unc_text align_root_name; + deque<Chunk *> chunks; + deque<AlignStack> array_of_AlignStack; + AlignStack fcn_as; + const char *add_str; + + // Default span is 3 if align_same_func_call_params is true + log_rule_B("align_same_func_call_params_span"); + + if (options::align_same_func_call_params_span() > 0) + { + span = options::align_same_func_call_params_span(); + } + log_rule_B("align_same_func_call_params_thresh"); + thresh = options::align_same_func_call_params_thresh(); + + fcn_as.Start(span, thresh); + LOG_FMT(LAS, "%s(%d): (3): span is %zu, thresh is %zu\n", + __func__, __LINE__, span, thresh); + + for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if (pc->IsNewline()) + { + LOG_FMT(LAS, "%s(%d): orig line is %zu, <Newline>\n", __func__, __LINE__, pc->GetOrigLine()); + } + else + { + LOG_FMT(LAS, "%s(%d): orig line is %zu, orig col is %zu, pc->Text() '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + } + + if (pc->IsNot(CT_FUNC_CALL)) + { + if (pc->IsNewline()) + { + for (auto &as_v : array_of_AlignStack) + { + as_v.NewLines(pc->GetNlCount()); + } + + fcn_as.NewLines(pc->GetNlCount()); + } + else + { + // if we drop below the brace level that started it, we are done + if ( align_root->IsNotNullChunk() + && align_root->GetBraceLevel() > pc->GetBraceLevel()) + { + LOG_FMT(LASFCP, " ++ (drop) Ended with %zu fcns\n", align_len); + + // Flush it all! + fcn_as.Flush(); + + for (auto &as_v : array_of_AlignStack) + { + as_v.Flush(); + } + + align_root = Chunk::NullChunkPtr; + } + } + continue; + } + // Only align function calls that are right after a newline + Chunk *prev = pc->GetPrev(); + + while ( prev->Is(CT_MEMBER) + || prev->Is(CT_DC_MEMBER)) + { + Chunk *tprev = prev->GetPrev(); + + if (tprev->IsNot(CT_TYPE)) + { + prev = tprev; + break; + } + prev = tprev->GetPrev(); + } + + if (!prev->IsNewline()) + { + continue; + } + prev = prev->GetNext(); + align_fcn = prev; + align_fcn_name.clear(); + LOG_FMT(LASFCP, "%s(%d):\n", __func__, __LINE__); + + while (prev != pc) + { + align_fcn_name += prev->GetStr(); + prev = prev->GetNext(); + } + align_fcn_name += pc->GetStr(); + LOG_FMT(LASFCP, "%s(%d): Func Call found at orig line is %zu, orig col is %zu, c_str() '%s'\n", + __func__, __LINE__, align_fcn->GetOrigLine(), + align_fcn->GetOrigCol(), + align_fcn_name.c_str()); + + add_str = nullptr; + + if (align_root->IsNotNullChunk()) + { + // Issue # 1395 + // can only align functions on the same brace level + // and on the same level + LOG_FMT(LASFCP, "%s(%d):align_root is not nullptr\n", __func__, __LINE__); + + if ( align_root->GetBraceLevel() == pc->GetBraceLevel() + && align_root->GetLevel() == pc->GetLevel() + && align_fcn_name.equals(align_root_name)) + { + fcn_as.Add(pc); + align_cur->AlignmentData().next = pc; + align_cur = pc; + align_len++; + add_str = " Add"; + } + else + { + LOG_FMT(LASFCP, " ++ Ended with %zu fcns\n", align_len); + + // Flush it all! + fcn_as.Flush(); + + for (auto &as_v : array_of_AlignStack) + { + as_v.Flush(); + } + + align_root = Chunk::NullChunkPtr; + } + } + LOG_FMT(LASFCP, "%s(%d):\n", __func__, __LINE__); + + if (align_root->IsNullChunk()) + { + LOG_FMT(LASFCP, "%s(%d):align_root is null chunk, Add pc '%s'\n", __func__, __LINE__, pc->Text()); + fcn_as.Add(pc); + align_root = align_fcn; + align_root_name = align_fcn_name; + align_cur = pc; + align_len = 1; + add_str = "Start"; + } + LOG_FMT(LASFCP, "%s(%d):\n", __func__, __LINE__); + + if (add_str != nullptr) + { + LOG_FMT(LASFCP, "%s(%d): %s with function '%s', on orig line %zu, ", + __func__, __LINE__, add_str, align_fcn_name.c_str(), pc->GetOrigLine()); + align_params(pc, chunks); + LOG_FMT(LASFCP, "%zu items:", chunks.size()); + + for (size_t idx = 0; idx < chunks.size(); idx++) + { + // show the chunk(s) + LOG_FMT(LASFCP, " [%s]", chunks[idx]->Text()); + + if (idx < chunks.size() - 1) + { + LOG_FMT(LASFCP, ","); + } + } + + LOG_FMT(LASFCP, "\n"); + + for (size_t idx = 0; idx < chunks.size(); idx++) + { + LOG_FMT(LASFCP, "%s(%d): chunks[%zu] is [%s]\n", __func__, __LINE__, idx, chunks[idx]->Text()); + // Issue #2368 + + if (array_of_AlignStack.size() > idx) + { + // Issue #2368 + array_of_AlignStack[idx].m_right_align = false; + } + + if (idx >= array_of_AlignStack.size()) + { + LOG_FMT(LASFCP, "%s(%d): resize with %zu\n", __func__, __LINE__, idx + 1); + array_of_AlignStack.resize(idx + 1); + LOG_FMT(LASFCP, "%s(%d): Start for the new\n", __func__, __LINE__); + array_of_AlignStack[idx].Start(span, thresh); + + log_rule_B("align_number_right"); + + if (!options::align_number_right()) + { + if ( chunks[idx]->Is(CT_NUMBER_FP) + || chunks[idx]->Is(CT_NUMBER) + || chunks[idx]->Is(CT_POS) + || chunks[idx]->Is(CT_NEG)) + { + log_rule_B("align_on_tabstop"); + array_of_AlignStack[idx].m_right_align = !options::align_on_tabstop(); + } + } + } + LOG_FMT(LASFCP, "%s(%d): save the chunk %s\n", __func__, __LINE__, chunks[idx]->Text()); + array_of_AlignStack[idx].Add(chunks[idx]); + } + } + } + + if (align_len > 1) + { + LOG_FMT(LASFCP, " ++ Ended with %zu fcns\n", align_len); + fcn_as.End(); + + for (auto &as_v : array_of_AlignStack) + { + as_v.End(); + } + } +} // align_same_func_call_params + + +void align_params(Chunk *start, deque<Chunk *> &chunks) +{ + LOG_FUNC_ENTRY(); + + chunks.clear(); + + bool hit_comma = true; + Chunk *pc = start->GetNextType(CT_FPAREN_OPEN, start->GetLevel()); + + while ((pc = pc->GetNext())->IsNotNullChunk()) + { + if ( pc->IsNewline() + || pc->Is(CT_SEMICOLON) + || ( pc->Is(CT_FPAREN_CLOSE) + && pc->GetLevel() == start->GetLevel())) + { + break; + } + + if (pc->GetLevel() == (start->GetLevel() + 1)) + { + if (hit_comma) + { + chunks.push_back(pc); + hit_comma = false; + } + else if (pc->Is(CT_COMMA)) + { + hit_comma = true; + } + } + } +} // void align_params diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_same_func_call_params.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_same_func_call_params.h new file mode 100644 index 00000000..648d7174 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_same_func_call_params.h @@ -0,0 +1,22 @@ +/** + * @file align_same_func_call_params.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_SAME_FUNC_CALL_PARAMS_H_INCLUDED +#define ALIGN_SAME_FUNC_CALL_PARAMS_H_INCLUDED + +#include "ChunkStack.h" +#include <deque> + +using namespace std; + +void align_params(Chunk *start, deque<Chunk *> &chunks); + +void align_same_func_call_params(); + +#endif /* ALIGN_SAME_FUNC_CALL_PARAMS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_stack.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_stack.cpp new file mode 100644 index 00000000..4ed5da0a --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_stack.cpp @@ -0,0 +1,661 @@ +/** + * @file align_stack.cpp + * Manages an align stack, which is just a pair of chunk stacks. + * There can be at most 1 item per line in the stack. + * The seqnum is actually a line counter. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_stack.h" + +#include "align_tab_column.h" +#include "indent.h" +#include "space.h" +#include "unc_tools.h" // to get stackID and get_A_Number() + + +constexpr static auto LCURRENT = LAS; + +using namespace uncrustify; + +using std::numeric_limits; + + +void AlignStack::Start(size_t span, int thresh) +{ + stackID = get_A_Number(); // for debugging purpose only + + // produces much more log output. Use it only debugging purpose + //WITH_STACKID_DEBUG; + + //LOG_FMT(LAS, "AlignStack::Start(%d):m_aligned.Reset()\n", __LINE__); + m_aligned.Reset(); + //LOG_FMT(LAS, "AlignStack::Start(%d):m_skipped.Reset()\n", __LINE__); + m_skipped.Reset(); + + if (thresh > 0) + { + m_absolute_thresh = false; + m_thresh = thresh; + } + else + { + m_absolute_thresh = true; + m_thresh = -thresh; + } + m_span = span; + m_min_col = numeric_limits<size_t>::max(); + m_max_col = 0; + m_nl_seqnum = 0; + m_seqnum = 0; + m_gap = 0; + m_right_align = false; + m_star_style = SS_IGNORE; + m_amp_style = SS_IGNORE; +} + + +void AlignStack::ReAddSkipped() +{ + // produces much more log output. Use it only debugging purpose + //WITH_STACKID_DEBUG; + + if (m_skipped.Empty()) + { + return; + } + // Make a copy of the ChunkStack and clear m_skipped + m_scratch.Set(m_skipped); + //LOG_FMT(LAS, "AlignStack::ReAddSkipped(%d):m_skipped.Reset()\n", __LINE__); + m_skipped.Reset(); + + // Need to add them in order so that m_nl_seqnum is correct + for (size_t idx = 0; idx < m_scratch.Len(); idx++) + { + const ChunkStack::Entry *ce = m_scratch.Get(idx); + LOG_FMT(LAS, "AlignStack::ReAddSkipped [%zu] - ", ce->m_seqnum); + Add(ce->m_pc, ce->m_seqnum); + } + + NewLines(0); // Check to see if we need to flush right away +} + + +void AlignStack::Add(Chunk *start, size_t seqnum) +{ + // produces much more log output. Use it only debugging purpose + //WITH_STACKID_DEBUG; + LOG_FUNC_ENTRY(); + + LOG_FMT(LAS, "AlignStack::%s(%d): Candidate is '%s': orig line is %zu, column is %zu, type is %s, level is %zu\n", + __func__, __LINE__, start->Text(), start->GetOrigLine(), start->GetColumn(), get_token_name(start->GetType()), start->GetLevel()); + LOG_FMT(LAS, "AlignStack::%s(%d): seqnum is %zu\n", __func__, __LINE__, seqnum); + + // Assign a seqnum if needed + if (seqnum == 0) + { + LOG_FMT(LAS, "AlignStack::%s(%d): m_seqnum is %zu\n", __func__, __LINE__, m_seqnum); + seqnum = m_seqnum; + LOG_FMT(LAS, "AlignStack::%s(%d): seqnum is %zu\n", __func__, __LINE__, seqnum); + } + m_last_added = 0; + + // Threshold check should begin after + // tighten down the spacing between ref and start + + /* + * SS_IGNORE: no special handling of '*' or '&', only 'foo' is aligned + * void foo; // gap=5, 'foo' is aligned + * char * foo; // gap=3, 'foo' is aligned + * foomatic foo; // gap=1, 'foo' is aligned + * The gap is the columns between 'foo' and the previous token. + * [void - foo], ['*' - foo], etc + * + * SS_INCLUDE: - space between variable and '*' or '&' is eaten + * void foo; // gap=5, 'foo' is aligned + * char *foo; // gap=5, '*' is aligned + * foomatic foo; // gap=1, 'foo' is aligned + * The gap is the columns between the first '*' or '&' before foo + * and the previous token. [void - foo], [char - '*'], etc + * + * SS_DANGLE: - space between variable and '*' or '&' is eaten + * void foo; // gap=5 + * char *bar; // gap=5, as the '*' doesn't count + * foomatic foo; // gap=1 + * The gap is the columns between 'foo' and the chunk before the first + * '*' or '&'. [void - foo], [char - bar], etc + * + * If the gap < m_gap, then the column is bumped out by the difference. + * So, if m_gap is 2, then the above would be: + * SS_IGNORE: + * void foo; // gap=6 + * char * foo; // gap=4 + * foomatic foo; // gap=2 + * SS_INCLUDE: + * void foo; // gap=6 + * char *foo; // gap=6 + * foomatic foo; // gap=2 + * SS_DANGLE: + * void foo; // gap=6 + * char *bar; // gap=6, as the '*' doesn't count + * foomatic foo; // gap=2 + * Right aligned numbers: + * #define A -1 + * #define B 631 + * #define C 3 + * Left aligned numbers: + * #define A -1 + * #define B 631 + * #define C 3 + * + * In the code below, pc is set to the item that is aligned. + * In the above examples, that is 'foo', '*', '-', or 63. + * + * Ref is set to the last part of the type. + * In the above examples, that is 'void', 'char', 'foomatic', 'A', or 'B'. + * + * The '*' and '&' can float between the two. + * + * If align_on_tabstop=true, then SS_DANGLE is changed to SS_INCLUDE. + */ + log_rule_B("align_on_tabstop"); + + if ( options::align_on_tabstop() + && m_star_style == SS_DANGLE) + { + m_star_style = SS_INCLUDE; + } + LOG_FMT(LAS, "AlignStack::%s(%d): m_star_style is %s\n", + __func__, __LINE__, get_StarStyle_name(m_star_style)); + // Find ref. Back up to the real item that is aligned. + Chunk *prev = start; + + while ( (prev = prev->GetPrev())->IsNotNullChunk() + && ( prev->IsPointerOperator() + || prev->Is(CT_TPAREN_OPEN))) + { + // do nothing - we want prev when this exits + } + + if (prev->IsNullChunk()) + { + return; + } + Chunk *ref = prev; + + if (ref->IsNewline()) + { + ref = ref->GetNext(); + } + // Find the item that we are going to align. + Chunk *ali = Chunk::NullChunkPtr; + + if (start != nullptr) + { + ali = start; + } + + if (m_star_style != SS_IGNORE) + { + // back up to the first '*' or '^' preceding the token + Chunk *tmp_prev = ali->GetPrev(); + + while ( tmp_prev->IsStar() + || tmp_prev->IsMsRef()) + { + ali = tmp_prev; + tmp_prev = ali->GetPrev(); + } + + if (tmp_prev->Is(CT_TPAREN_OPEN)) + { + ali = tmp_prev; + tmp_prev = ali->GetPrev(); + // this is correct, even Coverity says: + // CID 76021 (#1 of 1): Unused value (UNUSED_VALUE)returned_pointer: Assigning value from + // ali->GetPrev(nav_e::ALL) to prev here, but that stored value is overwritten before it can be used. + } + } + + if (m_amp_style != SS_IGNORE) + { + // back up to the first '&' preceding the token + Chunk *tmp_prev = ali->GetPrev(); + + while (tmp_prev->IsAddress()) + { + ali = tmp_prev; + tmp_prev = ali->GetPrev(); + } + } + log_rule_B("align_keep_extra_space"); + + // Tighten down the spacing between ref and start + if (!options::align_keep_extra_space()) + { + size_t tmp_col = ref->GetColumn(); + Chunk *tmp = ref; + LOG_FMT(LAS, "AlignStack::%s(%d): tmp_col is %zu\n", + __func__, __LINE__, tmp_col); + + while ( tmp->IsNotNullChunk() + && tmp != start) + { + Chunk *next = tmp->GetNext(); + + if (next->IsNotNullChunk()) + { + LOG_FMT(LAS, "AlignStack::%s(%d): next orig line is %zu, orig col is %zu, Text() '%s', level is %zu, type is %s\n", + __func__, __LINE__, next->GetOrigLine(), next->GetOrigCol(), next->Text(), next->GetLevel(), get_token_name(next->GetType())); + tmp_col += space_col_align(tmp, next); + LOG_FMT(LAS, "AlignStack::%s(%d): next column is %zu, level is %zu, tmp_col is %zu\n", + __func__, __LINE__, next->GetColumn(), next->GetLevel(), tmp_col); + + if (next->GetColumn() != tmp_col) + { + LOG_FMT(LAS, "AlignStack::%s(%d): Call align_to_column\n", __func__, __LINE__); + align_to_column(next, tmp_col); + } + } + tmp = next; + } + } + + // Check threshold limits + if ( m_max_col == 0 + || m_thresh == 0 + || ( ((start->GetColumn() + m_gap) <= (m_thresh + (m_absolute_thresh ? m_min_col : m_max_col))) // don't use subtraction here to prevent underflow + && ( (start->GetColumn() + m_gap + m_thresh) >= m_max_col // change the expression to mind negative expression + || start->GetColumn() >= m_min_col))) + { + // we are adding it, so update the newline seqnum + if (seqnum > m_nl_seqnum) + { + m_nl_seqnum = seqnum; + } + // Set the column adjust and gap + size_t col_adj = 0; // Amount the column is shifted for 'dangle' mode + size_t gap = 0; + + if (ref != ali) + { + gap = ali->GetColumn() - (ref->GetColumn() + ref->Len()); + } + Chunk *tmp = ali; + + if (tmp->Is(CT_TPAREN_OPEN)) + { + tmp = tmp->GetNext(); + } + + if ( ( tmp->IsStar() + && m_star_style == SS_DANGLE) + || ( tmp->IsAddress() + && m_amp_style == SS_DANGLE) + || ( tmp->IsNullable() + && (m_star_style == SS_DANGLE)) + || ( tmp->IsMsRef() + && m_star_style == SS_DANGLE)) // TODO: add m_msref_style + { + col_adj = start->GetColumn() - ali->GetColumn(); + gap = start->GetColumn() - (ref->GetColumn() + ref->Len()); + } + // See if this pushes out the max_col + const size_t endcol = ali->GetColumn() + col_adj + + (gap < m_gap ? m_gap - gap : 0); + + ali->AlignmentData().col_adj = col_adj; + ali->AlignmentData().ref = ref; + ali->AlignmentData().start = start; + m_aligned.Push_Back(ali, seqnum); + m_last_added = 1; + + // Issue #2278 + if (ali->Is(CT_PTR_TYPE)) + { + LOG_FMT(LAS, "AlignStack::%s(%d): Add-[%s][%s]: ali orig line is %zu, column is %zu, type is %s, level is %zu\n", + __func__, __LINE__, ali->Text(), start->Text(), ali->GetOrigLine(), ali->GetColumn(), get_token_name(ali->GetType()), ali->GetLevel()); + } + else + { + LOG_FMT(LAS, "AlignStack::%s(%d): Add-[%s]: ali orig line is %zu, column is %zu, type is %s, level is %zu\n", + __func__, __LINE__, ali->Text(), ali->GetOrigLine(), ali->GetColumn(), get_token_name(ali->GetType()), ali->GetLevel()); + } + LOG_FMT(LAS, "AlignStack::%s(%d): ali alignment col_adj is %d, ref '%s', endcol is %zu\n", + __func__, __LINE__, ali->GetAlignmentData().col_adj, ref->Text(), endcol); + + if (m_min_col > endcol) + { + m_min_col = endcol; + } + + if (endcol > m_max_col) + { + LOG_FMT(LAS, "AlignStack::%s(%d): Add-aligned: seqnum is %zu, m_nl_seqnum is %zu, m_seqnum is %zu\n", + __func__, __LINE__, seqnum, m_nl_seqnum, m_seqnum); + LOG_FMT(LAS, "AlignStack::%s(%d): ali orig line is %zu, column is %zu, max_col old is %zu, new is %zu, m_min_col is %zu\n", + __func__, __LINE__, ali->GetOrigLine(), ali->GetColumn(), m_max_col, endcol, m_min_col); + m_max_col = endcol; + + /* + * If there were any entries that were skipped, re-add them as they + * may now be within the threshold + */ + if (!m_skipped.Empty()) + { + ReAddSkipped(); + } + } + else + { + LOG_FMT(LAS, "AlignStack::%s(%d): Add-aligned: seqnum is %zu, m_nl_seqnum is %zu, m_seqnum is %zu\n", + __func__, __LINE__, seqnum, m_nl_seqnum, m_seqnum); + LOG_FMT(LAS, "AlignStack::%s(%d): ali orig line is %zu, column is %zu, max_col old is %zu, new is %zu, m_min_col is %zu\n", + __func__, __LINE__, ali->GetOrigLine(), ali->GetColumn(), m_max_col, endcol, m_min_col); + } + } + else + { + // The threshold check failed, so add it to the skipped list + m_skipped.Push_Back(start, seqnum); + m_last_added = 2; + + LOG_FMT(LAS, "AlignStack::Add-skipped [%zu/%zu/%zu]: line %zu, col %zu <= %zu + %zu\n", + seqnum, m_nl_seqnum, m_seqnum, + start->GetOrigLine(), start->GetColumn(), m_max_col, m_thresh); + } + // produces much more log output. Use it only debugging purpose + //WITH_STACKID_DEBUG; +} // AlignStack::Add + + +void AlignStack::NewLines(size_t cnt) +{ + // produces much more log output. Use it only debugging purpose + //WITH_STACKID_DEBUG; + + if (m_aligned.Empty()) + { + //LOG_FMT(LAS, "AlignStack::Newlines(%d): nothing to do, is empty\n", __LINE__); + return; + } + LOG_FMT(LAS, "AlignStack::Newlines(%d): cnt is %zu\n", __LINE__, cnt); + m_seqnum += cnt; + LOG_FMT(LAS, "AlignStack::Newlines(%d): m_seqnum is %zu, m_nl_seqnum is %zu, m_span is %zu\n", + __LINE__, m_seqnum, m_nl_seqnum, m_span); + + if (m_seqnum > (m_nl_seqnum + m_span)) + { + LOG_FMT(LAS, "AlignStack::Newlines(%d): cnt is %zu\n", __LINE__, cnt); + Flush(); + } +} + + +void AlignStack::Flush() +{ + // produces much more log output. Use it only debugging purpose + //WITH_STACKID_DEBUG; + + LOG_FMT(LAS, "AlignStack::%s(%d): Len() is %zu\n", + __func__, __LINE__, Len()); + + if (Len() > 0) + { + LOG_FMT(LAS, " (min is %zu, max is %zu)\n", + m_min_col, m_max_col); + } + + if (Len() == 1) + { + // check if we have *one* typedef in the line + Chunk *pc = m_aligned.Get(0)->m_pc; + Chunk *temp = pc->GetPrevType(CT_TYPEDEF, pc->GetLevel()); + + if (temp->IsNotNullChunk()) + { + if (pc->GetOrigLine() == temp->GetOrigLine()) + { + // reset the gap only for *this* stack + m_gap = 1; + } + } + } + m_last_added = 0; + m_max_col = 0; + + // produces much more log output. Use it only debugging purpose + //WITH_STACKID_DEBUG; + LOG_FMT(LAS, "AlignStack::%s(%d): Debug the stack, Len is %zu\n", + __func__, __LINE__, Len()); + + for (size_t idx = 0; idx < Len(); idx++) + { + Chunk *pc = m_aligned.Get(idx)->m_pc; + LOG_FMT(LAS, "AlignStack::%s(%d): idx is %zu, pc->Text() is '%s', pc alignment col_adj is %d\n", + __func__, __LINE__, idx, pc->Text(), pc->GetAlignmentData().col_adj); + } + + // Recalculate the max_col - it may have shifted since the last Add() + for (size_t idx = 0; idx < Len(); idx++) + { + Chunk *pc = m_aligned.Get(idx)->m_pc; + + // Set the column adjust and gap + size_t col_adj = 0; + size_t gap = 0; + + if (pc != pc->GetAlignmentData().ref) + { + gap = pc->GetColumn() - (pc->GetAlignmentData().ref->GetColumn() + pc->GetAlignmentData().ref->Len()); + } + + if (m_star_style == SS_DANGLE) + { + Chunk *tmp = (pc->Is(CT_TPAREN_OPEN)) ? pc->GetNext() : pc; + + if (tmp->IsPointerOperator()) + { + col_adj = pc->GetAlignmentData().start->GetColumn() - pc->GetColumn(); + gap = pc->GetAlignmentData().start->GetColumn() - (pc->GetAlignmentData().ref->GetColumn() + pc->GetAlignmentData().ref->Len()); + } + } + + if (m_right_align) + { + // Adjust the width for signed numbers + if (pc->GetAlignmentData().start != nullptr) + { + size_t start_len = pc->GetAlignmentData().start->Len(); + + if (pc->GetAlignmentData().start->GetType() == CT_NEG) + { + Chunk *next = pc->GetAlignmentData().start->GetNext(); + + if (next->Is(CT_NUMBER)) + { + start_len += next->Len(); + } + } + col_adj += start_len; + } + } + pc->AlignmentData().col_adj = col_adj; + + // See if this pushes out the max_col + const size_t endcol = pc->GetColumn() + col_adj + + (gap < m_gap ? m_gap - gap : 0); + + if (endcol > m_max_col) + { + m_max_col = endcol; + } + } + + log_rule_B("align_on_tabstop"); + + if ( options::align_on_tabstop() + && Len() > 1) + { + m_max_col = align_tab_column(m_max_col); + } + LOG_FMT(LAS, "AlignStack::%s(%d): Len() is %zu\n", + __func__, __LINE__, Len()); + + const ChunkStack::Entry *ce = nullptr; + + for (size_t idx = 0; idx < Len(); idx++) + { + ce = m_aligned.Get(idx); + LOG_FMT(LAS, "AlignStack::%s(%d): idx is %zu, ce->m_pc->Text() is '%s', orig line is %zu, orig col is %zu, alignment col_adj is %d\n", + __func__, __LINE__, idx, ce->m_pc->Text(), ce->m_pc->GetOrigLine(), ce->m_pc->GetOrigCol(), ce->m_pc->GetAlignmentData().col_adj); + } + + for (size_t idx = 0; idx < Len(); idx++) + { + ce = m_aligned.Get(idx); + Chunk *pc = ce->m_pc; + + const size_t tmp_col = m_max_col - pc->GetAlignmentData().col_adj; + + if (idx == 0) + { + if ( m_skip_first + && pc->GetColumn() != tmp_col) + { + LOG_FMT(LAS, "AlignStack::%s(%d): orig line is %zu, orig col is %zu, dropping first item due to skip_first\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + m_skip_first = false; + m_aligned.Pop_Front(); + Flush(); + m_skip_first = true; + return; + } + pc->SetFlagBits(PCF_ALIGN_START); + + pc->AlignmentData().right_align = m_right_align; + pc->AlignmentData().amp_style = m_amp_style; + pc->AlignmentData().star_style = m_star_style; + } + pc->AlignmentData().gap = m_gap; + pc->AlignmentData().next = m_aligned.GetChunk(idx + 1); + + // Indent the token, taking col_adj into account + LOG_FMT(LAS, "AlignStack::%s(%d): orig line is %zu, orig col is %zu, Text() '%s', set to col %zu (adj is %d)\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), tmp_col, pc->GetAlignmentData().col_adj); + align_to_column(pc, tmp_col); + } + + size_t last_seqnum = 0; + + if (ce != nullptr) + { + last_seqnum = ce->m_seqnum; + //LOG_FMT(LAS, "AlignStack::Flush(%d):m_aligned.Reset()\n", __LINE__); + m_aligned.Reset(); + } + m_min_col = numeric_limits<size_t>::max(); // use unrealistic high numbers + m_max_col = 0; // as start value + + if (m_skipped.Empty()) + { + // Nothing was skipped, sync the sequence numbers + m_nl_seqnum = m_seqnum; + } + else + { + // Remove all items with seqnum < last_seqnum + for (size_t idx = 0; idx < m_skipped.Len(); idx++) + { + if (m_skipped.Get(idx)->m_seqnum < last_seqnum) + { + m_skipped.Zap(idx); + } + } + + m_skipped.Collapse(); + + ReAddSkipped(); // Add all items from the skipped list + } +} // AlignStack::Flush + + +void AlignStack::Reset() +{ + //WITH_STACKID_DEBUG; + //LOG_FMT(LAS, "AlignStack::Reset(%d):m_aligned.Reset()\n", __LINE__); + m_aligned.Reset(); + //LOG_FMT(LAS, "AlignStack::Reset(%d):m_skipped.Reset()\n", __LINE__); + m_skipped.Reset(); +} + + +void AlignStack::End() +{ + //WITH_STACKID_DEBUG; + + if (!m_aligned.Empty()) + { + //LOG_FMT(LAS, "AlignStack::End(%d):\n", __LINE__); + Flush(); + } + //LOG_FMT(LAS, "AlignStack::End(%d):m_aligned.Reset()\n", __LINE__); + m_aligned.Reset(); + //LOG_FMT(LAS, "AlignStack::End(%d):m_skipped.Reset()\n", __LINE__); + m_skipped.Reset(); +} + + +size_t AlignStack::Len() +{ + return(m_aligned.Len()); +} + + +void AlignStack::Debug() +{ + //WITH_STACKID_DEBUG; + + size_t length = Len(); + + if (length > 0) + { + LOG_FMT(LAS, "AlignStack::%s(%d): Debug the stack, Len is %zu\n", + __func__, __LINE__, Len()); + + for (size_t idx = 0; idx < length; idx++) + { + Chunk *pc = m_aligned.Get(idx)->m_pc; + + if (pc->Is(CT_PTR_TYPE)) + { + LOG_FMT(LAS, "AlignStack::%s(%d): idx is %zu, [%s][%s]: orig line is %zu, orig col is %zu, type is %s, level is %zu, brace level is %zu\n", + __func__, __LINE__, idx, pc->Text(), pc->GetNext()->Text(), pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType()), pc->GetLevel(), pc->GetBraceLevel()); + } + else + { + LOG_FMT(LAS, "AlignStack::%s(%d): idx is %zu, [%s]: orig line is %zu, orig col is %zu, type is %s, level is %zu, brace level is %zu\n", + __func__, __LINE__, idx, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType()), pc->GetLevel(), pc->GetBraceLevel()); + } + } + } +} + + +const char *AlignStack::get_StarStyle_name(StarStyle star_style) +{ + switch (star_style) + { + case StarStyle::SS_IGNORE: + return("SS_IGNORE"); + + case StarStyle::SS_INCLUDE: + return("SS_INCLUDE"); + + case StarStyle::SS_DANGLE: + return("SS_DANGLE"); + } + return("?????"); +} // get_StarStyle_name diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_stack.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_stack.h new file mode 100644 index 00000000..6d079fe5 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_stack.h @@ -0,0 +1,154 @@ +/** + * @file align_stack.h + * Manages an align stack, which is just a pair of chunk stacks with a few + * fancy functions. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_STACK_H_INCLUDED +#define ALIGN_STACK_H_INCLUDED + +#include "ChunkStack.h" + +#include <limits> + +class AlignStack +{ +public: + enum StarStyle + { + SS_IGNORE, //! don't look for prev stars + SS_INCLUDE, //! include prev * before add + SS_DANGLE //! include prev * after add + }; + + ChunkStack m_aligned; //! contains the tokens that are aligned + ChunkStack m_skipped; //! contains the tokens sent to Add() + size_t m_max_col; + size_t m_min_col; + size_t m_span; + size_t m_thresh; + size_t m_seqnum; + size_t m_nl_seqnum; + size_t m_gap; + bool m_right_align; + bool m_absolute_thresh; + StarStyle m_star_style; + StarStyle m_amp_style; + bool m_skip_first; //! do not include the first item if it causes it to be indented + size_t stackID; //! for debugging purposes only + + + AlignStack() + : m_max_col(0) + , m_min_col(0) + , m_span(0) + , m_thresh(0) + , m_seqnum(0) + , m_nl_seqnum(0) + , m_gap(0) + , m_right_align(false) + , m_absolute_thresh(false) + , m_star_style(SS_IGNORE) + , m_amp_style(SS_IGNORE) + , m_skip_first(false) + , stackID(std::numeric_limits<std::size_t>::max()) // under linux 64 bits: 18446744073709551615 + , m_last_added(0) + { + } + + + AlignStack(const AlignStack &ref) + : m_aligned(ref.m_aligned) + , m_skipped(ref.m_skipped) + , m_max_col(ref.m_max_col) + , m_min_col(ref.m_min_col) + , m_span(ref.m_span) + , m_thresh(ref.m_thresh) + , m_seqnum(ref.m_seqnum) + , m_nl_seqnum(ref.m_nl_seqnum) + , m_gap(ref.m_gap) + , m_right_align(ref.m_right_align) + , m_absolute_thresh(ref.m_absolute_thresh) + , m_star_style(ref.m_star_style) + , m_amp_style(ref.m_amp_style) + , m_skip_first(ref.m_skip_first) + , m_last_added(ref.m_last_added) + { + } + + + ~AlignStack() + { + } + + /** + * Resets the two ChunkLists and zeroes local vars. + * + * @param span The row span limit + * @param threshold The column threshold + */ + void Start(size_t span, int threshold = 0); + + + /** + * Adds an entry to the appropriate stack. + * + * @param pc the chunk + * @param seqnum optional sequence number (0=assign one) + */ + void Add(Chunk *pc, size_t seqnum = 0); + + + //! Adds some newline and calls Flush() if needed + void NewLines(size_t cnt); + + + /** + * Aligns all the stuff in m_aligned. + * Re-adds 'newer' items in m_skipped. + */ + void Flush(); + + + //! Resets the stack, discarding anything that was previously added + void Reset(); + + + //! Aligns everything else and resets the lists. + void End(); + + + //! the size of the lists. + size_t Len(); + + + //! for debugging purpose only + void Debug(); + + + const char *get_StarStyle_name(StarStyle star_style); + +protected: + size_t m_last_added; //! 0=none, 1=aligned, 2=skipped + ChunkStack m_scratch; //! used in ReAddSkipped() + + //! Calls Add on all the skipped items + void ReAddSkipped(); +}; + +#define WITH_STACKID_DEBUG \ + if (stackID == std::numeric_limits<std::size_t>::max()) \ + { \ + fprintf(stderr, "AlignStack::%s(%d): the stack is not ready, Start is missed\n", __func__, __LINE__); \ + log_flush(true); \ + exit(EX_SOFTWARE); \ + } \ + else \ + { \ + LOG_FMT(LAS, "AlignStack::%s(%d): stackID is %zu\n", __func__, __LINE__, stackID); \ + } + +#endif /* ALIGN_STACK_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_struct_initializers.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_struct_initializers.cpp new file mode 100644 index 00000000..ca032bc3 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_struct_initializers.cpp @@ -0,0 +1,34 @@ +/** + * @file align_struct_initializers.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_struct_initializers.h" + +#include "align_init_brace.h" +#include "chunk.h" + + +void align_struct_initializers() +{ + LOG_FUNC_ENTRY(); + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + Chunk *prev = pc->GetPrevNcNnl(); + + if ( prev->Is(CT_ASSIGN) + && ( pc->Is(CT_BRACE_OPEN) + || ( language_is_set(LANG_D) + && pc->Is(CT_SQUARE_OPEN)))) + { + align_init_brace(pc); + } + pc = pc->GetNextType(CT_BRACE_OPEN); + } +} // align_struct_initializers diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_struct_initializers.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_struct_initializers.h new file mode 100644 index 00000000..7310d072 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_struct_initializers.h @@ -0,0 +1,18 @@ +/** + * @file align_struct_initializers.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_STRUCT_INITIALIZERS_H_INCLUDED +#define ALIGN_STRUCT_INITIALIZERS_H_INCLUDED + +#include "uncrustify_types.h" + +//! Aligns stuff inside a multi-line "= { ... }" sequence. +void align_struct_initializers(); + +#endif /* ALIGN_STRUCT_INITIALIZERS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_tab_column.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_tab_column.cpp new file mode 100644 index 00000000..8d91b0ff --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_tab_column.cpp @@ -0,0 +1,39 @@ +/** + * @file align_tab_column.cpp + * + * @author Guy Maurel + * split from prototypes.h + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_tab_column.h" + +#include "prototypes.h" + +constexpr static auto LCURRENT = LALIGN; + +using namespace uncrustify; + + +/** + * Advances to the next tab stop if not currently on one. + * + * @param col The current column + * @return the next tabstop column + */ +size_t align_tab_column(size_t col) +{ + //if (col <= 0) + if (col == 0) + { + col = 1; + } + log_rule_B("output_tab_size"); + + if ((col % uncrustify::options::output_tab_size()) != 1) + { + col = next_tab_column(col); + } + return(col); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_tab_column.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_tab_column.h new file mode 100644 index 00000000..9e57baa0 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_tab_column.h @@ -0,0 +1,23 @@ +/** + * @file align_tab_column.h + * + * @author Guy Maurel + * split from prototypes.h + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_TAB_COLUMN_H_INCLUDED +#define ALIGN_TAB_COLUMN_H_INCLUDED + +#include "uncrustify_types.h" + +/** + * Advances to the next tab stop if not currently on one. + * + * @param col The current column + * @return the next tabstop column + */ +size_t align_tab_column(size_t col); + +#endif /* ALIGN_TAB_COLUMN_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_tools.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_tools.cpp new file mode 100644 index 00000000..2a3bbc09 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_tools.cpp @@ -0,0 +1,197 @@ +/** + * @file align_tools.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_tools.h" + +#include "space.h" +#include "uncrustify.h" + + +Chunk *skip_c99_array(Chunk *sq_open) +{ + if (sq_open->Is(CT_SQUARE_OPEN)) + { + Chunk *tmp = sq_open->GetClosingParen()->GetNextNc(); + + if (tmp->Is(CT_ASSIGN)) + { + return(tmp->GetNextNc()); + } + } + return(nullptr); +} // skip_c99_array + + +Chunk *scan_ib_line(Chunk *start) +{ + LOG_FUNC_ENTRY(); + Chunk *prev_match = nullptr; + size_t idx = 0; + + // Skip past C99 "[xx] =" stuff + Chunk *tmp = skip_c99_array(start); + + if (tmp != nullptr) + { + start->SetParentType(CT_TSQUARE); + start = tmp; + cpd.al_c99_array = true; + } + Chunk *pc = start; + + if (pc != nullptr) + { + LOG_FMT(LSIB, "%s(%d): start: orig line is %zu, orig col is %zu, column is %zu, type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->GetColumn(), get_token_name(pc->GetType())); + } + else + { + pc = Chunk::NullChunkPtr; + } + + while ( pc->IsNotNullChunk() + && !pc->IsNewline() + && pc->GetLevel() >= start->GetLevel()) + { + //LOG_FMT(LSIB, "%s: '%s' col %d/%d line %zu\n", __func__, + // pc->Text(), pc->GetColumn(), pc->GetOrigCol(), pc->GetOrigLine()); + + Chunk *next = pc->GetNext(); + + if ( next->IsNullChunk() + || next->IsComment()) + { + // do nothing + } + else if ( pc->Is(CT_ASSIGN) + || pc->Is(CT_BRACE_OPEN) + || pc->Is(CT_BRACE_CLOSE) + || pc->Is(CT_COMMA)) + { + size_t token_width = space_col_align(pc, next); + + // TODO: need to handle missing structure defs? ie NULL vs { ... } ?? + + // Is this a new entry? + if (idx >= cpd.al_cnt) + { + if (idx == 0) + { + LOG_FMT(LSIB, "%s(%d): Prepare the 'idx's\n", __func__, __LINE__); + } + LOG_FMT(LSIB, "%s(%d): New idx is %2.1zu, pc->GetColumn() is %2.1zu, Text() '%s', token_width is %zu, type is %s\n", + __func__, __LINE__, idx, pc->GetColumn(), pc->Text(), token_width, get_token_name(pc->GetType())); + cpd.al[cpd.al_cnt].type = pc->GetType(); + cpd.al[cpd.al_cnt].col = pc->GetColumn(); + cpd.al[cpd.al_cnt].len = token_width; + cpd.al[cpd.al_cnt].ref = pc; // Issue #3786 + cpd.al_cnt++; + + if (cpd.al_cnt == uncrustify::limits::AL_SIZE) + { + fprintf(stderr, "Number of 'entry' to be aligned is too big for the current value %d,\n", + uncrustify::limits::AL_SIZE); + fprintf(stderr, "at line %zu, column %zu.\n", + pc->GetOrigLine(), pc->GetOrigCol()); + fprintf(stderr, "Please make a report.\n"); + log_flush(true); + exit(EX_SOFTWARE); + } + idx++; + } + else + { + // expect to match stuff + if (cpd.al[idx].type == pc->GetType()) + { + LOG_FMT(LSIB, "%s(%d): Match? idx is %2.1zu, orig line is %2.1zu, column is %2.1zu, token_width is %zu, type is %s\n", + __func__, __LINE__, idx, pc->GetOrigLine(), pc->GetColumn(), token_width, get_token_name(pc->GetType())); + + // Shift out based on column + if (prev_match == nullptr) + { + if (pc->GetColumn() > cpd.al[idx].col) + { + LOG_FMT(LSIB, "%s(%d): [ pc column (%zu) > cpd.al[%zu].col(%zu) ] \n", + __func__, __LINE__, pc->GetColumn(), idx, cpd.al[idx].col); + + ib_shift_out(idx, pc->GetColumn() - cpd.al[idx].col); + cpd.al[idx].col = pc->GetColumn(); + } + } + else if (idx > 0) + { + LOG_FMT(LSIB, "%s(%d): prev_match '%s', orig line is %zu, orig col is %zu\n", + __func__, __LINE__, prev_match->Text(), prev_match->GetOrigLine(), prev_match->GetOrigCol()); + int min_col_diff = pc->GetColumn() - prev_match->GetColumn(); + int cur_col_diff = cpd.al[idx].col - cpd.al[idx - 1].col; + + if (cur_col_diff < min_col_diff) + { + LOG_FMT(LSIB, "%s(%d): pc orig line is %zu\n", + __func__, __LINE__, pc->GetOrigLine()); + ib_shift_out(idx, min_col_diff - cur_col_diff); + } + } + LOG_FMT(LSIB, "%s(%d): at ende of the loop: now is col %zu, len is %zu\n", + __func__, __LINE__, cpd.al[idx].col, cpd.al[idx].len); + idx++; + } + } + prev_match = pc; + } + pc = pc->GetNextNc(); + } + return(pc); +} // scan_ib_line + + +void ib_shift_out(size_t idx, size_t num) +{ + while (idx < cpd.al_cnt) + { + bool is_empty = false; // Issue #3786 + Chunk *tmp = cpd.al[idx].ref; + + if (tmp->Is(CT_BRACE_CLOSE)) + { + Chunk *pre = tmp->GetPrev(); + + if (pre->Is(CT_COMMA)) + { + is_empty = true; + } + } + + if (!is_empty) + { + cpd.al[idx].col += num; + } + idx++; + } +} // ib_shift_out + + +Chunk *step_back_over_member(Chunk *pc) +{ + if (pc == nullptr) + { + pc = Chunk::NullChunkPtr; + } + Chunk *tmp = pc->GetPrevNcNnl(); + + // Skip over any class stuff: bool CFoo::bar() + while ( tmp->IsNotNullChunk() + && tmp->Is(CT_DC_MEMBER)) + { + pc = tmp->GetPrevNcNnl(); + tmp = pc->GetPrevNcNnl(); + } + return(pc); +} // step_back_over_member diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_tools.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_tools.h new file mode 100644 index 00000000..6153ba34 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_tools.h @@ -0,0 +1,48 @@ +/** + * @file align_tools.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_TOOLS_H_INCLUDED +#define ALIGN_TOOLS_H_INCLUDED + +#include "chunk.h" +#include "uncrustify_types.h" + + +/** + * @brief return the chunk the follows after a C array + * + * The provided chunk is considered an array if it is an opening square + * (CT_SQUARE_OPEN) and the matching close is followed by an equal sign '=' + * + * Example: array[25] = 12; + * /|\ /|\ + * | | + * provided chunk has to point to [ | + * returned chunk points to 12 + * + * @param chunk chunk to operate on + * + * @return the chunk after the '=' if the check succeeds + * @return nullptr in all other cases + */ +Chunk *skip_c99_array(Chunk *sq_open); + +/** + * Scans a line for stuff to align on. + * + * We trigger on BRACE_OPEN, FPAREN_OPEN, ASSIGN, and COMMA. + * We want to align the NEXT item. + */ +Chunk *scan_ib_line(Chunk *start); + +void ib_shift_out(size_t idx, size_t num); + +Chunk *step_back_over_member(Chunk *pc); + +#endif /* ALIGN_TOOLS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_trailing_comments.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_trailing_comments.cpp new file mode 100644 index 00000000..777c3dee --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_trailing_comments.cpp @@ -0,0 +1,235 @@ +/** + * @file align_trailing_comments.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_trailing_comments.h" + +#include "align_add.h" +#include "align_tab_column.h" +#include "indent.h" +#include "log_rules.h" + +constexpr static auto LCURRENT = LALTC; + +using namespace uncrustify; + + +void align_stack(ChunkStack &cs, size_t col, bool align_single, log_sev_t sev) +{ + LOG_FUNC_ENTRY(); + + log_rule_B("align_on_tabstop"); + + if (options::align_on_tabstop()) + { + col = align_tab_column(col); + } + + if ( (cs.Len() > 1) + || ( align_single + && (cs.Len() == 1))) + { + LOG_FMT(sev, "%s(%d): max_col=%zu\n", __func__, __LINE__, col); + Chunk *pc; + + while ((pc = cs.Pop_Back()) != nullptr) + { + align_to_column(pc, col); + pc->SetFlagBits(PCF_WAS_ALIGNED); + + LOG_FMT(sev, "%s(%d): indented [%s] on line %zu to %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetColumn()); + } + } + cs.Reset(); +} // align_stack + + +Chunk *align_trailing_comments(Chunk *start) +{ + LOG_FUNC_ENTRY(); + size_t min_col = 0; + size_t min_orig = 0; + Chunk *pc = start; + const size_t lvl = start->GetBraceLevel(); + size_t nl_count = 0; + ChunkStack cs; + size_t col; + + log_rule_B("align_right_cmt_at_col"); + size_t intended_col = options::align_right_cmt_at_col(); + + log_rule_B("align_right_cmt_same_level"); + const bool same_level = options::align_right_cmt_same_level(); + comment_align_e cmt_type_cur; + comment_align_e cmt_type_start = get_comment_align_type(pc); + + LOG_FMT(LALADD, "%s(%d): start on line=%zu\n", + __func__, __LINE__, pc->GetOrigLine()); + + // Find the max column + log_rule_B("align_right_cmt_span"); + + while ( pc->IsNotNullChunk() + && (nl_count < options::align_right_cmt_span())) + { + if ( pc->TestFlags(PCF_RIGHT_COMMENT) + && pc->GetColumn() > 1) + { + if ( same_level + && pc->GetBraceLevel() != lvl) + { + pc = pc->GetPrev(); + break; + } + cmt_type_cur = get_comment_align_type(pc); + + if (cmt_type_cur == cmt_type_start) + { + LOG_FMT(LALADD, "%s(%d): line=%zu min_col=%zu pc->col=%zu pc->len=%zu %s\n", + __func__, __LINE__, pc->GetOrigLine(), min_col, pc->GetColumn(), pc->Len(), + get_token_name(pc->GetType())); + + if ( min_orig == 0 + || min_orig > pc->GetColumn()) + { + min_orig = pc->GetColumn(); + } + align_add(cs, pc, min_col); // (intended_col < col)); + nl_count = 0; + } + } + + if (pc->IsNewline()) + { + nl_count += pc->GetNlCount(); + } + pc = pc->GetNext(); + } + // Start with the minimum original column + col = min_orig; + + // fall back to the intended column + if ( intended_col > 0 + && col > intended_col) + { + col = intended_col; + } + + // if less than allowed, bump it out + if (col < min_col) + { + col = min_col; + } + + // bump out to the intended column + if (col < intended_col) + { + col = intended_col; + } + LOG_FMT(LALADD, "%s(%d): -- min_orig=%zu intended_col=%zu min_allowed=%zu ==> col=%zu\n", + __func__, __LINE__, min_orig, intended_col, min_col, col); + + if ( cpd.frag_cols > 0 + && cpd.frag_cols <= col) + { + col -= cpd.frag_cols; + } + align_stack(cs, col, (intended_col != 0), LALTC); + + return(pc->GetNext()); +} // align_trailing_comments + + +comment_align_e get_comment_align_type(Chunk *cmt) +{ + Chunk *prev; + comment_align_e cmt_type = comment_align_e::REGULAR; + + log_rule_B("align_right_cmt_mix"); + + if ( !options::align_right_cmt_mix() + && cmt != nullptr + && ((prev = cmt->GetPrev())->IsNotNullChunk())) + { + if ( prev->Is(CT_PP_ENDIF) + || prev->Is(CT_PP_ELSE) + || prev->Is(CT_ELSE) + || prev->Is(CT_BRACE_CLOSE)) + { + // TODO: make the magic 3 configurable + if ((cmt->GetColumn() - (prev->GetColumn() + prev->Len())) < 3) + { + cmt_type = (prev->Is(CT_PP_ENDIF)) ? comment_align_e::ENDIF : comment_align_e::BRACE; + } + } + } + return(cmt_type); +} // get_comment_align_type + + +void align_right_comments() +{ + LOG_FUNC_ENTRY(); + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if ( pc->Is(CT_COMMENT) + || pc->Is(CT_COMMENT_CPP) + || pc->Is(CT_COMMENT_MULTI)) + { + if (pc->GetParentType() == CT_COMMENT_END) + { + log_rule_B("align_right_cmt_gap"); + + if (pc->GetOrigPrevSp() < options::align_right_cmt_gap()) + { + LOG_FMT(LALTC, "NOT changing END comment on line %zu (%zu < %u)\n", + pc->GetOrigLine(), pc->GetOrigPrevSp(), + options::align_right_cmt_gap()); + } + else + { + LOG_FMT(LALTC, "Changing END comment on line %zu into a RIGHT-comment\n", + pc->GetOrigLine()); + pc->SetFlagBits(PCF_RIGHT_COMMENT); + } + } + + // Change certain WHOLE comments into RIGHT-alignable comments + if (pc->GetParentType() == CT_COMMENT_WHOLE) + { + log_rule_B("input_tab_size"); + size_t max_col = pc->GetColumnIndent() + options::input_tab_size(); + + // If the comment is further right than the brace level... + if (pc->GetColumn() >= max_col) + { + LOG_FMT(LALTC, "Changing WHOLE comment on line %zu into a RIGHT-comment (col=%zu col_ind=%zu max_col=%zu)\n", + pc->GetOrigLine(), pc->GetColumn(), pc->GetColumnIndent(), max_col); + + pc->SetFlagBits(PCF_RIGHT_COMMENT); + } + } + } + } + + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + if (pc->TestFlags(PCF_RIGHT_COMMENT)) + { + pc = align_trailing_comments(pc); + } + else + { + pc = pc->GetNext(); + } + } +} // align_right_comments diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_trailing_comments.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_trailing_comments.h new file mode 100644 index 00000000..4fec7b8b --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_trailing_comments.h @@ -0,0 +1,46 @@ +/** + * @file align_trailing_comments.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_TRAILING_COMMENTS_H_INCLUDED +#define ALIGN_TRAILING_COMMENTS_H_INCLUDED + +#include "chunk.h" +#include "ChunkStack.h" + +enum class comment_align_e : unsigned int +{ + REGULAR, + BRACE, + ENDIF, +}; + +/** + * For a series of lines ending in a comment, align them. + * The series ends when more than align_right_cmt_span newlines are found. + * + * Interesting info: + * - least physically allowed column + * - intended column + * - least original cmt column + * + * min_col is the minimum allowed column (based on prev token col/size) + * cmt_col less than + * + * @param start Start point + * @return pointer the last item looked at + */ +Chunk *align_trailing_comments(Chunk *start); + +comment_align_e get_comment_align_type(Chunk *cmt); + +void align_stack(ChunkStack &cs, size_t col, bool align_single, log_sev_t sev); + +void align_right_comments(); + +#endif /* ALIGN_TRAILING_COMMENTS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_typedefs.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_typedefs.cpp new file mode 100644 index 00000000..b97d9ddf --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_typedefs.cpp @@ -0,0 +1,65 @@ +/** + * @file align_typedefs.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_typedefs.h" + +#include "align_stack.h" +#include "log_rules.h" + +constexpr static auto LCURRENT = LALTD; + +using namespace uncrustify; + + +void align_typedefs(size_t span) +{ + LOG_FUNC_ENTRY(); + + AlignStack as; + + as.Start(span); + log_rule_B("align_typedef_gap"); + as.m_gap = options::align_typedef_gap(); + log_rule_B("align_typedef_star_style"); + as.m_star_style = static_cast<AlignStack::StarStyle>(options::align_typedef_star_style()); + log_rule_B("align_typedef_amp_style"); + as.m_amp_style = static_cast<AlignStack::StarStyle>(options::align_typedef_amp_style()); + + Chunk *c_typedef = Chunk::NullChunkPtr; + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + if (pc->IsNewline()) + { + as.NewLines(pc->GetNlCount()); + c_typedef = Chunk::NullChunkPtr; + } + else if (c_typedef->IsNotNullChunk()) + { + if (pc->TestFlags(PCF_ANCHOR)) + { + as.Add(pc); + LOG_FMT(LALTD, "%s(%d): typedef @ %zu:%zu, tag '%s' @ %zu:%zu\n", + __func__, __LINE__, c_typedef->GetOrigLine(), c_typedef->GetOrigCol(), + pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + c_typedef = Chunk::NullChunkPtr; + } + } + else + { + if (pc->Is(CT_TYPEDEF)) + { + c_typedef = pc; + } + } + pc = pc->GetNext(); + } + as.End(); +} // align_typedefs diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_typedefs.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_typedefs.h new file mode 100644 index 00000000..2902d0d2 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_typedefs.h @@ -0,0 +1,25 @@ +/** + * @file align_typedefs.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_TYPEDEFS_H_INCLUDED +#define ALIGN_TYPEDEFS_H_INCLUDED + +#include "uncrustify_types.h" + +/** + * Aligns simple typedefs that are contained on a single line each. + * This should be called after the typedef target is marked as a type. + * + * typedef int foo_t; + * typedef char bar_t; + * typedef const char cc_t; + */ +void align_typedefs(size_t span); + +#endif /* ALIGN_TYPEDEFS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_var_def_brace.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_var_def_brace.cpp new file mode 100644 index 00000000..a8cc2563 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_var_def_brace.cpp @@ -0,0 +1,362 @@ +/** + * @file align_var_def_brace.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "align_var_def_brace.h" + +#include "align_stack.h" +#include "align_tools.h" +#include "log_rules.h" + +constexpr static auto LCURRENT = LAVDB; + +using namespace uncrustify; + + +Chunk *align_var_def_brace(Chunk *start, size_t span, size_t *p_nl_count) +{ + LOG_FUNC_ENTRY(); + + if (start->IsNullChunk()) + { + return(nullptr); + } + Chunk *next; + size_t myspan = span; + size_t mythresh = 0; + size_t mygap = 0; + + // Override the span, if this is a struct/union + if ( start->GetParentType() == CT_STRUCT + || start->GetParentType() == CT_UNION) + { + log_rule_B("align_var_struct_span"); + myspan = options::align_var_struct_span(); + log_rule_B("align_var_struct_thresh"); + mythresh = options::align_var_struct_thresh(); + log_rule_B("align_var_struct_gap"); + mygap = options::align_var_struct_gap(); + } + else if (start->GetParentType() == CT_CLASS) + { + log_rule_B("align_var_class_span"); + myspan = options::align_var_class_span(); + log_rule_B("align_var_class_thresh"); + mythresh = options::align_var_class_thresh(); + log_rule_B("align_var_class_gap"); + mygap = options::align_var_class_gap(); + } + else + { + log_rule_B("align_var_def_thresh"); + mythresh = options::align_var_def_thresh(); + log_rule_B("align_var_def_gap"); + mygap = options::align_var_def_gap(); + } + // can't be any variable definitions in a "= {" block + Chunk *prev = start->GetPrevNcNnl(); + + if (prev->Is(CT_ASSIGN)) + { + LOG_FMT(LAVDB, "%s(%d): start->Text() '%s', type is %s, on orig line %zu (abort due to assign)\n", + __func__, __LINE__, start->Text(), get_token_name(start->GetType()), start->GetOrigLine()); + + Chunk *pc = start->GetNextType(CT_BRACE_CLOSE, start->GetLevel()); + return(pc->GetNextNcNnl()); + } + char copy[1000]; + + LOG_FMT(LAVDB, "%s(%d): start->Text() '%s', type is %s, on orig line %zu\n", + __func__, __LINE__, start->ElidedText(copy), get_token_name(start->GetType()), start->GetOrigLine()); + + log_rule_B("align_var_def_inline"); + auto const align_mask = + PCF_IN_FCN_DEF | PCF_VAR_1ST | + (options::align_var_def_inline() ? PCF_NONE : PCF_VAR_INLINE); + + // Set up the variable/prototype/definition aligner + AlignStack as; + + as.Start(myspan, mythresh); + as.m_gap = mygap; + log_rule_B("align_var_def_star_style"); + as.m_star_style = static_cast<AlignStack::StarStyle>(options::align_var_def_star_style()); + log_rule_B("align_var_def_amp_style"); + as.m_amp_style = static_cast<AlignStack::StarStyle>(options::align_var_def_amp_style()); + + // Set up the bit colon aligner + AlignStack as_bc; + + as_bc.Start(myspan, 0); + log_rule_B("align_var_def_colon_gap"); + as_bc.m_gap = options::align_var_def_colon_gap(); + + AlignStack as_at; // attribute + + as_at.Start(myspan, 0); + + // Set up the brace open aligner + AlignStack as_br; + + as_br.Start(myspan, mythresh); + log_rule_B("align_single_line_brace_gap"); + as_br.m_gap = options::align_single_line_brace_gap(); + + bool fp_look_bro = false; + bool did_this_line = false; + + log_rule_B("align_mix_var_proto"); + bool fp_active = options::align_mix_var_proto(); + Chunk *pc = start->GetNext(); + LOG_FMT(LAVDB, "%s(%d): start->Text() is '%s', level is %zu, brace level is %zu\n", + __func__, __LINE__, start->IsNewline() ? "Newline" : start->Text(), start->GetLevel(), start->GetBraceLevel()); + + while (pc->IsNotNullChunk()) + { + LOG_CHUNK(LAVDB, pc); + + if ( pc->GetLevel() < start->GetLevel() + && pc->GetLevel() != 0 + && !pc->IsPreproc()) + { + LOG_FMT(LAVDB, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s, PRE is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()), pc->IsPreproc() ? "true" : "false"); + break; + } + + if (pc->IsComment()) + { + if (pc->GetNlCount() > 0) + { + as.NewLines(pc->GetNlCount()); + as_bc.NewLines(pc->GetNlCount()); + as_at.NewLines(pc->GetNlCount()); + as_br.NewLines(pc->GetNlCount()); + } + pc = pc->GetNext(); + LOG_FMT(LAVDB, "%s(%d): pc->Text() is '%s', level is %zu, brace level is %zu\n", + __func__, __LINE__, pc->IsNewline() ? "Newline" : pc->Text(), pc->GetLevel(), pc->GetBraceLevel()); + continue; + } + + if ( fp_active + && !pc->TestFlags(PCF_IN_CLASS_BASE)) + { + // WARNING: Duplicate from the align_func_proto() + log_rule_B("align_single_line_func"); + + if ( pc->Is(CT_FUNC_PROTO) + || ( pc->Is(CT_FUNC_DEF) + && options::align_single_line_func())) + { + LOG_FMT(LAVDB, "%s(%d): add = '%s', orig line is %zu, orig col is %zu, level is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol(), pc->GetLevel()); + + Chunk *toadd; + + log_rule_B("align_on_operator"); + + if ( pc->GetParentType() == CT_OPERATOR + && options::align_on_operator()) + { + toadd = pc->GetPrevNcNnl(); + } + else + { + toadd = pc; + } + as.Add(step_back_over_member(toadd)); + log_rule_B("align_single_line_brace"); + fp_look_bro = (pc->Is(CT_FUNC_DEF)) + && options::align_single_line_brace(); + } + else if ( fp_look_bro + && pc->Is(CT_BRACE_OPEN) + && pc->TestFlags(PCF_ONE_LINER)) + { + as_br.Add(pc); + fp_look_bro = false; + } + } + + // process nested braces + if (pc->Is(CT_BRACE_OPEN)) + { + size_t sub_nl_count = 0; + + pc = align_var_def_brace(pc, span, &sub_nl_count); + + if (sub_nl_count > 0) + { + fp_look_bro = false; + did_this_line = false; + as.NewLines(sub_nl_count); + as_bc.NewLines(sub_nl_count); + as_at.NewLines(sub_nl_count); + as_br.NewLines(sub_nl_count); + + if (p_nl_count != nullptr) + { + *p_nl_count += sub_nl_count; + } + } + continue; + } + + // Done with this brace set? + if (pc->Is(CT_BRACE_CLOSE)) + { + pc = pc->GetNext(); + LOG_FMT(LAVDB, "%s(%d): pc->Text() is '%s', level is %zu, brace level is %zu\n", + __func__, __LINE__, pc->IsNewline() ? "Newline" : pc->Text(), pc->GetLevel(), pc->GetBraceLevel()); + break; + } + + if (pc->IsNewline()) + { + fp_look_bro = false; + did_this_line = false; + as.NewLines(pc->GetNlCount()); + as_bc.NewLines(pc->GetNlCount()); + as_at.NewLines(pc->GetNlCount()); + as_br.NewLines(pc->GetNlCount()); + + if (p_nl_count != nullptr) + { + *p_nl_count += pc->GetNlCount(); + } + } + LOG_FMT(LAVDB, "%s(%d): pc->Text() is '%s', level is %zu, brace level is %zu\n", + __func__, __LINE__, pc->IsNewline() ? "Newline" : pc->Text(), pc->GetLevel(), pc->GetBraceLevel()); + + if (!pc->IsNewline()) + { + LOG_FMT(LAVDB, "%s(%d): pc orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + + if (pc->IsNot(CT_IGNORED)) + { + LOG_FMT(LAVDB, " "); + log_pcf_flags(LAVDB, pc->GetFlags()); + } + } + + // don't align stuff inside parenthesis/squares/angles + if (pc->GetLevel() > pc->GetBraceLevel()) + { + pc = pc->GetNext(); + LOG_FMT(LAVDB, "%s(%d): pc->Text() is '%s', level is %zu, brace level is %zu\n", + __func__, __LINE__, pc->IsNewline() ? "Newline" : pc->Text(), pc->GetLevel(), pc->GetBraceLevel()); + continue; + } + + // If this is a variable def, update the max_col + if ( !pc->TestFlags(PCF_IN_CLASS_BASE) + && pc->IsNot(CT_FUNC_CLASS_DEF) + && pc->IsNot(CT_FUNC_CLASS_PROTO) + && ((pc->GetFlags() & align_mask) == PCF_VAR_1ST) + && pc->IsNot(CT_FUNC_DEF) // Issue 1452 + && ( (pc->GetLevel() == (start->GetLevel() + 1)) + || pc->GetLevel() == 0) + && pc->GetPrev()->IsNot(CT_MEMBER)) + { + LOG_FMT(LAVDB, "%s(%d): a-did_this_line is %s\n", + __func__, __LINE__, did_this_line ? "TRUE" : "FALSE"); + LOG_FMT(LAVDB, "%s(%d): Text() is '%s', orig line is %zu, orig col is %zu, level is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol(), pc->GetLevel()); + + if (!did_this_line) + { + if ( start->GetParentType() == CT_STRUCT + && (as.m_star_style == AlignStack::SS_INCLUDE)) + { + // we must look after the previous token + Chunk *prev_local = pc->GetPrev(); + + while ( prev_local->Is(CT_PTR_TYPE) + || prev_local->Is(CT_ADDR)) + { + LOG_FMT(LAVDB, "%s(%d): prev_local '%s', prev_local->GetType() %s\n", + __func__, __LINE__, prev_local->Text(), get_token_name(prev_local->GetType())); + prev_local = prev_local->GetPrev(); + } + pc = prev_local->GetNext(); + LOG_FMT(LAVDB, "%s(%d): pc->Text() is '%s', level is %zu, brace level is %zu\n", + __func__, __LINE__, pc->IsNewline() ? "Newline" : pc->Text(), pc->GetLevel(), pc->GetBraceLevel()); + } + // we must look after the previous token + Chunk *prev_local = pc->GetPrev(); + + if (prev_local->IsNot(CT_DEREF)) // Issue #2971 + { + LOG_FMT(LAVDB, "%s(%d): add = '%s', orig line is %zu, orig col is %zu, level is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol(), pc->GetLevel()); + + as.Add(step_back_over_member(pc)); + } + log_rule_B("align_var_def_colon"); + + if (options::align_var_def_colon()) + { + next = pc->GetNextNc(); + LOG_FMT(LAVDB, "%s(%d): pc->Text() is '%s', level is %zu, brace level is %zu\n", + __func__, __LINE__, pc->IsNewline() ? "Newline" : pc->Text(), pc->GetLevel(), pc->GetBraceLevel()); + + if (next->Is(CT_BIT_COLON)) + { + as_bc.Add(next); + } + } + log_rule_B("align_var_def_attribute"); + + if (options::align_var_def_attribute()) + { + next = pc; + + while ((next = next->GetNextNc())->IsNotNullChunk()) + { + if (next->Is(CT_ATTRIBUTE)) + { + as_at.Add(next); + break; + } + + if ( next->Is(CT_SEMICOLON) + || next->IsNewline()) + { + break; + } + } + } + } + did_this_line = true; + } + else if (pc->Is(CT_BIT_COLON)) + { + if (!did_this_line) + { + as_bc.Add(pc); + did_this_line = true; + } + } + else + { + LOG_FMT(LAVDB, "%s(%d): b-did_this_line is %s\n", + __func__, __LINE__, did_this_line ? "TRUE" : "FALSE"); + } + pc = pc->GetNext(); + LOG_FMT(LAVDB, "%s(%d): pc->Text() is '%s', level is %zu, brace level is %zu\n", + __func__, __LINE__, pc->IsNewline() ? "Newline" : pc->Text(), pc->GetLevel(), pc->GetBraceLevel()); + } + as.End(); + as_bc.End(); + as_at.End(); + as_br.End(); + + return(pc); +} // align_var_def_brace diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_var_def_brace.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_var_def_brace.h new file mode 100644 index 00000000..6d06adf9 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/align_var_def_brace.h @@ -0,0 +1,22 @@ +/** + * @file align_var_def_brace.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef ALIGN_VAR_DEF_BRACE_H_INCLUDED +#define ALIGN_VAR_DEF_BRACE_H_INCLUDED + +#include "chunk.h" + +/** + * Scan everything at the current level until the close brace and find the + * variable def align column. Also aligns bit-colons, but that assumes that + * bit-types are the same! But that should always be the case... + */ +Chunk *align_var_def_brace(Chunk *pc, size_t span, size_t *nl_count); + +#endif /* ALIGN_VAR_DEF_BRACE_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/args.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/args.cpp new file mode 100644 index 00000000..a03bbe00 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/args.cpp @@ -0,0 +1,228 @@ +/** + * @file args.cpp + * Parses command line arguments. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "args.h" + +#include "unc_ctype.h" + +#include <cstring> + +Args::Args(int argc, char **argv) +{ + m_count = argc; + m_values = argv; + size_t len = (argc >> 3) + 1; + + m_used = new UINT8[len]; + + if (m_used != nullptr) + { + memset(m_used, 0, len); + } +} + + +Args::~Args() +{ + if (m_used != nullptr) + { + delete[] m_used; + m_used = nullptr; + } + m_count = 0; +} + + +bool Args::Present(const char *token) +{ + if (token != nullptr) + { + for (size_t idx = 0; idx < m_count; idx++) + { + if (strcmp(token, m_values[idx]) == 0) + { + SetUsed(idx); + return(true); + } + } + } + return(false); +} + + +const char *Args::Param(const char *token) +{ + size_t idx = 0; + + return(Params(token, idx)); +} + + +const char *Args::Params(const char *token, size_t &index) +{ + if (token == nullptr) + { + // coveralls will complain + // can only occur with a call such as: arg.Param(nullptr) + return(nullptr); + } + size_t token_len = strlen(token); + + for (size_t idx = index; idx < m_count; idx++) + { + size_t arg_len = strlen(m_values[idx]); + + if ( arg_len >= token_len + && (memcmp(token, m_values[idx], token_len) == 0)) + { + SetUsed(idx); + + if (arg_len > token_len) + { + if (m_values[idx][token_len] == '=') + { + token_len++; + } + index = idx + 1; + return(&m_values[idx][token_len]); + } + idx++; + index = idx + 1; + + if (idx < m_count) + { + SetUsed(idx); + return(m_values[idx]); + } + return(nullptr); + } + } + + return(nullptr); +} // Args::Params + + +bool Args::GetUsed(size_t idx) +{ + if ( m_used != nullptr + && idx > 0 + && idx < m_count) + { + return((m_used[idx >> 3] & (1 << (idx & 0x07))) != 0); + } + return(false); +} + + +void Args::SetUsed(size_t idx) +{ + if ( m_used != nullptr + && idx > 0 + && idx < m_count) + { + m_used[idx >> 3] |= (1 << (idx & 0x07)); + } +} + + +const char *Args::Unused(size_t &index) +{ + if (m_used == nullptr) + { + return(nullptr); + } + + for (size_t idx = index; idx < m_count; idx++) + { + if (!GetUsed(idx)) + { + index = idx + 1; + return(m_values[idx]); + } + } + + index = m_count; + return(nullptr); +} + + +size_t Args::SplitLine(char *text, char *args[], size_t num_args) +{ + if ( text == nullptr + || num_args == 0) + { + return(0); + } + char cur_quote = 0; + bool in_backslash = false; + bool in_arg = false; + size_t argc = 0; + char *dest = text; + + while ( argc <= num_args // maximal number of arguments not reached yet + && *text != 0) // end of string not reached yet + { + // Detect the start of an arg + if ( !in_arg + && !unc_isspace(*text)) + { + in_arg = true; + args[argc] = dest; + argc++; + } + + if (in_arg) + { + if (in_backslash) + { + in_backslash = false; + *dest = *text; + dest++; + } + else if (*text == '\\') + { + in_backslash = true; + } + else if (*text == cur_quote) + { + cur_quote = 0; + } + else if ( (*text == '\'') + || (*text == '"') + || (*text == '`')) + { + cur_quote = *text; + } + else if (cur_quote != 0) + { + *dest = *text; + dest++; + } + else if (unc_isspace(*text)) + { + *dest = 0; + dest++; + in_arg = false; + + if (argc == num_args) + { + break; // all arguments found, we can stop + } + } + else + { + *dest = *text; + dest++; + } + } + text++; // go on with next character + } + *dest = 0; + + return(argc); +} // Args::SplitLine diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/args.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/args.h new file mode 100644 index 00000000..712fbd59 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/args.h @@ -0,0 +1,122 @@ +/** + * @file args.h + * Parses command line arguments. + * + * This differs from the GNU/getopt way in that: + * - parameters cannot mixed "-e -f" is not the same as "-ef" + * - knowledge of the complete set of parameters is not required + * - this means you can handle args in multiple spots + * - it is more portable + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef ARGS_H_INCLUDED +#define ARGS_H_INCLUDED + +#include "base_types.h" + +class Args +{ +protected: + size_t m_count; //! number of command line arguments + char **m_values; //! pointer array to each argument + UINT8 *m_used; //! bit array with one flag per argument + +public: + /** + * Initializes the argument library. + * Store the values and allocates enough memory for the 'used' flags. + * This keeps a reference to argv, so don't change it. + * + * @param argc number of command line parameter passed to main() + * @param argv pointer array to command line parameters + */ + Args(int argc, char **argv); + + //! Standard destructor + ~Args(); + + /** + * Checks to see if an arg w/o a value is present. + * Scans the args looking for an exact match. + * + * "-c" matches "-c", but not "-call" or "-ec" + * + * @param token The token string to match + * + * @return true/false -- Whether the argument was present + */ + bool Present(const char *token); + + /** + * Calls Args::Params() with index 0 + * + * @param token The token string to match + * + * @return nullptr or the pointer to the string + */ + const char *Param(const char *token); + + /** + * Check for an arg with a value. + * Returns only the first match. + * + * Assuming the token "-c"... + * "-call" returns "all" + * "-c=all" returns "all" + * "-c", "all" returns "all" + * "-c=", "all" returns "" + * + * @param token the token string to match + * @param[in, out] index search start position, in case that something is + * found, it will get the succeeding position number + * assigned + * + * @return nullptr or the pointer to the string + */ + const char *Params(const char *token, size_t &index); + + /** + * Marks an argument as being used. + * + * @param idx The index of the argument + */ + void SetUsed(size_t idx); + + /** + * Gets whether an argument has been used, by index. + * + * @param idx The index of the argument + */ + bool GetUsed(size_t idx); + + /** + * This function retrieves all unused parameters. + * You must set the index before the first call. + * Set the index to 1 to skip argv[0]. + * + * @param idx Pointer to the index + * + * @return nullptr (done) or the pointer to the string + */ + const char *Unused(size_t &idx); + + /** + * Takes text and splits it into arguments. + * args is an array of char pointers that will get populated. + * num_args is the maximum number of args split off. + * If there are more than num_args, the remaining text is ignored. + * Note that text is modified (zeroes are inserted) + * + * @param text the text to split (modified) + * @param[out] args array of pointers to be populated + * @param num_args number of items in input string + * + * @return The number of arguments parsed (always <= num_args) + */ + static size_t SplitLine(char *text, char *args[], size_t num_args); +}; + + +#endif /* ARGS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/backup.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/backup.cpp new file mode 100644 index 00000000..93a19c6a --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/backup.cpp @@ -0,0 +1,164 @@ +/** + * @file backup.cpp + * Make a backup of a source file + * The current plans are to use two files. + * + * - A '.unc-backup~' file that contains the original contents + * - A '.unc-backup-md5~' file that contains the MD5 over the last output + * that uncrustify generated + * + * The logic goes like this: + * 1. If there isn't a .backup-md5 or the md5 over the input file doesn't + * match what is in .backup-md5, then copy the source file to .backup. + * + * 2. Create the output file. + * + * 3. Calculate the md5 over the output file. + * Create the .backup-md5 file. + * + * This will let you run uncrustify multiple times over the same file without + * losing the original file. If you edit the file, then a new backup is made. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "prototypes.h" + +#include "backup.h" +#include "md5.h" +#include "unc_ctype.h" + +#include <cerrno> + +using namespace std; + + +int backup_copy_file(const char *filename, const vector<UINT8> &data) +{ + char newpath[1024]; + char md5_str_in[33]; + char md5_str[34]; + UINT8 dig[16]; + + md5_str_in[0] = 0; + + MD5::Calc(data.data(), data.size(), dig); + snprintf(md5_str, sizeof(md5_str), + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + dig[0], dig[1], dig[2], dig[3], + dig[4], dig[5], dig[6], dig[7], + dig[8], dig[9], dig[10], dig[11], + dig[12], dig[13], dig[14], dig[15]); + + // Create the backup-md5 filename, open it and read the md5 + snprintf(newpath, sizeof(newpath), "%s%s", filename, UNC_BACKUP_MD5_SUFFIX); + + FILE *thefile = fopen(newpath, "rb"); + + if (thefile != nullptr) + { + char buffer[128]; + + if (fgets(buffer, sizeof(buffer), thefile) != nullptr) + { + for (int i = 0; buffer[i] != 0; i++) + { + if (unc_isxdigit(buffer[i])) + { + md5_str_in[i] = unc_tolower(buffer[i]); + } + else + { + md5_str_in[i] = 0; + break; + } + } + } + fclose(thefile); + } + + // if the MD5s match, then there is no need to back up the file + if (memcmp(md5_str, md5_str_in, 32) == 0) + { + LOG_FMT(LNOTE, "%s: MD5 match for %s\n", __func__, filename); + return(EX_OK); + } + LOG_FMT(LNOTE, "%s: MD5 mismatch - backing up %s\n", __func__, filename); + + // Create the backup file + snprintf(newpath, sizeof(newpath), "%s%s", filename, UNC_BACKUP_SUFFIX); + + thefile = fopen(newpath, "wb"); + + if (thefile != nullptr) + { + size_t retval = fwrite(data.data(), data.size(), 1, thefile); + int my_errno = errno; + + fclose(thefile); + + if ( retval == 1 + || data.empty()) + { + return(EX_OK); + } + LOG_FMT(LERR, "fwrite(%s) failed: %s (%d)\n", + newpath, strerror(my_errno), my_errno); + exit(EX_SOFTWARE); + } + else + { + LOG_FMT(LERR, "fopen(%s) failed: %s (%d)\n", + newpath, strerror(errno), errno); + exit(EX_SOFTWARE); + } + return(EX_IOERR); +} // backup_copy_file + + +void backup_create_md5_file(const char *filename) +{ + UINT8 dig[16]; + MD5 md5; + FILE *thefile; + UINT8 buf[4096]; + size_t len; + char newpath[1024]; + + md5.Init(); + + thefile = fopen(filename, "rb"); + + if (thefile == nullptr) + { + LOG_FMT(LERR, "%s: fopen(%s) failed: %s (%d)\n", + __func__, filename, strerror(errno), errno); + exit(EX_SOFTWARE); + } + + // read file chunk by chunk and calculate its MD5 checksum + while ((len = fread(buf, 1, sizeof(buf), thefile)) > 0) + { + md5.Update(buf, len); + } + fclose(thefile); + md5.Final(dig); + + snprintf(newpath, sizeof(newpath), "%s%s", filename, UNC_BACKUP_MD5_SUFFIX); + + thefile = fopen(newpath, "wb"); + + if (thefile != nullptr) + { + fprintf(thefile, + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %s\n", + dig[0], dig[1], dig[2], dig[3], + dig[4], dig[5], dig[6], dig[7], + dig[8], dig[9], dig[10], dig[11], + dig[12], dig[13], dig[14], dig[15], + path_basename(filename)); + + fclose(thefile); + } +} // backup_create_md5_file diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/backup.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/backup.h new file mode 100644 index 00000000..0d385649 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/backup.h @@ -0,0 +1,66 @@ +/** + * @file backup.h + * Handles backing up file data. + * + * It works like this: + * + * 1. Read in the file data + * + * 2. Call backup_copy_file() to create a backup of the input, if needed + * + * 3. Do the uncrustify magic and write the output file + * + * 4. Call backup_create_md5_file() + * + * This will let you run uncrustify multiple times over the same file without + * losing the original file. If you edit the file, then a new backup is made. + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef BACKUP_H_INCLUDED +#define BACKUP_H_INCLUDED + +#include "base_types.h" +#include <vector> + +#define UNC_BACKUP_SUFFIX ".unc-backup~" +#define UNC_BACKUP_MD5_SUFFIX ".unc-backup.md5~" + + +/** + * @brief Check the backup-md5 file and copy the input file to a backup if needed. + * + * If there isn't a FILENAME+UNC_BACKUP_MD5_SUFFIX or the md5 over the data + * doesn't match what is in FILENAME+UNC_BACKUP_MD5_SUFFIX, then write the + * data to FILENAME+UNC_BACKUP_SUFFIX. + * + * Note that if this fails, we shouldn't overwrite to original file with the + * output. + * + * @param filename The file that was read (full path) + * @param file_data The file data + * @param file_len The file length + * + * @retval EX_OK successfully created backup file + * @retval EX_IOERR could not create backup file + */ +int backup_copy_file(const char *filename, const std::vector<UINT8> &data); + + +/** + * This calculates the MD5 over the file and writes the MD5 to + * FILENAME+UNC_BACKUP_MD5_SUFFIX.* + * This should be called after the file was written to disk. + * We really don't care if it fails, as the MD5 just prevents us from backing + * up a file that uncrustify created. + * + * This should be called after the file was written to disk. + * It will be read back and an md5 will be calculated over it. + * + * @param filename The file that was written (full path) + */ +void backup_create_md5_file(const char *filename); + + +#endif /* BACKUP_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/base_types.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/base_types.h new file mode 100644 index 00000000..1e98b0ac --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/base_types.h @@ -0,0 +1,53 @@ +/** + * @file base_types.h + * + * Defines some base types, includes config.h + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef BASE_TYPES_H_INCLUDED +#define BASE_TYPES_H_INCLUDED + +#include "error_types.h" + +#ifdef WIN32 + +#include "windows_compat.h" + +#else // not WIN32 + +#include "config.h" + +#define PATH_SEP '/' + +#define __STDC_FORMAT_MACROS + +#if defined HAVE_INTTYPES_H +#include <inttypes.h> +#else +#error "Don't know where int8_t is defined" +#endif + + +// some of my favorite aliases + +typedef char CHAR; + +typedef int8_t INT8; +typedef int16_t INT16; +typedef int32_t INT32; + +typedef uint8_t UINT8; +typedef uint16_t UINT16; +typedef uint32_t UINT32; +typedef uint64_t UINT64; +#endif /* ifdef WIN32 */ + +// and the ever-so-important array size macro +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + + +#endif /* BASE_TYPES_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/brace_cleanup.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/brace_cleanup.cpp new file mode 100644 index 00000000..2cfe2ac2 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/brace_cleanup.cpp @@ -0,0 +1,1449 @@ +/** + * @file brace_cleanup.cpp + * Determines the brace level and paren level. + * Inserts virtual braces as needed. + * Handles all that preprocessor stuff. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "brace_cleanup.h" + +#include "flag_parens.h" +#include "frame_list.h" +#include "keywords.h" +#include "lang_pawn.h" +#include "prototypes.h" + +#include <stdexcept> // to get std::invalid_argument + +constexpr static auto LCURRENT = LBC; + +using namespace uncrustify; + +using std::invalid_argument; +using std::string; +using std::to_string; +using std::stringstream; + + +/* + * abbreviations used: + * - sparen = tbd + * - PS = Parenthesis Stack + * - pse = Parenthesis Stack + */ + + +struct BraceState +{ + std::vector<ParseFrame> frames = {}; + E_Token in_preproc = CT_NONE; + int pp_level = 0; + bool consumed = false; +}; + +/** + * Called when a statement was just closed and the pse_tos was just + * decremented. + * + * - if the TOS is now VBRACE, insert a CT_VBRACE_CLOSE and recurse. + * - if the TOS is a complex statement, call handle_complex_close() + * + * @retval true done with this chunk + * @retval false keep processing + */ +static bool close_statement(ParseFrame &frm, Chunk *pc, const BraceState &braceState); + + +static size_t preproc_start(BraceState &braceState, ParseFrame &frm, Chunk *pc); + + +static void print_stack(log_sev_t logsev, const char *str, const ParseFrame &frm); + + +/** + * pc is a CT_WHILE. + * Scan backwards to see if we find a brace/vbrace with the parent set to CT_DO + */ +static bool maybe_while_of_do(Chunk *pc); + + +/** + * @param after determines: true - insert_vbrace_close_after(pc, frm) + * false - insert_vbrace_open_before(pc, frm) + */ +static Chunk *insert_vbrace(Chunk *pc, bool after, const ParseFrame &frm); + +#define insert_vbrace_close_after(pc, frm) insert_vbrace(pc, true, frm) +#define insert_vbrace_open_before(pc, frm) insert_vbrace(pc, false, frm) + +static void parse_cleanup(BraceState &braceState, ParseFrame &frm, Chunk *pc); + + +/** + * Checks the progression of complex statements. + * - checks for else after if + * - checks for if after else + * - checks for while after do + * - checks for open brace in BRACE2 and BRACE_DO stages, inserts open VBRACE + * - checks for open paren in PAREN1 and BRACE2 stages, complains + * + * @param frm The parse frame + * @param pc The current chunk + * + * @return true - done with this chunk, false - keep processing + */ +static bool check_complex_statements(ParseFrame &frm, Chunk *pc, const BraceState &braceState); + + +/** + * Handles a close paren or brace - just progress the stage, if the end + * of the statement is hit, call close_statement() + * + * @param frm The parse frame + * @param pc The current chunk + * + * @return true - done with this chunk, false - keep processing + */ +static bool handle_complex_close(ParseFrame &frm, Chunk *pc, const BraceState &braceState); + + +//! We're on a 'namespace' skip the word and then set the parent of the braces. +static void mark_namespace(Chunk *pns); + + +static size_t preproc_start(BraceState &braceState, ParseFrame &frm, Chunk *pc) +{ + LOG_FUNC_ENTRY(); + const size_t pp_level = braceState.pp_level; + + Chunk *next = pc->GetNextNcNnl(); + + if (next->IsNullChunk()) + { + return(pp_level); + } + // Get the type of preprocessor and handle it + braceState.in_preproc = next->GetType(); + + // If we are not in a define, check for #if, #else, #endif, etc + if (braceState.in_preproc != CT_PP_DEFINE) + { + int pp_indent = fl_check(braceState.frames, frm, braceState.pp_level, pc); + return(pp_indent); + } + // else push the frame stack + fl_push(braceState.frames, frm); + + // a preproc body starts a new, blank frame + frm = {}; + frm.level = 1; + frm.brace_level = 1; + + // TODO: not sure about the next 3 lines + frm.push(nullptr); + frm.top().type = CT_PP_DEFINE; + + return(pp_level); +} + + +static void print_stack(log_sev_t logsev, const char *str, + const ParseFrame &frm) +{ + LOG_FUNC_ENTRY(); + + if (!log_sev_on(logsev)) + { + return; + } + log_fmt(logsev, "%s(%d): str is '%s'", __func__, __LINE__, str); + + for (size_t idx = 1; idx < frm.size(); idx++) + { + if (frm.at(idx).stage != brace_stage_e::NONE) + { + LOG_FMT(logsev, " [%s - %u]", get_token_name(frm.at(idx).type), + (unsigned int)frm.at(idx).stage); + } + else + { + LOG_FMT(logsev, " [%s]", get_token_name(frm.at(idx).type)); + } + } + + log_fmt(logsev, "\n"); +} + + +//TODO: This can be cleaned up and simplified - we can look both forward and backward! +void brace_cleanup() +{ + LOG_FUNC_ENTRY(); + + BraceState braceState; + ParseFrame frm{}; + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + LOG_CHUNK(LTOK, pc); + + // Check for leaving a #define body + if ( braceState.in_preproc != CT_NONE + && !pc->TestFlags(PCF_IN_PREPROC)) + { + if (braceState.in_preproc == CT_PP_DEFINE) + { + // out of the #define body, restore the frame + size_t brace_level = frm.brace_level; + + if ( options::pp_warn_unbalanced_if() + && brace_level != 1) + { + LOG_FMT(LWARN, "%s(%d): orig line is %zu, unbalanced #define block braces, out-level is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), brace_level); + } + fl_pop(braceState.frames, frm); + } + braceState.in_preproc = CT_NONE; + } + // Check for a preprocessor start + size_t pp_level; + + if (pc->Is(CT_PREPROC)) + { + pp_level = preproc_start(braceState, frm, pc); + } + else + { + pp_level = braceState.pp_level; + } + LOG_FMT(LTOK, "%s(%d): pp level is %zu\n", + __func__, __LINE__, pp_level); + + // Do before assigning stuff from the frame + if ( language_is_set(LANG_PAWN) + && frm.top().type == CT_VBRACE_OPEN + && pc->Is(CT_NEWLINE)) + { + pc = pawn_check_vsemicolon(pc); + + if (pc == nullptr) + { + return; + } + } + + // Issue #1813 + if (pc->Is(CT_NAMESPACE)) + { + mark_namespace(pc); + } + // Assume the level won't change + pc->SetLevel(frm.level); + pc->SetBraceLevel(frm.brace_level); + pc->SetPpLevel(pp_level); + + /* + * #define bodies get the full formatting treatment + * Also need to pass in the initial '#' to close out any virtual braces. + */ + if ( !pc->IsCommentOrNewline() + && !pc->Is(CT_ATTRIBUTE) + && !pc->Is(CT_IGNORED) // Issue #2279 + && ( braceState.in_preproc == CT_PP_DEFINE + || braceState.in_preproc == CT_NONE)) + { + braceState.consumed = false; + parse_cleanup(braceState, frm, pc); + print_stack(LBCSAFTER, (pc->Is(CT_VBRACE_CLOSE)) ? "Virt-}\n" : pc->GetStr().c_str(), frm); + } + pc = pc->GetNext(); + } +} // brace_cleanup + + +static bool maybe_while_of_do(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + Chunk *prev = pc->GetPrevNcNnl(); + + if ( prev->IsNullChunk() + || !prev->TestFlags(PCF_IN_PREPROC)) + { + return(false); + } + + // Find the chunk before the preprocessor + while ( prev->IsNullChunk() + && prev->TestFlags(PCF_IN_PREPROC)) + { + prev = prev->GetPrevNcNnl(); + } + + if ( ( prev->Is(CT_VBRACE_CLOSE) + || prev->Is(CT_BRACE_CLOSE)) + && prev->GetParentType() == CT_DO) + { + return(true); + } + return(false); +} + + +/** + * At the heart of this algorithm are two stacks. + * There is the Paren Stack (PS) and the Frame stack. + * + * The PS (pse in the code) keeps track of braces, parens, + * if/else/switch/do/while/etc items -- anything that is nestable. + * Complex statements go through stages. + * Take this simple if statement as an example: + * if ( x ) { x--; } + * + * The stack would change like so: 'token' stack afterwards + * 'if' [IF - 1] + * '(' [IF - 1] [PAREN OPEN] + * 'x' [IF - 1] [PAREN OPEN] + * ')' [IF - 2] <- note that the state was incremented + * '{' [IF - 2] [BRACE OPEN] + * 'x' [IF - 2] [BRACE OPEN] + * '--' [IF - 2] [BRACE OPEN] + * ';' [IF - 2] [BRACE OPEN] + * '}' [IF - 3] + * <- lack of else kills the IF, closes statement + * + * Virtual braces example: + * if ( x ) x--; else x++; + * + * 'if' [IF - 1] + * '(' [IF - 1] [PAREN OPEN] + * 'x' [IF - 1] [PAREN OPEN] + * ')' [IF - 2] + * 'x' [IF - 2] [VBRACE OPEN] <- VBrace open inserted before because '{' was not next + * '--' [IF - 2] [VBRACE OPEN] + * ';' [IF - 3] <- VBrace close inserted after semicolon + * 'else' [ELSE - 0] <- IF changed into ELSE + * 'x' [ELSE - 0] [VBRACE OPEN] <- lack of '{' -> VBrace + * '++' [ELSE - 0] [VBRACE OPEN] + * ';' [ELSE - 0] <- VBrace close inserted after semicolon + * <- ELSE removed after statement close + * + * The pse stack is kept on a frame stack. + * The frame stack is need for languages that support preprocessors (C, C++, C#) + * that can arbitrarily change code flow. It also isolates #define macros so + * that they are indented independently and do not affect the rest of the program. + * + * When an #if is hit, a copy of the current frame is push on the frame stack. + * When an #else/#elif is hit, a copy of the current stack is pushed under the + * #if frame and the original (pre-#if) frame is copied to the current frame. + * When #endif is hit, the top frame is popped. + * This has the following effects: + * - a simple #if / #endif does not affect program flow + * - #if / #else /#endif - continues from the #if clause + * + * When a #define is entered, the current frame is pushed and cleared. + * When a #define is exited, the frame is popped. + */ +static void parse_cleanup(BraceState &braceState, ParseFrame &frm, Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LTOK, "%s(%d): orig line is %zu, orig col is %zu, type is %s, tos is %zu, TOS.type is %s, TOS.stage is %s, ", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType()), + frm.size() - 1, get_token_name(frm.top().type), + get_brace_stage_name(frm.top().stage)); + log_pcf_flags(LTOK, pc->GetFlags()); + + // Mark statement starts + LOG_FMT(LTOK, "%s(%d): orig line is %zu, type is %s, Text() is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), get_token_name(pc->GetType()), pc->Text()); + LOG_FMT(LTOK, "%s(%d): frm.stmt_count is %zu, frm.expr_count is %zu\n", + __func__, __LINE__, frm.stmt_count, frm.expr_count); + + if ( ( frm.stmt_count == 0 + || frm.expr_count == 0) + && !pc->IsSemicolon() + && pc->IsNot(CT_BRACE_CLOSE) + && pc->IsNot(CT_VBRACE_CLOSE) + && !pc->IsString(")") + && !pc->IsString("]")) + { + pc->SetFlagBits(PCF_EXPR_START | ((frm.stmt_count == 0) ? PCF_STMT_START : PCF_NONE)); + LOG_FMT(LSTMT, "%s(%d): orig line is %zu, 1.marked '%s' as %s, start stmt_count is %zu, expr_count is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->Text(), + pc->TestFlags(PCF_STMT_START) ? "stmt" : "expr", frm.stmt_count, + frm.expr_count); + } + frm.stmt_count++; + frm.expr_count++; + LOG_FMT(LTOK, "%s(%d): frm.stmt_count is %zu, frm.expr_count is %zu\n", + __func__, __LINE__, frm.stmt_count, frm.expr_count); + + if (frm.sparen_count > 0) + { + pc->SetFlagBits(PCF_IN_SPAREN); + + // Mark everything in the for statement + for (int tmp = static_cast<int>(frm.size()) - 2; tmp >= 0; tmp--) + { + if (frm.at(tmp).type == CT_FOR) + { + pc->SetFlagBits(PCF_IN_FOR); + break; + } + } + + // Mark the parent on semicolons in for() statements + if ( pc->Is(CT_SEMICOLON) + && frm.size() > 2 + && frm.prev().type == CT_FOR) + { + pc->SetParentType(CT_FOR); + } + } + + // Check the progression of complex statements + if ( frm.top().stage != brace_stage_e::NONE + && !pc->Is(CT_AUTORELEASEPOOL) + && check_complex_statements(frm, pc, braceState)) + { + return; + } + + /* + * Check for a virtual brace statement close due to a semicolon. + * The virtual brace will get handled the next time through. + * The semicolon isn't handled at all. + * TODO: may need to float VBRACE past comments until newline? + */ + if (frm.top().type == CT_VBRACE_OPEN) + { + if (pc->IsSemicolon()) + { + braceState.consumed = true; + close_statement(frm, pc, braceState); + } + else if ( language_is_set(LANG_PAWN) + && pc->Is(CT_BRACE_CLOSE)) + { + close_statement(frm, pc, braceState); + } + else if ( language_is_set(LANG_D) + && pc->Is(CT_BRACE_CLOSE)) + { + close_statement(frm, pc, braceState); + } + } + + // Handle close parenthesis, vbrace, brace, and square + if ( pc->Is(CT_PAREN_CLOSE) + || pc->Is(CT_BRACE_CLOSE) + || pc->Is(CT_VBRACE_CLOSE) + || pc->Is(CT_ANGLE_CLOSE) + || pc->Is(CT_MACRO_CLOSE) + || pc->Is(CT_SQUARE_CLOSE)) + { + // Change CT_PAREN_CLOSE into CT_SPAREN_CLOSE or CT_FPAREN_CLOSE + if ( pc->Is(CT_PAREN_CLOSE) + && ( (frm.top().type == CT_FPAREN_OPEN) + || (frm.top().type == CT_SPAREN_OPEN))) + { + // TODO: fix enum hack + pc->SetType(static_cast<E_Token>(frm.top().type + 1)); + + if (pc->Is(CT_SPAREN_CLOSE)) + { + frm.sparen_count--; + pc->ResetFlagBits(PCF_IN_SPAREN); + } + } + + // Make sure the open / close match + if (pc->IsNot((E_Token)(frm.top().type + 1))) + { + if (pc->TestFlags(PCF_IN_PREPROC)) // Issue #3113, #3283 + { + // do nothing + } + else + { + LOG_FMT(LWARN, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + paren_stack_entry_t AA = frm.top(); // Issue #3055 + + if (AA.type != CT_EOF) + { + LOG_FMT(LWARN, "%s(%d): (frm.top().type + 1) is %s\n", + __func__, __LINE__, get_token_name((E_Token)(frm.top().type + 1))); + } + + if ( frm.top().type != CT_EOF + && frm.top().type != CT_PP_DEFINE) + { + LOG_FMT(LWARN, "%s(%d): File: %s, orig line is %zu, orig col is %zu, Error: Unexpected '%s' for '%s', which was on line %zu\n", + __func__, __LINE__, cpd.filename.c_str(), pc->GetOrigLine(), pc->GetOrigCol(), + pc->Text(), get_token_name(frm.top().pc->GetType()), + frm.top().pc->GetOrigLine()); + print_stack(LBCSPOP, "=Error ", frm); + exit(EXIT_FAILURE); + } + } + } + else + { + braceState.consumed = true; + + // Copy the parent, update the parenthesis/brace levels + pc->SetParentType(frm.top().parent); + frm.level--; + + if ( pc->Is(CT_BRACE_CLOSE) + || pc->Is(CT_VBRACE_CLOSE) + || pc->Is(CT_MACRO_CLOSE)) + { + frm.brace_level--; + LOG_FMT(LBCSPOP, "%s(%d): frm.brace_level decreased to %zu", + __func__, __LINE__, frm.brace_level); + log_pcf_flags(LBCSPOP, pc->GetFlags()); + } + pc->SetLevel(frm.level); + pc->SetBraceLevel(frm.brace_level); + + // Pop the entry + LOG_FMT(LBCSPOP, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + print_stack(LBCSPOP, "-Close ", frm); + + if ( frm.top().stage == brace_stage_e::NONE + && ( pc->Is(CT_VBRACE_CLOSE) + || pc->Is(CT_BRACE_CLOSE) + || pc->Is(CT_SEMICOLON)) + && frm.top().pc->Is(CT_VBRACE_OPEN)) + { + // frames for functions are not created as they are for an if + // this here is a hackish solution to close a vbrace of a block that + // contains the function + frm.push(nullptr); // <- dummy frame for the function + frm.top().stage = brace_stage_e::BRACE2; + } + + // See if we are in a complex statement + if (frm.top().stage != brace_stage_e::NONE) + { + handle_complex_close(frm, pc, braceState); + } + } + } + + /* + * In this state, we expect a semicolon, but we'll also hit the closing + * sparen, so we need to check braceState.consumed to see if the close sparen + * was already handled. + */ + if (frm.top().stage == brace_stage_e::WOD_SEMI) + { + if (braceState.consumed) + { + /* + * If consumed, then we are on the close sparen. + * PAWN: Check the next chunk for a semicolon. If it isn't, then + * add a virtual semicolon, which will get handled on the next pass. + */ + if (language_is_set(LANG_PAWN)) + { + Chunk *tmp = pc->GetNextNcNnl(); + + if (!tmp->IsSemicolon()) + { + pawn_add_vsemi_after(pc); + } + } + } + else + { + // Complain if this ISN'T a semicolon, but close out WHILE_OF_DO anyway + if (pc->IsSemicolon()) + { + braceState.consumed = true; + pc->SetParentType(CT_WHILE_OF_DO); + } + else + { + LOG_FMT(LWARN, "%s: %s(%d): %zu: Error: Expected a semicolon for WHILE_OF_DO, but got '%s'\n", + cpd.filename.c_str(), __func__, __LINE__, pc->GetOrigLine(), + get_token_name(pc->GetType())); + exit(EX_SOFTWARE); + } + handle_complex_close(frm, pc, braceState); + } + } + // Get the parent type for brace and parenthesis open + E_Token parentType = pc->GetParentType(); + + if ( pc->Is(CT_PAREN_OPEN) + || pc->Is(CT_FPAREN_OPEN) + || pc->Is(CT_SPAREN_OPEN) + || pc->Is(CT_BRACE_OPEN)) + { + Chunk *prev = pc->GetPrevNcNnl(); + + if (prev->IsNotNullChunk()) + { + if ( pc->Is(CT_PAREN_OPEN) + || pc->Is(CT_FPAREN_OPEN) + || pc->Is(CT_SPAREN_OPEN)) + { + // Set the parent for parenthesis and change parenthesis type + if ( prev->Is(CT_IF) + || prev->Is(CT_CONSTEXPR) + || prev->Is(CT_ELSEIF) + || prev->Is(CT_WHILE) + || prev->Is(CT_WHILE_OF_DO) + || prev->Is(CT_DO) + || prev->Is(CT_FOR) + || prev->Is(CT_SWITCH) + || prev->Is(CT_CATCH) + || prev->Is(CT_SYNCHRONIZED) + || prev->Is(CT_D_VERSION) + || prev->Is(CT_D_VERSION_IF) + || prev->Is(CT_D_SCOPE) + || prev->Is(CT_D_SCOPE_IF)) + { + pc->SetType(CT_SPAREN_OPEN); + parentType = frm.top().type; + frm.sparen_count++; + } + else if (prev->Is(CT_FUNCTION)) + { + pc->SetType(CT_FPAREN_OPEN); + parentType = CT_FUNCTION; + } + // NS_ENUM and NS_OPTIONS are followed by a (type, name) pair + else if ( prev->Is(CT_ENUM) + && language_is_set(LANG_OC)) + { + // Treat both as CT_ENUM since the syntax is identical + pc->SetType(CT_FPAREN_OPEN); + parentType = CT_ENUM; + } + else if (prev->Is(CT_DECLSPEC)) // Issue 1289 + { + parentType = CT_DECLSPEC; + } + // else: no need to set parent + } + else // must be CT_BRACE_OPEN + { + // Set the parent for open braces + if (frm.top().stage != brace_stage_e::NONE) + { + parentType = frm.top().type; + } + else if ( prev->Is(CT_ASSIGN) + && (prev->GetStr()[0] == '=')) + { + parentType = CT_ASSIGN; + } + else if ( prev->Is(CT_RETURN) + && language_is_set(LANG_CPP)) + { + parentType = CT_RETURN; + } + // Carry through CT_ENUM parent in NS_ENUM (type, name) { + // only to help the vim command } + else if ( prev->Is(CT_FPAREN_CLOSE) + && language_is_set(LANG_OC) + && prev->GetParentType() == CT_ENUM) + { + parentType = CT_ENUM; + } + else if (prev->Is(CT_FPAREN_CLOSE)) + { + parentType = CT_FUNCTION; + } + // else: no need to set parent + } + } + } + + /* + * Adjust the level for opens & create a stack entry + * Note that CT_VBRACE_OPEN has already been handled. + */ + if ( pc->Is(CT_BRACE_OPEN) + || pc->Is(CT_PAREN_OPEN) + || pc->Is(CT_FPAREN_OPEN) + || pc->Is(CT_SPAREN_OPEN) + || pc->Is(CT_ANGLE_OPEN) + || pc->Is(CT_MACRO_OPEN) + || pc->Is(CT_SQUARE_OPEN)) + { + frm.level++; + + if ( pc->Is(CT_BRACE_OPEN) + || pc->Is(CT_MACRO_OPEN)) + { + // Issue #1813 + bool single = false; + + if (pc->GetParentType() == CT_NAMESPACE) + { + LOG_FMT(LBCSPOP, "%s(%d): parent type is NAMESPACE\n", + __func__, __LINE__); + Chunk *tmp = frm.top().pc; + + if ( tmp != nullptr + && tmp->GetParentType() == CT_NAMESPACE) + { + LOG_FMT(LBCSPOP, "%s(%d): tmp->GetParentType() is NAMESPACE\n", + __func__, __LINE__); + + log_rule_B("indent_namespace"); + log_rule_B("indent_namespace_single_indent"); + + if ( options::indent_namespace() + && options::indent_namespace_single_indent()) + { + LOG_FMT(LBCSPOP, "%s(%d): Options are SINGLE\n", + __func__, __LINE__); + single = true; + } + } + } + LOG_FMT(LBCSPOP, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s, parent type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType()), get_token_name(pc->GetParentType())); + + if (!single) + { + frm.brace_level++; + LOG_FMT(LBCSPOP, "%s(%d): frm.brace_level increased to %zu\n", + __func__, __LINE__, frm.brace_level); + } + } + frm.push(pc, __func__, __LINE__); + frm.top().parent = parentType; + pc->SetParentType(parentType); + } + // Issue #2281 + + if ( pc->Is(CT_BRACE_OPEN) + && pc->GetParentType() == CT_SWITCH) + { + size_t idx = frm.size(); + LOG_FMT(LBCSPOP, "%s(%d): idx is %zu\n", + __func__, __LINE__, idx); + Chunk *saved = frm.at(idx - 2).pc; + + if (saved != nullptr) + { + // set parent member + pc->SetParent(saved); + } + } + + if ( pc->Is(CT_CASE) + || pc->Is(CT_DEFAULT)) + { + Chunk *prev = pc->GetPrevNcNnl(); // Issue #3176 + + if ( pc->Is(CT_CASE) + || ( pc->Is(CT_DEFAULT) + && prev->IsNot(CT_ASSIGN))) + { + // it is a CT_DEFAULT from a switch + LOG_FMT(LBCSPOP, "%s(%d): pc orig line is %zu, orig col is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + pc->SetParentType(CT_SWITCH); + size_t idx = frm.size(); + LOG_FMT(LBCSPOP, "%s(%d): idx is %zu\n", + __func__, __LINE__, idx); + Chunk *saved = frm.at(idx - 2).pc; + + if (saved != nullptr) + { + // set parent member + pc->SetParent(saved); + } + } + } + + if (pc->Is(CT_BREAK)) + { + LOG_FMT(LBCSPOP, "%s(%d): pc orig line is %zu, orig col is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + size_t idx = frm.size(); + LOG_FMT(LBCSPOP, "%s(%d): idx is %zu\n", + __func__, __LINE__, idx); + Chunk *saved = frm.at(idx - 2).pc; + + if (saved != nullptr) + { + // set parent member + pc->SetParent(saved); + } + } + const pattern_class_e patcls = get_token_pattern_class(pc->GetType()); + + /* + * Create a stack entry for complex statements: + * if, elseif, switch, for, while, synchronized, using, lock, with, + * version, CT_D_SCOPE_IF + */ + if (patcls == pattern_class_e::BRACED) + { + frm.push(pc, __func__, __LINE__, (pc->Is(CT_DO) ? brace_stage_e::BRACE_DO + : brace_stage_e::BRACE2)); + // "+ComplexBraced" + } + else if (patcls == pattern_class_e::PBRACED) + { + brace_stage_e bs = brace_stage_e::PAREN1; + + if ( pc->Is(CT_WHILE) + && maybe_while_of_do(pc)) + { + pc->SetType(CT_WHILE_OF_DO); + bs = brace_stage_e::WOD_PAREN; + } + frm.push(pc, __func__, __LINE__, bs); + // "+ComplexParenBraced" + } + else if (patcls == pattern_class_e::OPBRACED) + { + frm.push(pc, __func__, __LINE__, brace_stage_e::OP_PAREN1); + // "+ComplexOpParenBraced"); + } + else if (patcls == pattern_class_e::ELSE) + { + frm.push(pc, __func__, __LINE__, brace_stage_e::ELSEIF); + // "+ComplexElse"); + } + + /* + * Mark simple statement/expression starts + * - after { or } + * - after ';', but not if the paren stack top is a paren + * - after '(' that has a parent type of CT_FOR + */ + if ( pc->Is(CT_SQUARE_OPEN) + || ( pc->Is(CT_BRACE_OPEN) + && pc->GetParentType() != CT_ASSIGN) + || pc->Is(CT_BRACE_CLOSE) + || pc->Is(CT_VBRACE_CLOSE) + || ( pc->Is(CT_SPAREN_OPEN) + && pc->GetParentType() == CT_FOR) + || pc->Is(CT_COLON) + || pc->Is(CT_OC_END) + || ( pc->IsSemicolon() + && frm.top().type != CT_PAREN_OPEN + && frm.top().type != CT_FPAREN_OPEN + && frm.top().type != CT_SPAREN_OPEN) + || pc->Is(CT_MACRO)) // Issue #2742 + { + LOG_FMT(LSTMT, "%s(%d): orig line is %zu, reset1 stmt on '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->Text()); + frm.stmt_count = 0; + frm.expr_count = 0; + LOG_FMT(LTOK, "%s(%d): frm.stmt_count is %zu, frm.expr_count is %zu\n", + __func__, __LINE__, frm.stmt_count, frm.expr_count); + } + // Mark expression starts + LOG_FMT(LSTMT, "%s(%d): Mark expression starts: orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + Chunk *tmp = pc->GetNextNcNnl(); + + if ( pc->Is(CT_ARITH) + || pc->Is(CT_SHIFT) + || pc->Is(CT_ASSIGN) + || pc->Is(CT_CASE) + || pc->Is(CT_COMPARE) + || ( pc->Is(CT_STAR) + && tmp->IsNot(CT_STAR)) + || pc->Is(CT_BOOL) + || pc->Is(CT_MINUS) + || pc->Is(CT_PLUS) + || pc->Is(CT_CARET) + || pc->Is(CT_ANGLE_OPEN) + || pc->Is(CT_ANGLE_CLOSE) + || pc->Is(CT_RETURN) + || pc->Is(CT_THROW) + || pc->Is(CT_GOTO) + || pc->Is(CT_CONTINUE) + || pc->Is(CT_PAREN_OPEN) + || pc->Is(CT_FPAREN_OPEN) + || pc->Is(CT_SPAREN_OPEN) + || pc->Is(CT_BRACE_OPEN) + || pc->IsSemicolon() + || pc->Is(CT_COMMA) + || pc->Is(CT_NOT) + || pc->Is(CT_INV) + || pc->Is(CT_COLON) + || pc->Is(CT_QUESTION)) + { + frm.expr_count = 0; + LOG_FMT(LSTMT, "%s(%d): orig line is %zu, orig col is %zu, reset expr on '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + } +} // parse_cleanup + + +static bool check_complex_statements(ParseFrame &frm, Chunk *pc, const BraceState &braceState) +{ + LOG_FUNC_ENTRY(); + + brace_stage_e atest = frm.top().stage; + + LOG_FMT(LBCSPOP, "%s(%d): atest is %s\n", + __func__, __LINE__, get_brace_stage_name(atest)); + + // Turn an optional parenthesis into either a real parenthesis or a brace + if (frm.top().stage == brace_stage_e::OP_PAREN1) + { + frm.top().stage = (pc->IsNot(CT_PAREN_OPEN)) + ? brace_stage_e::BRACE2 + : brace_stage_e::PAREN1; + LOG_FMT(LBCSPOP, "%s(%d): frm.top().stage is now %s\n", + __func__, __LINE__, get_brace_stage_name(frm.top().stage)); + } + + // Check for CT_ELSE after CT_IF + while (frm.top().stage == brace_stage_e::ELSE) + { + if (pc->Is(CT_ELSE)) + { + // Replace CT_IF with CT_ELSE on the stack & we are done + frm.top().type = CT_ELSE; + frm.top().stage = brace_stage_e::ELSEIF; + print_stack(LBCSSWAP, "=Swap ", frm); + + return(true); + } + // Remove the CT_IF and close the statement + LOG_FMT(LBCSPOP, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + print_stack(LBCSPOP, "-IF-CCS ", frm); + + if (close_statement(frm, pc, braceState)) + { + return(true); + } + } + + // Check for CT_IF after CT_ELSE + if (frm.top().stage == brace_stage_e::ELSEIF) + { + log_rule_B("indent_else_if"); + + if ( pc->Is(CT_IF) + && ( !options::indent_else_if() + || !pc->GetPrevNc()->IsNewline())) + { + // Replace CT_ELSE with CT_IF + pc->SetType(CT_ELSEIF); + frm.top().type = CT_ELSEIF; + frm.top().stage = brace_stage_e::PAREN1; + return(true); + } + // Jump to the 'expecting brace' stage + frm.top().stage = brace_stage_e::BRACE2; + } + + // Check for CT_CATCH or CT_FINALLY after CT_TRY or CT_CATCH + while (frm.top().stage == brace_stage_e::CATCH) + { + if ( pc->Is(CT_CATCH) + || pc->Is(CT_FINALLY)) + { + // Replace CT_TRY with CT_CATCH or CT_FINALLY on the stack & we are done + frm.top().type = pc->GetType(); + + if (language_is_set(LANG_CS)) + { + frm.top().stage = (pc->Is(CT_CATCH)) ? brace_stage_e::CATCH_WHEN : brace_stage_e::BRACE2; + } + else + { + // historically this used OP_PAREN1; however, to my knowledge the expression after a catch clause + // is only optional for C# which has been handled above; therefore, this should now always expect + // a parenthetical expression after the catch keyword and brace after the finally keyword + frm.top().stage = (pc->Is(CT_CATCH)) ? brace_stage_e::PAREN1 : brace_stage_e::BRACE2; + } + print_stack(LBCSSWAP, "=Swap ", frm); + + return(true); + } + // Remove the CT_TRY and close the statement + LOG_FMT(LBCSPOP, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + print_stack(LBCSPOP, "-TRY-CCS ", frm); + + if (close_statement(frm, pc, braceState)) + { + return(true); + } + } + + // Check for optional parenthesis and optional CT_WHEN after CT_CATCH + if (frm.top().stage == brace_stage_e::CATCH_WHEN) + { + if (pc->Is(CT_PAREN_OPEN)) // this is for the paren after "catch" + { + // Replace CT_PAREN_OPEN with CT_SPAREN_OPEN + pc->SetType(CT_SPAREN_OPEN); + frm.top().type = pc->GetType(); + frm.top().stage = brace_stage_e::PAREN1; + + return(false); + } + + if (pc->Is(CT_WHEN)) + { + frm.top().type = pc->GetType(); + frm.top().stage = brace_stage_e::OP_PAREN1; + + return(true); + } + + if (pc->Is(CT_BRACE_OPEN)) + { + frm.top().stage = brace_stage_e::BRACE2; + + return(false); + } + } + + // Check for CT_WHILE after the CT_DO + if (frm.top().stage == brace_stage_e::WHILE) + { + if (pc->Is(CT_WHILE)) + { + pc->SetType(CT_WHILE_OF_DO); + frm.top().type = CT_WHILE_OF_DO; //CT_WHILE; + frm.top().stage = brace_stage_e::WOD_PAREN; + + return(true); + } + LOG_FMT(LWARN, "%s(%d): %s, orig line is %zu, Error: Expected 'while', got '%s'\n", + __func__, __LINE__, cpd.filename.c_str(), pc->GetOrigLine(), + pc->Text()); + LOG_FMT(LBCSPOP, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + print_stack(LBCSPOP, "-Error ", frm); + exit(EX_SOFTWARE); + } + // Insert a CT_VBRACE_OPEN, if needed + // but not in a preprocessor + atest = frm.top().stage; + + if ( pc->IsNot(CT_BRACE_OPEN) + && !pc->TestFlags(PCF_IN_PREPROC) + && ( (frm.top().stage == brace_stage_e::BRACE2) + || (frm.top().stage == brace_stage_e::BRACE_DO))) + { + log_rule_B("indent_using_block"); + + if ( language_is_set(LANG_CS) + && pc->Is(CT_USING_STMT) + && (!options::indent_using_block())) + { + // don't indent the using block + } + else + { + const E_Token parentType = frm.top().type; + + Chunk *vbrace = insert_vbrace_open_before(pc, frm); + vbrace->SetParentType(parentType); + + frm.level++; + frm.brace_level++; + LOG_FMT(LBCSPOP, "%s(%d): frm.brace_level increased to %zu\n", + __func__, __LINE__, frm.brace_level); + log_pcf_flags(LBCSPOP, pc->GetFlags()); + + frm.push(vbrace, __func__, __LINE__, brace_stage_e::NONE); + // "+VBrace"); + + frm.top().parent = parentType; + + // update the level of pc + pc->SetLevel(frm.level); + pc->SetBraceLevel(frm.brace_level); + + // Mark as a start of a statement + frm.stmt_count = 0; + frm.expr_count = 0; + LOG_FMT(LTOK, "%s(%d): frm.stmt_count is %zu, frm.expr_count is %zu\n", + __func__, __LINE__, frm.stmt_count, frm.expr_count); + pc->SetFlagBits(PCF_STMT_START | PCF_EXPR_START); + frm.stmt_count = 1; + frm.expr_count = 1; + LOG_FMT(LSTMT, "%s(%d): orig line is %zu, 2.marked '%s' as stmt start\n", + __func__, __LINE__, pc->GetOrigLine(), pc->Text()); + } + } + + // Check for "constexpr" after CT_IF or CT_ELSEIF + if ( frm.top().stage == brace_stage_e::PAREN1 + && ( frm.top().type == CT_IF + || frm.top().type == CT_ELSEIF) + && pc->Is(CT_CONSTEXPR)) + { + return(false); + } + + // Verify open parenthesis in complex statement + if ( pc->IsNot(CT_PAREN_OPEN) + && ( (frm.top().stage == brace_stage_e::PAREN1) + || (frm.top().stage == brace_stage_e::WOD_PAREN))) + { + LOG_FMT(LWARN, "%s(%d): %s, orig line is %zu, Error: Expected '(', got '%s' for '%s'\n", + __func__, __LINE__, cpd.filename.c_str(), pc->GetOrigLine(), pc->Text(), + get_token_name(frm.top().type)); + + // Throw out the complex statement + LOG_FMT(LBCSPOP, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + print_stack(LBCSPOP, "-Error ", frm); + exit(EX_SOFTWARE); + } + return(false); +} // check_complex_statements + + +static bool handle_complex_close(ParseFrame &frm, Chunk *pc, const BraceState &braceState) +{ + LOG_FUNC_ENTRY(); + + if (frm.top().stage == brace_stage_e::PAREN1) + { + if (pc->GetNext()->GetType() == CT_WHEN) + { + frm.top().type = pc->GetType(); + frm.top().stage = brace_stage_e::CATCH_WHEN; + + return(true); + } + // PAREN1 always => BRACE2 + frm.top().stage = brace_stage_e::BRACE2; + } + else if (frm.top().stage == brace_stage_e::BRACE2) + { + // BRACE2: IF => ELSE, anything else => close + if ( (frm.top().type == CT_IF) + || (frm.top().type == CT_ELSEIF)) + { + frm.top().stage = brace_stage_e::ELSE; + + // If the next chunk isn't CT_ELSE, close the statement + Chunk *next = pc->GetNextNcNnl(); + + if ( next->IsNullChunk() + || next->IsNot(CT_ELSE)) + { + LOG_FMT(LBCSPOP, "%s(%d): no CT_ELSE, pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + print_stack(LBCSPOP, "-IF-HCS ", frm); + + return(close_statement(frm, pc, braceState)); + } + } + else if ( (frm.top().type == CT_TRY) + || (frm.top().type == CT_CATCH)) + { + frm.top().stage = brace_stage_e::CATCH; + + // If the next chunk isn't CT_CATCH or CT_FINALLY, close the statement + Chunk *next = pc->GetNextNcNnl(); + + if ( next->IsNot(CT_CATCH) + && next->IsNot(CT_FINALLY)) + { + LOG_FMT(LBCSPOP, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + print_stack(LBCSPOP, "-TRY-HCS ", frm); + + return(close_statement(frm, pc, braceState)); + } + } + else + { + LOG_FMT(LNOTE, "%s(%d): close_statement on %s brace_stage_e::BRACE2\n", + __func__, __LINE__, get_token_name(frm.top().type)); + LOG_FMT(LBCSPOP, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + print_stack(LBCSPOP, "-HCC B2 ", frm); + + return(close_statement(frm, pc, braceState)); + } + } + else if (frm.top().stage == brace_stage_e::BRACE_DO) + { + frm.top().stage = brace_stage_e::WHILE; + } + else if (frm.top().stage == brace_stage_e::WOD_PAREN) + { + LOG_FMT(LNOTE, "%s(%d): close_statement on %s brace_stage_e::WOD_PAREN\n", + __func__, __LINE__, get_token_name(frm.top().type)); + frm.top().stage = brace_stage_e::WOD_SEMI; + print_stack(LBCSPOP, "-HCC WoDP ", frm); + } + else if (frm.top().stage == brace_stage_e::WOD_SEMI) + { + LOG_FMT(LNOTE, "%s(%d): close_statement on %s brace_stage_e::WOD_SEMI\n", + __func__, __LINE__, get_token_name(frm.top().type)); + LOG_FMT(LBCSPOP, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + print_stack(LBCSPOP, "-HCC WoDS ", frm); + + return(close_statement(frm, pc, braceState)); + } + else + { + // PROBLEM + LOG_FMT(LWARN, "%s(%d): %s:%zu Error: TOS.type='%s' TOS.stage=%u\n", + __func__, __LINE__, cpd.filename.c_str(), pc->GetOrigLine(), + get_token_name(frm.top().type), + (unsigned int)frm.top().stage); + exit(EX_SOFTWARE); + } + return(false); +} // handle_complex_close + + +static void mark_namespace(Chunk *pns) +{ + LOG_FUNC_ENTRY(); + // Issue #1813 + Chunk *br_close; + bool is_using = false; + + Chunk *pc = pns->GetPrevNcNnl(); + + if (pc->Is(CT_USING)) + { + is_using = true; + pns->SetParentType(CT_USING); + } + pc = pns->GetNextNcNnl(); + + while (pc->IsNotNullChunk()) + { + pc->SetParentType(CT_NAMESPACE); + + if (pc->IsNot(CT_BRACE_OPEN)) + { + if (pc->Is(CT_SEMICOLON)) + { + if (is_using) + { + pc->SetParentType(CT_USING); + } + return; + } + pc = pc->GetNextNcNnl(); + continue; + } + log_rule_B("indent_namespace_limit"); + + if ( (options::indent_namespace_limit() > 0) + && ((br_close = pc->GetClosingParen())->IsNotNullChunk())) + { + // br_close->GetOrigLine() is always >= pc->GetOrigLine(); + size_t numberOfLines = br_close->GetOrigLine() - pc->GetOrigLine() - 1; // Issue #2345 + LOG_FMT(LTOK, "%s(%d): br_close orig line is %zu, pc orig line is %zu\n", + __func__, __LINE__, br_close->GetOrigLine(), pc->GetOrigLine()); + LOG_FMT(LTOK, "%s(%d): numberOfLines is %zu, indent_namespace_limit() is %d\n", + __func__, __LINE__, numberOfLines, options::indent_namespace_limit()); + + log_rule_B("indent_namespace_limit"); + + if (numberOfLines > options::indent_namespace_limit()) + { + LOG_FMT(LTOK, "%s(%d): PCF_LONG_BLOCK is set\n", __func__, __LINE__); + pc->SetFlagBits(PCF_LONG_BLOCK); + br_close->SetFlagBits(PCF_LONG_BLOCK); + } + } + flag_parens(pc, PCF_IN_NAMESPACE, CT_NONE, CT_NAMESPACE, false); + return; + } +} // mark_namespace + + +static Chunk *insert_vbrace(Chunk *pc, bool after, const ParseFrame &frm) +{ + LOG_FUNC_ENTRY(); + + Chunk chunk; + + chunk.SetParentType(frm.top().type); + chunk.SetOrigLine(pc->GetOrigLine()); + chunk.SetLevel(frm.level); + chunk.SetPpLevel(frm.pp_level); + chunk.SetBraceLevel(frm.brace_level); + chunk.SetFlags(pc->GetFlags() & PCF_COPY_FLAGS); + chunk.Str() = ""; + + if (after) + { + chunk.SetOrigCol(pc->GetOrigCol()); + chunk.SetType(CT_VBRACE_CLOSE); + return(chunk.CopyAndAddAfter(pc)); + } + Chunk *ref = pc->GetPrev(); + + if (ref->IsNullChunk()) + { + return(nullptr); + } + + if (!ref->TestFlags(PCF_IN_PREPROC)) + { + chunk.ResetFlagBits(PCF_IN_PREPROC); + } + bool ref_is_comment = ref->IsComment(); // Issue #3351 + + while (ref->IsCommentOrNewline()) + { + ref->SetLevel(ref->GetLevel() + 1); + ref->SetBraceLevel(ref->GetBraceLevel() + 1); + ref = ref->GetPrev(); + } + + if (ref->IsNullChunk()) + { + return(nullptr); + } + + // Don't back into a preprocessor + if ( !pc->TestFlags(PCF_IN_PREPROC) + && ref->TestFlags(PCF_IN_PREPROC)) + { + if (ref->Is(CT_PREPROC_BODY)) + { + while ( ref->IsNotNullChunk() + && ref->TestFlags(PCF_IN_PREPROC)) + { + ref = ref->GetPrev(); + } + } + else + { + ref = ref->GetNext(); + + if (ref->Is(CT_COMMENT)) // Issue #3034 + { + ref = ref->GetNextNc(); + } + } + } + + if (ref_is_comment) // Issue #3351 + { + ref = ref->GetNext(); + } + + if (ref->IsNullChunk()) + { + return(nullptr); + } + chunk.SetOrigLine(ref->GetOrigLine()); + chunk.SetOrigCol(ref->GetOrigCol()); + chunk.SetColumn(ref->GetColumn() + ref->Len() + 1); + chunk.SetPpLevel(ref->GetPpLevel()); // Issue #3055 + chunk.SetType(CT_VBRACE_OPEN); + + return(chunk.CopyAndAddAfter(ref)); +} // insert_vbrace + + +bool close_statement(ParseFrame &frm, Chunk *pc, const BraceState &braceState) +{ + LOG_FUNC_ENTRY(); + + if ( pc == nullptr + || pc->IsNullChunk()) + { + throw invalid_argument(string(__func__) + ":" + to_string(__LINE__) + + "args cannot be nullptr"); + } + LOG_FMT(LTOK, "%s(%d): orig line is %zu, type is %s, '%s' type is %s, stage is %u\n", + __func__, __LINE__, pc->GetOrigLine(), + get_token_name(pc->GetType()), pc->Text(), + get_token_name(frm.top().type), + (unsigned int)frm.top().stage); + + if (braceState.consumed) + { + frm.stmt_count = 0; + frm.expr_count = 0; + LOG_FMT(LSTMT, "%s(%d): orig line is %zu> reset2 stmt on '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->Text()); + } + /* + * Insert a CT_VBRACE_CLOSE, if needed: + * If we are in a virtual brace and we are not ON a CT_VBRACE_CLOSE add one + */ + Chunk *vbc = pc; + + if (frm.top().type == CT_VBRACE_OPEN) + { + // If the current token has already been consumed, then add after it + if (braceState.consumed) + { + insert_vbrace_close_after(pc, frm); + } + else + { + // otherwise, add before it and consume the vbrace + vbc = pc->GetPrevNcNnl(); + + frm.level--; + frm.brace_level--; + vbc = insert_vbrace_close_after(vbc, frm); + vbc->SetParentType(frm.top().parent); + + LOG_FMT(LBCSPOP, "%s(%d): frm.brace_level decreased to %zu\n", + __func__, __LINE__, frm.brace_level); + log_pcf_flags(LBCSPOP, pc->GetFlags()); + LOG_FMT(LBCSPOP, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + + // Update the token level + pc->SetLevel(frm.level); + pc->SetBraceLevel(frm.brace_level); + + print_stack(LBCSPOP, "-CS VB ", frm); + + // And repeat the close + close_statement(frm, pc, braceState); + return(true); + } + } + + // See if we are done with a complex statement + if (frm.top().stage != brace_stage_e::NONE) + { + if (handle_complex_close(frm, vbc, braceState)) + { + return(true); + } + } + return(false); +} // close_statement diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/brace_cleanup.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/brace_cleanup.h new file mode 100644 index 00000000..e281d2e3 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/brace_cleanup.h @@ -0,0 +1,23 @@ +/** + * @file brace_cleanup.h + * prototypes for brace_cleanup.cpp + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef BRACE_CLEANUP_H_INCLUDED +#define BRACE_CLEANUP_H_INCLUDED + +#include "uncrustify_types.h" +// necessary to not sort +#include "ParseFrame.h" + +/** + * Scans through the whole list and does stuff. + * It has to do some tricks to parse preprocessors. + */ +void brace_cleanup(); + + +#endif /* BRACE_CLEANUP_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/braces.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/braces.cpp new file mode 100644 index 00000000..1737e79e --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/braces.cpp @@ -0,0 +1,1697 @@ +/** + * @file braces.cpp + * Adds or removes braces. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "braces.h" + +#include "calculate_closing_brace_position.h" +#include "combine_tools.h" +#include "newlines.h" +#include "prototypes.h" + +constexpr static auto LCURRENT = LBR; + +using namespace uncrustify; + +using std::vector; + + +//! Converts a single brace into a virtual brace +static void convert_brace(Chunk *br); + + +//! Converts a single virtual brace into a real brace +static void convert_vbrace(Chunk *br); + + +static void convert_vbrace_to_brace(); + + +//! Go backwards to honor brace newline removal limits +static void examine_braces(); + + +/** + * Step forward and count the number of semi colons at the current level. + * Abort if more than 1 or if we enter a preprocessor + */ +static void examine_brace(Chunk *bopen); + + +static void move_case_break(); + + +static void move_case_return(); + + +static void mod_case_brace(); + + +static void mod_full_brace_if_chain(); + + +/** + * Checks to see if the braces can be removed. + * - less than a certain length + * - doesn't mess up if/else stuff + */ +static bool can_remove_braces(Chunk *bopen); + + +/** + * Checks to see if the virtual braces should be converted to real braces. + * - over a certain length + * + * @param vbopen Virtual Brace Open chunk + * + * @return true (convert to real braces) or false (leave alone) + */ +static bool should_add_braces(Chunk *vbopen); + + +/** + * Collect the text into txt that contains the full tag name. + * Mainly for collecting namespace 'a.b.c' or function 'foo::bar()' names. + */ +static void append_tag_name(unc_text &txt, Chunk *pc); + + +//! Remove the case brace, if allowable. +static Chunk *mod_case_brace_remove(Chunk *br_open); + + +//! Add the case brace, if allowable. +static Chunk *mod_case_brace_add(Chunk *cl_colon); + + +/** + * Traverse the if chain and see if all can be removed + * + * @param br_start chunk pointing to opening brace of if clause + */ +static void process_if_chain(Chunk *br_start); + + +/** + * Check if parenthesis pair that comes before a brace spans multiple lines + * + * + * @param brace the brace chunk whose predecessing parenthesis will be checked + * + * @pre the brace chunk cannot be a nullptr, + * it needs to be of type CT_BRACE_OPEN or CT_BRACE_CLOSE, + * its parent type needs to be one of this types: + * CT_IF, CT_ELSEIF, CT_FOR, CT_USING_STMT, CT_WHILE, + * CT_FUNC_CLASS_DEF, CT_FUNC_DEF + * + * @return false: if preconditions are not met, + * if an error occurs while counting the newline between the + * parenthesis or + * when no newlines are found between the parenthesis + */ +static bool paren_multiline_before_brace(Chunk *brace) +{ + if ( brace == nullptr + || ( brace->IsNot(CT_BRACE_OPEN) + && brace->IsNot(CT_BRACE_CLOSE)) + || ( brace->GetParentType() != CT_IF + && brace->GetParentType() != CT_ELSEIF + && brace->GetParentType() != CT_FOR + && brace->GetParentType() != CT_USING_STMT + && brace->GetParentType() != CT_WHILE + && brace->GetParentType() != CT_FUNC_CLASS_DEF + && brace->GetParentType() != CT_FUNC_DEF)) + { + return(false); + } + const auto paren_t = CT_SPAREN_CLOSE; + + // find parenthesis pair of the if/for/while/... + auto paren_close = brace->GetPrevType(paren_t, brace->GetLevel(), E_Scope::ALL); + auto paren_open = paren_close->GetOpeningParen(); + + if ( paren_close->IsNullChunk() + || paren_open->IsNullChunk() + || paren_close == brace + || paren_open == paren_close) + { + return(false); + } + // determine number of lines in the parenthesis pair spans + auto nl_count = size_t{}; + const auto ret_flag = newlines_between(paren_open, paren_close, nl_count); + + if (!ret_flag) + { + LOG_FMT(LERR, "%s(%d): newlines_between error\n", __func__, __LINE__); + return(false); + } + // nl_count = 0 -> 1 line + return(nl_count > 0); +} + + +void do_braces() +{ + LOG_FUNC_ENTRY(); + // Mark one-liners + // Issue #2232 put this at the beginning + Chunk *pc = Chunk::GetHead()->GetNextNcNnl(); + + while (pc->IsNotNullChunk()) + { + if ( pc->IsNot(CT_BRACE_OPEN) + && pc->IsNot(CT_VBRACE_OPEN)) + { + pc = pc->GetNextNcNnl(); + continue; + } + Chunk *br_open = pc; + const E_Token brc_type = E_Token(pc->GetType() + 1); // corresponds to closing type + // Detect empty bodies + Chunk *tmp = pc->GetNextNcNnl(); + + if (tmp->Is(brc_type)) + { + br_open->SetFlagBits(PCF_EMPTY_BODY); + tmp->SetFlagBits(PCF_EMPTY_BODY); + } + // Scan for the brace close or a newline + tmp = br_open->GetNextNc(); + + while (tmp->IsNotNullChunk()) + { + if (tmp->IsNewline()) + { + break; + } + + if ( tmp->Is(brc_type) + && br_open->GetLevel() == tmp->GetLevel()) + { + flag_series(br_open, tmp, PCF_ONE_LINER); + break; + } + tmp = tmp->GetNextNc(); + } + pc = pc->GetNextNcNnl(); + } + log_rule_B("mod_full_brace_if_chain"); + log_rule_B("mod_full_brace_if_chain_only"); + + if ( options::mod_full_brace_if_chain() + || options::mod_full_brace_if_chain_only()) + { + mod_full_brace_if_chain(); + } + log_rule_B("mod_full_brace_if"); + log_rule_B("mod_full_brace_do"); + log_rule_B("mod_full_brace_for"); + log_rule_B("mod_full_brace_using"); + log_rule_B("mod_full_brace_while"); + + if ((options::mod_full_brace_if() | + options::mod_full_brace_do() | + options::mod_full_brace_for() | + options::mod_full_brace_using() | + options::mod_full_brace_while()) & IARF_REMOVE) + { + examine_braces(); + } + // convert vbraces if needed + log_rule_B("mod_full_brace_if"); + log_rule_B("mod_full_brace_do"); + log_rule_B("mod_full_brace_for"); + log_rule_B("mod_full_brace_function"); + log_rule_B("mod_full_brace_using"); + log_rule_B("mod_full_brace_while"); + + if ((options::mod_full_brace_if() | + options::mod_full_brace_do() | + options::mod_full_brace_for() | + options::mod_full_brace_function() | + options::mod_full_brace_using() | + options::mod_full_brace_while()) & IARF_ADD) + { + convert_vbrace_to_brace(); + } + log_rule_B("mod_case_brace"); + + if (options::mod_case_brace() != IARF_IGNORE) + { + mod_case_brace(); + } + log_rule_B("mod_move_case_break"); + + if (options::mod_move_case_break()) + { + move_case_break(); + } + log_rule_B("mod_move_case_return"); + + if (options::mod_move_case_return()) + { + move_case_return(); + } +} // do_braces + + +static void examine_braces() +{ + LOG_FUNC_ENTRY(); + + log_rule_B("mod_full_brace_nl_block_rem_mlcond"); + const auto multiline_block = options::mod_full_brace_nl_block_rem_mlcond(); + + log_rule_B("mod_full_brace_if"); + log_rule_B("mod_full_brace_do"); + log_rule_B("mod_full_brace_for"); + log_rule_B("mod_full_brace_using"); + log_rule_B("mod_full_brace_while"); + + for (Chunk *pc = Chunk::GetTail(); pc->IsNotNullChunk();) + { + Chunk *prev = pc->GetPrevType(CT_BRACE_OPEN); + + if ( pc->Is(CT_BRACE_OPEN) + && !pc->TestFlags(PCF_IN_PREPROC) + && ( ( ( pc->GetParentType() == CT_IF + || pc->GetParentType() == CT_ELSE + || pc->GetParentType() == CT_ELSEIF) + && options::mod_full_brace_if() == IARF_REMOVE) + || ( pc->GetParentType() == CT_DO + && options::mod_full_brace_do() == IARF_REMOVE) + || ( pc->GetParentType() == CT_FOR + && options::mod_full_brace_for() == IARF_REMOVE) + || ( pc->GetParentType() == CT_USING_STMT + && options::mod_full_brace_using() == IARF_REMOVE) + || ( pc->GetParentType() == CT_WHILE + && options::mod_full_brace_while() == IARF_REMOVE))) + { + if ( multiline_block + && paren_multiline_before_brace(pc)) + { + pc = prev; + continue; + } + examine_brace(pc); + } + pc = prev; + } +} // examine_braces + + +static bool should_add_braces(Chunk *vbopen) +{ + LOG_FUNC_ENTRY(); + log_rule_B("mod_full_brace_nl"); + const size_t nl_max = options::mod_full_brace_nl(); + + if (nl_max == 0) + { + return(false); + } + LOG_FMT(LBRDEL, "%s(%d): start on %zu:\n", + __func__, __LINE__, vbopen->GetOrigLine()); + + size_t nl_count = 0; + + Chunk *pc = Chunk::NullChunkPtr; + + for (pc = vbopen->GetNextNc(E_Scope::PREPROC); + (pc->IsNotNullChunk() && pc->GetLevel() > vbopen->GetLevel()); + pc = pc->GetNextNc(E_Scope::PREPROC)) + { + if (pc->IsNewline()) + { + nl_count += pc->GetNlCount(); + } + } + + if ( pc->IsNotNullChunk() + && nl_count > nl_max + && vbopen->GetPpLevel() == pc->GetPpLevel()) + { + LOG_FMT(LBRDEL, "%s(%d): exceeded %zu newlines\n", + __func__, __LINE__, nl_max); + return(true); + } + return(false); +} + + +static bool can_remove_braces(Chunk *bopen) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LBRDEL, "%s(%d): start on line %zu:\n", + __func__, __LINE__, bopen->GetOrigLine()); + + // Cannot remove braces inside a preprocessor + if (bopen->TestFlags(PCF_IN_PREPROC)) + { + return(false); + } + Chunk *pc = bopen->GetNextNcNnl(E_Scope::PREPROC); + + if (pc->Is(CT_BRACE_CLOSE)) + { + // Can't remove empty statement + return(false); + } + const size_t level = bopen->GetLevel() + 1; + + log_rule_B("mod_full_brace_nl"); + const size_t nl_max = options::mod_full_brace_nl(); + Chunk *prev = Chunk::NullChunkPtr; + + size_t semi_count = 0; + bool hit_semi = false; + size_t nl_count = 0; + size_t if_count = 0; + int br_count = 0; + + pc = bopen->GetNextNc(E_Scope::ALL); + LOG_FMT(LBRDEL, "%s(%d): - begin with token '%s', orig line is %zu, orig col is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + + while ( pc->IsNotNullChunk() + && pc->GetLevel() >= level) + { + LOG_FMT(LBRDEL, "%s(%d): test token '%s', orig line is %zu, orig col is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + + if (pc->TestFlags(PCF_IN_PREPROC)) + { + // Cannot remove braces that contain a preprocessor + return(false); + } + + if (pc->IsNewline()) + { + nl_count += pc->GetNlCount(); + + if ( nl_max > 0 + && nl_count > nl_max) + { + LOG_FMT(LBRDEL, "%s(%d): exceeded %zu newlines\n", + __func__, __LINE__, nl_max); + return(false); + } + } + else + { + if (pc->Is(CT_BRACE_OPEN)) + { + br_count++; + } + else if (pc->Is(CT_BRACE_CLOSE)) + { + if (br_count == 0) + { + fprintf(stderr, "%s(%d): br_count is ZERO, cannot be decremented, at line %zu, column %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + br_count--; + + if (pc->GetLevel() == level) + { + // mean a statement in a braces { stmt; } + // as a statement with a semicolon { stmt; }; + ++semi_count; + hit_semi = true; + } + } + else if ( ( pc->Is(CT_IF) + || pc->Is(CT_ELSEIF)) + && br_count == 0) + { + if_count++; + } + + if (pc->GetLevel() == level) + { + if ( semi_count > 0 + && hit_semi) + { + // should have bailed due to close brace level drop + LOG_FMT(LBRDEL, "%s(%d): no close brace\n", __func__, __LINE__); + return(false); + } + LOG_FMT(LBRDEL, "%s(%d): Text() '%s', orig line is %zu, semi_count is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), semi_count); + + if (pc->Is(CT_ELSE)) + { + LOG_FMT(LBRDEL, "%s(%d): bailed on '%s' on line %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine()); + return(false); + } + + if ( pc->IsSemicolon() + || pc->Is(CT_IF) + || pc->Is(CT_ELSEIF) + || pc->Is(CT_FOR) + || pc->Is(CT_DO) + || pc->Is(CT_WHILE) + || pc->Is(CT_USING_STMT) + || ( pc->Is(CT_BRACE_OPEN) + && prev->Is(CT_FPAREN_CLOSE))) + { + hit_semi |= pc->IsSemicolon(); + + if (++semi_count > 1) + { + LOG_FMT(LBRDEL, "%s(%d): bailed on %zu because of '%s' on line %zu\n", + __func__, __LINE__, bopen->GetOrigLine(), pc->Text(), pc->GetOrigLine()); + return(false); + } + } + } + } + prev = pc; + pc = pc->GetNextNc(); + } + + if (pc->IsNullChunk()) + { + LOG_FMT(LBRDEL, "%s(%d): pc is null chunk\n", __func__, __LINE__); + return(false); + } + + if ( pc->Is(CT_BRACE_CLOSE) + && pc->GetParentType() == CT_IF) + { + Chunk *next = pc->GetNextNcNnl(E_Scope::PREPROC); + Chunk *tmp_prev = pc->GetPrevNcNnl(E_Scope::PREPROC); + + if ( next->Is(CT_ELSE) + && tmp_prev->IsBraceClose() + && tmp_prev->GetParentType() == CT_IF) + { + LOG_FMT(LBRDEL, "%s(%d): - bailed on '%s'[%s] on line %zu due to 'if' and 'else' sequence\n", + __func__, __LINE__, get_token_name(pc->GetType()), get_token_name(pc->GetParentType()), + pc->GetOrigLine()); + return(false); + } + } + LOG_FMT(LBRDEL, "%s(%d): - end on '%s' on line %zu. if_count is %zu semi_count is %zu\n", + __func__, __LINE__, get_token_name(pc->GetType()), pc->GetOrigLine(), if_count, semi_count); + + return( pc->Is(CT_BRACE_CLOSE) + && pc->GetPpLevel() == bopen->GetPpLevel()); +} // can_remove_braces + + +static void examine_brace(Chunk *bopen) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LBRDEL, "%s(%d): start on orig line %zu, bopen->GetLevel() is %zu\n", + __func__, __LINE__, bopen->GetOrigLine(), bopen->GetLevel()); + + const size_t level = bopen->GetLevel() + 1; + + log_rule_B("mod_full_brace_nl"); + const size_t nl_max = options::mod_full_brace_nl(); + + Chunk *prev = Chunk::NullChunkPtr; + size_t semi_count = 0; + bool hit_semi = false; + size_t nl_count = 0; + size_t if_count = 0; + int br_count = 0; + + Chunk *pc = bopen->GetNextNc(); + + while ( pc->IsNotNullChunk() + && pc->GetLevel() >= level) + { + if (pc->Is(CT_NEWLINE)) + { + LOG_FMT(LBRDEL, "%s(%d): orig line is %zu, orig col is %zu, <Newline>\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + } + else + { + LOG_FMT(LBRDEL, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + } + + if (pc->TestFlags(PCF_IN_PREPROC)) + { + // Cannot remove braces that contain a preprocessor + LOG_FMT(LBRDEL, "%s(%d): PREPROC\n", __func__, __LINE__); + return; + } + + if (pc->IsNewline()) + { + nl_count += pc->GetNlCount(); + + if ( nl_max > 0 + && nl_count > nl_max) + { + LOG_FMT(LBRDEL, "%s(%d): exceeded %zu newlines\n", + __func__, __LINE__, nl_max); + return; + } + } + else + { + LOG_FMT(LBRDEL, "%s(%d): for pc->Text() '%s', pc->GetLevel() is %zu, bopen->GetLevel() is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetLevel(), bopen->GetLevel()); + + if ( pc->Is(CT_BRACE_OPEN) + && pc->GetLevel() == bopen->GetLevel()) + { + br_count++; + LOG_FMT(LBRDEL, "%s(%d): br_count is now %d, pc->GetLevel() is %zu, bopen->GetLevel() is %zu\n", + __func__, __LINE__, br_count, pc->GetLevel(), bopen->GetLevel()); + } + else if ( pc->Is(CT_BRACE_CLOSE) + && pc->GetLevel() == bopen->GetLevel()) + { + if (br_count == 0) + { + fprintf(stderr, "%s(%d): br_count is ZERO, cannot be decremented, at line %zu, column %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + br_count--; + LOG_FMT(LBRDEL, "%s(%d): br_count is now %d, pc->GetLevel() is %zu, bopen->GetLevel() is %zu\n", + __func__, __LINE__, br_count, pc->GetLevel(), bopen->GetLevel()); + + if (br_count == 0) + { + Chunk *next = pc->GetNextNcNnl(E_Scope::PREPROC); + + if ( next->IsNullChunk() + || next->IsNot(CT_BRACE_CLOSE)) + { + LOG_FMT(LBRDEL, "%s(%d): junk after close brace\n", __func__, __LINE__); + return; + } + } + } + else if ( ( pc->Is(CT_IF) + || pc->Is(CT_ELSEIF)) + && br_count == 0) + { + if_count++; + } + LOG_FMT(LBRDEL, "%s(%d): pc->GetLevel() is %zu, level is %zu\n", + __func__, __LINE__, pc->GetLevel(), level); + + if (pc->GetLevel() == level) + { + if ( semi_count > 0 + && hit_semi) + { + // should have bailed due to close brace level drop + LOG_FMT(LBRDEL, "%s(%d): no close brace\n", __func__, __LINE__); + return; + } + LOG_FMT(LBRDEL, "%s(%d): Text() '%s', orig line is %zu, semi_count is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), semi_count); + + if (pc->Is(CT_ELSE)) + { + LOG_FMT(LBRDEL, "%s(%d): bailed on '%s' on line %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine()); + return; + } + + if (prev->IsNotNullChunk()) + { + LOG_FMT(LBRDEL, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', prev->Text '%s', prev->GetType() %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), prev->Text(), get_token_name(prev->GetType())); + } + else + { + LOG_FMT(LBRDEL, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', prev is a null chunk\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + } + LOG_FMT(LBRDEL, "%s(%d): for pc->Text() '%s', pc->GetLevel() is %zu, bopen->GetLevel() is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetLevel(), bopen->GetLevel()); + + if ( pc->IsSemicolon() + || pc->Is(CT_IF) + || pc->Is(CT_ELSEIF) + || pc->Is(CT_FOR) + || pc->Is(CT_DO) + || pc->Is(CT_WHILE) + || pc->Is(CT_SWITCH) + || pc->Is(CT_USING_STMT) + || ( pc->Is(CT_BRACE_OPEN) + && pc->GetLevel() == bopen->GetLevel())) // Issue #1758 + { + LOG_FMT(LBRDEL, "%s(%d): pc->Text() '%s', orig line is %zu, orig col is %zu, level is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol(), pc->GetLevel()); + hit_semi |= pc->IsSemicolon(); + semi_count++; + LOG_FMT(LBRDEL, "%s(%d): semi_count is %zu\n", + __func__, __LINE__, semi_count); + + if (semi_count > 1) + { + LOG_FMT(LBRDEL, "%s(%d): bailed on %zu because of '%s' on line %zu\n", + __func__, __LINE__, bopen->GetOrigLine(), pc->Text(), pc->GetOrigLine()); + return; + } + } + } + } + prev = pc; + pc = pc->GetNext(); // Issue #1907 + } + + if (pc->IsNullChunk()) + { + LOG_FMT(LBRDEL, "%s(%d): pc is nullptr\n", __func__, __LINE__); + return; + } + LOG_FMT(LBRDEL, "%s(%d): - end on '%s' on line %zu. if_count is %zu, semi_count is %zu\n", + __func__, __LINE__, get_token_name(pc->GetType()), pc->GetOrigLine(), if_count, semi_count); + + if (pc->Is(CT_BRACE_CLOSE)) + { + Chunk *next = pc->GetNextNcNnl(); + + if (next->IsNotNullChunk()) + { + while (next->Is(CT_VBRACE_CLOSE)) + { + next = next->GetNextNcNnl(); + } + + if (next->IsNotNullChunk()) + { + LOG_FMT(LBRDEL, "%s(%d): orig line is %zu, orig col is %zu, next is '%s'\n", + __func__, __LINE__, next->GetOrigLine(), next->GetOrigCol(), get_token_name(next->GetType())); + } + + if ( if_count > 0 + && ( next->Is(CT_ELSE) + || next->Is(CT_ELSEIF))) + { + LOG_FMT(LBRDEL, "%s(%d): bailed on because 'else' is next and %zu ifs\n", + __func__, __LINE__, if_count); + return; + } + } + LOG_FMT(LBRDEL, "%s(%d): semi_count is %zu\n", + __func__, __LINE__, semi_count); + + if (semi_count > 0) + { + LOG_FMT(LBRDEL, "%s(%d): bopen->GetParentType() is %s\n", + __func__, __LINE__, get_token_name(bopen->GetParentType())); + + if (bopen->GetParentType() == CT_ELSE) + { + Chunk *tmp_next = bopen->GetNextNcNnl(); + + if (tmp_next->Is(CT_IF)) + { + Chunk *tmp_prev = bopen->GetPrevNcNnl(); + LOG_FMT(LBRDEL, "%s(%d): else-if removing braces on line %zu and %zu\n", + __func__, __LINE__, bopen->GetOrigLine(), pc->GetOrigLine()); + + Chunk::Delete(bopen); + Chunk::Delete(pc); + newline_del_between(tmp_prev, tmp_next); + + log_rule_B("nl_else_if"); + + if (options::nl_else_if() & IARF_ADD) + { + newline_add_between(tmp_prev, tmp_next); + } + return; + } + } + // we have a pair of braces with only 1 statement inside + LOG_FMT(LBRDEL, "%s(%d): we have a pair of braces with only 1 statement inside\n", + __func__, __LINE__); + LOG_FMT(LBRDEL, "%s(%d): removing braces on line %zu and %zu\n", + __func__, __LINE__, bopen->GetOrigLine(), pc->GetOrigLine()); + convert_brace(bopen); + convert_brace(pc); + } + else + { + LOG_FMT(LBRDEL, "%s(%d): empty statement\n", __func__, __LINE__); + } + } + else + { + LOG_FMT(LBRDEL, "%s(%d): not a close brace? - '%s'\n", + __func__, __LINE__, pc->Text()); + } +} // examine_brace + + +static void convert_brace(Chunk *br) +{ + LOG_FUNC_ENTRY(); + + if ( br == nullptr + || br->TestFlags(PCF_KEEP_BRACE)) + { + return; + } + Chunk *tmp; + + if (br->Is(CT_BRACE_OPEN)) + { + br->SetType(CT_VBRACE_OPEN); + br->Str().clear(); + tmp = br->GetPrev(); + + if (tmp->IsNullChunk()) + { + return; + } + } + else if (br->Is(CT_BRACE_CLOSE)) + { + br->SetType(CT_VBRACE_CLOSE); + br->Str().clear(); + tmp = br->GetNext(); + + if (tmp->IsNullChunk()) + { + return; + } + } + else + { + return; + } + + if (tmp->IsNewline()) + { + if (tmp->GetNlCount() > 1) + { + if (!br->TestFlags(PCF_ONE_LINER)) // Issue #2232 + { + tmp->SetNlCount(tmp->GetNlCount() - 1); + LOG_FMT(LBRDEL, "%s(%d): tmp new line count is %zu\n", + __func__, __LINE__, tmp->GetNlCount()); + } + } + else + { + // Issue #2219 + // look for opening brace + Chunk *brace = Chunk::NullChunkPtr; + + if (br->Is(CT_VBRACE_OPEN)) + { + brace = tmp; + } + else if (br->Is(CT_VBRACE_CLOSE)) + { + brace = br->GetOpeningParen(); + + if (brace->IsNullChunk()) + { + brace = br->GetPrevType(CT_BRACE_OPEN, br->GetLevel()); + } + } + + if ( br->Is(CT_VBRACE_OPEN) + || ( br->Is(CT_VBRACE_CLOSE) + && brace->GetOrigLine() < tmp->GetOrigLine())) + { + if (tmp->SafeToDeleteNl()) + { + Chunk::Delete(tmp); + } + } + } + } +} // convert_brace + + +static void convert_vbrace(Chunk *vbr) +{ + LOG_FUNC_ENTRY(); + + if (vbr == nullptr) + { + return; + } + + if (vbr->Is(CT_VBRACE_OPEN)) + { + vbr->SetType(CT_BRACE_OPEN); + vbr->Str() = "{"; + + /* + * If the next chunk is a preprocessor, then move the open brace after the + * preprocessor. + */ + Chunk *tmp = vbr->GetNext(); + + if (tmp->Is(CT_PREPROC)) + { + tmp = vbr->GetNext(E_Scope::PREPROC); + vbr->MoveAfter(tmp); + newline_add_after(vbr); + } + } + else if (vbr->Is(CT_VBRACE_CLOSE)) + { + vbr->SetType(CT_BRACE_CLOSE); + vbr->Str() = "}"; + + /* + * If the next chunk is a comment, followed by a newline, then + * move the brace after the newline and add another newline after + * the close brace, unless we're keeping a one-liner. + */ + Chunk *tmp = vbr->GetNext(); + + if ( tmp->IsComment() + && ( !vbr->TestFlags(PCF_ONE_LINER) + || !options::nl_if_leave_one_liners())) + { + tmp = tmp->GetNext(); + + if (tmp->IsNewline()) + { + vbr->MoveAfter(tmp); + newline_add_after(vbr); + } + } + } +} // convert_vbrace + + +static void convert_vbrace_to_brace() +{ + LOG_FUNC_ENTRY(); + + // Find every vbrace open + log_rule_B("mod_full_brace_if"); + log_rule_B("mod_full_brace_if_chain"); + log_rule_B("mod_full_brace_for"); + log_rule_B("mod_full_brace_do"); + log_rule_B("mod_full_brace_while"); + log_rule_B("mod_full_brace_using"); + log_rule_B("mod_full_brace_function"); + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + if (pc->IsNot(CT_VBRACE_OPEN)) + { + continue; + } + auto const in_preproc = pc->TestFlags(PCF_IN_PREPROC); + + if ( ( ( pc->GetParentType() == CT_IF + || pc->GetParentType() == CT_ELSE + || pc->GetParentType() == CT_ELSEIF) + && (options::mod_full_brace_if() & IARF_ADD) + && !options::mod_full_brace_if_chain()) + || ( pc->GetParentType() == CT_FOR + && (options::mod_full_brace_for() & IARF_ADD)) + || ( pc->GetParentType() == CT_DO + && (options::mod_full_brace_do() & IARF_ADD)) + || ( pc->GetParentType() == CT_WHILE + && (options::mod_full_brace_while() & IARF_ADD)) + || ( pc->GetParentType() == CT_USING_STMT + && (options::mod_full_brace_using() & IARF_ADD)) + || ( pc->GetParentType() == CT_FUNC_DEF + && (options::mod_full_brace_function() & IARF_ADD))) + { + // Find the matching vbrace close + Chunk *vbc = Chunk::NullChunkPtr; + Chunk *tmp = pc->GetNext(); + + while (tmp->IsNotNullChunk()) + { + if ( in_preproc + && !tmp->TestFlags(PCF_IN_PREPROC)) + { + // Can't leave a preprocessor + break; + } + + if ( pc->GetBraceLevel() == tmp->GetBraceLevel() + && tmp->Is(CT_VBRACE_CLOSE) + && pc->GetParentType() == tmp->GetParentType() + && ((tmp->GetFlags() & PCF_IN_PREPROC) == (pc->GetFlags() & PCF_IN_PREPROC))) + { + vbc = tmp; + break; + } + tmp = tmp->GetNext(); + } + + if (vbc->IsNullChunk()) + { + continue; + } + // if we found a corresponding virtual closing brace + convert_vbrace(pc); // convert both the opening + convert_vbrace(vbc); // and closing brace + } + } +} // convert_vbrace_to_brace + + +Chunk *insert_comment_after(Chunk *ref, E_Token cmt_type, + const unc_text &cmt_text) +{ + LOG_FUNC_ENTRY(); + + Chunk new_cmt = *ref; + + new_cmt.SetFlags(ref->GetFlags() & PCF_COPY_FLAGS); + new_cmt.SetType(cmt_type); + new_cmt.Str().clear(); + + if (cmt_type == CT_COMMENT_CPP) + { + new_cmt.Str().append("// "); + new_cmt.Str().append(cmt_text); + } + else + { + if (ref->Is(CT_PP_ELSE)) + { // make test c/ 02501 stable + new_cmt.Str().append(" "); + } + new_cmt.Str().append("/* "); + new_cmt.Str().append(cmt_text); + new_cmt.Str().append(" */"); + } + // TODO: expand comment type to cover other comment styles? + + new_cmt.SetColumn(ref->GetColumn() + ref->Len() + 1); + new_cmt.SetOrigCol(new_cmt.GetColumn()); + + return(new_cmt.CopyAndAddAfter(ref)); +} + + +static void append_tag_name(unc_text &txt, Chunk *pc) +{ + LOG_FUNC_ENTRY(); + Chunk *tmp = pc->GetPrevNcNnl(); + + LOG_FMT(LMCB, "%s(%d): txt is '%s'\n", + __func__, __LINE__, txt.c_str()); + + // step backwards over all a::b stuff + while (tmp->IsNotNullChunk()) + { + if ( tmp->IsNot(CT_DC_MEMBER) + && tmp->IsNot(CT_MEMBER)) + { + break; + } + tmp = tmp->GetPrevNcNnl(); + pc = tmp; + + if (!tmp->IsWord()) + { + break; + } + } + txt += pc->GetStr(); + LOG_FMT(LMCB, "%s(%d): txt is '%s'\n", + __func__, __LINE__, txt.c_str()); + + pc = pc->GetNextNcNnl(); + + while (pc->IsNotNullChunk()) + { + if ( pc->IsNot(CT_DC_MEMBER) + && pc->IsNot(CT_MEMBER)) + { + break; + } + txt += pc->GetStr(); + LOG_FMT(LMCB, "%s(%d): txt is '%s'\n", + __func__, __LINE__, txt.c_str()); + pc = pc->GetNextNcNnl(); + + if (pc->IsNotNullChunk()) + { + txt += pc->GetStr(); + LOG_FMT(LMCB, "%s(%d): txt is '%s'\n", + __func__, __LINE__, txt.c_str()); + } + pc = pc->GetNextNcNnl(); + } +} // append_tag_name + + +void add_long_closebrace_comment() +{ + LOG_FUNC_ENTRY(); + Chunk *fcn_pc = Chunk::NullChunkPtr; + Chunk *sw_pc = Chunk::NullChunkPtr; + Chunk *ns_pc = Chunk::NullChunkPtr; + Chunk *cl_pc = Chunk::NullChunkPtr; + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + if ( pc->Is(CT_FUNC_DEF) + || pc->Is(CT_OC_MSG_DECL)) + { + fcn_pc = pc; + } + else if (pc->Is(CT_SWITCH)) + { + // pointless, since it always has the text "switch" + sw_pc = pc; + } + else if (pc->Is(CT_NAMESPACE)) + { + ns_pc = pc; + } + else if (pc->Is(CT_CLASS)) + { + cl_pc = pc; + } + + if ( pc->IsNot(CT_BRACE_OPEN) + || pc->TestFlags(PCF_IN_PREPROC)) + { + continue; + } + Chunk *br_open = pc; + size_t nl_count = 0; + + Chunk *tmp = pc; + + while ((tmp = tmp->GetNext(E_Scope::PREPROC))->IsNotNullChunk()) + { + if (tmp->IsNewline()) + { + nl_count += tmp->GetNlCount(); + continue; + } + + // handle only matching closing braces, skip other chunks + if ( tmp->GetLevel() != br_open->GetLevel() + || tmp->IsNot(CT_BRACE_CLOSE)) + { + continue; + } + Chunk *br_close = tmp; + + tmp = tmp->GetNext(); + + // check for a possible end semicolon + if (tmp->Is(CT_SEMICOLON)) + { + // set br_close to the semi token, + // as br_close is used to add the comment after it + br_close = tmp; + tmp = tmp->GetNext(); + } + + // make sure a newline follows in order to not overwrite an already + // existring comment + if ( tmp->IsNotNullChunk() + && !tmp->IsNewline()) + { + break; + } + size_t nl_min = 0; + Chunk *tag_pc = Chunk::NullChunkPtr; + unc_text xstr; + + if ( br_open->GetParentType() == CT_FUNC_DEF + || br_open->GetParentType() == CT_OC_MSG_DECL) + { + log_rule_B("mod_add_long_function_closebrace_comment"); + nl_min = options::mod_add_long_function_closebrace_comment(); + tag_pc = fcn_pc; + + if (tag_pc->IsNotNullChunk()) + { + append_tag_name(xstr, tag_pc); + LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n", + __func__, __LINE__, xstr.c_str()); + } + } + else if ( br_open->GetParentType() == CT_SWITCH + && sw_pc != nullptr) + { + log_rule_B("mod_add_long_switch_closebrace_comment"); + nl_min = options::mod_add_long_switch_closebrace_comment(); + tag_pc = sw_pc; + xstr = sw_pc->GetStr(); + LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n", + __func__, __LINE__, xstr.c_str()); + } + else if ( br_open->GetParentType() == CT_NAMESPACE + && ns_pc != nullptr) + { + log_rule_B("mod_add_long_namespace_closebrace_comment"); + nl_min = options::mod_add_long_namespace_closebrace_comment(); + tag_pc = ns_pc; + xstr = tag_pc->GetStr(); // add 'namespace' to the string + LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n", + __func__, __LINE__, xstr.c_str()); + + // next chunk, normally is going to be the namespace name + // append it with a space to generate "namespace xyz" + Chunk *tmp_next = tag_pc->GetNextNcNnl(); + + if (tmp_next->IsNot(CT_BRACE_OPEN)) // anonymous namespace -> ignore + { + xstr.append(" "); + LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n", + __func__, __LINE__, xstr.c_str()); + append_tag_name(xstr, tmp_next); + LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n", + __func__, __LINE__, xstr.c_str()); + } + } + else if ( br_open->GetParentType() == CT_CLASS + && cl_pc->IsNotNullChunk() + && ( !language_is_set(LANG_CPP) // proceed if not C++ + || br_close->Is(CT_SEMICOLON))) // else a C++ class needs to end with a semicolon + { + log_rule_B("mod_add_long_class_closebrace_comment"); + nl_min = options::mod_add_long_class_closebrace_comment(); + tag_pc = cl_pc; + xstr = tag_pc->GetStr(); + LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n", + __func__, __LINE__, xstr.c_str()); + + Chunk *tmp_next = cl_pc->GetNext(); + + if (tag_pc->IsNotNullChunk()) + { + xstr.append(" "); + LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n", + __func__, __LINE__, xstr.c_str()); + append_tag_name(xstr, tmp_next); + LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n", + __func__, __LINE__, xstr.c_str()); + } + } + + if ( nl_min > 0 + && nl_count >= nl_min + && tag_pc->IsNotNullChunk()) + { + // use the comment style that fits to the selected language + const E_Token style = language_is_set(LANG_CPP | LANG_CS) + ? CT_COMMENT_CPP : CT_COMMENT; + + // Add a comment after the close brace + LOG_FMT(LMCB, "%s(%d): xstr is '%s'\n", + __func__, __LINE__, xstr.c_str()); + insert_comment_after(br_close, style, xstr); + } + break; + } + } +} // add_long_closebrace_comment + + +static void move_case_break() +{ + LOG_FUNC_ENTRY(); + Chunk *prev = Chunk::NullChunkPtr; + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + if ( pc->Is(CT_BREAK) + && prev->Is(CT_BRACE_CLOSE) + && prev->GetParentType() == CT_CASE + && pc->GetPrev()->IsNewline() + && prev->GetPrev()->IsNewline()) + { + prev->SwapLines(pc); + } + prev = pc; + } +} + + +static void move_case_return() +{ + LOG_FUNC_ENTRY(); + Chunk *prev = Chunk::NullChunkPtr; + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + if ( pc->Is(CT_RETURN) + && prev->Is(CT_BRACE_CLOSE) + && prev->GetParentType() == CT_CASE + && pc->GetPrev()->IsNewline() + && prev->GetPrev()->IsNewline()) + { + // Find the end of the return statement + while (pc->IsNot(CT_SEMICOLON)) + { + if ( pc->Is(CT_CASE) + || pc->Is(CT_BRACE_CLOSE)) + { + // This may indicate a semicolon was missing in the code to format. + // Avoid moving the return statement to prevent potential unwanted errors. + pc = Chunk::NullChunkPtr; + break; + } + pc = pc->GetNext(); + } + pc = pc->GetNextNl(); + pc = pc->GetNextNcNnl(); + + if (pc->IsNotNullChunk()) + { + // Swap all lines between brace close and current token + LOG_FMT(LMCB, "%s(%d): move line %zu before line %zu\n", + __func__, __LINE__, prev->GetOrigLine(), pc->GetOrigLine()); + Chunk *curr = prev->GetNextNcNnl(); + + while (curr != pc) + { + prev->SwapLines(curr); + curr = prev->GetNextNcNnl(); + } + } + } + prev = pc; + } +} // move_case_return + + +static Chunk *mod_case_brace_remove(Chunk *br_open) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LMCB, "%s(%d): line %zu", + __func__, __LINE__, br_open->GetOrigLine()); + + // Find the matching brace close + Chunk *next = br_open->GetNextNcNnl(E_Scope::PREPROC); + Chunk *br_close = br_open->GetNextType(CT_BRACE_CLOSE, br_open->GetLevel(), E_Scope::PREPROC); + + if (br_close->IsNullChunk()) + { + LOG_FMT(LMCB, "%s(%d): - no close\n", __func__, __LINE__); + return(next); + } + // Make sure 'break', 'return', 'goto', 'case' or '}' is after the close brace + Chunk *pc = br_close->GetNextNcNnl(E_Scope::PREPROC); + + if ( pc->IsNullChunk() + || ( pc->IsNot(CT_BREAK) + && pc->IsNot(CT_RETURN) + && pc->IsNot(CT_CASE) + && pc->IsNot(CT_GOTO) + && pc->IsNot(CT_BRACE_CLOSE))) + { + LOG_FMT(LMCB, "%s(%d): - after '%s'\n", + __func__, __LINE__, (pc == nullptr) ? "<null>" : get_token_name(pc->GetType())); + return(next); + } + + // scan to make sure there are no definitions at brace level between braces + for (Chunk *tmp_pc = br_open; + tmp_pc != br_close; + tmp_pc = tmp_pc->GetNextNcNnl(E_Scope::PREPROC)) + { + if ( tmp_pc->GetLevel() == (br_open->GetLevel() + 1) + && tmp_pc->TestFlags(PCF_VAR_DEF)) + { + LOG_FMT(LMCB, "%s(%d): - vardef on line %zu: '%s'\n", + __func__, __LINE__, tmp_pc->GetOrigLine(), pc->Text()); + return(next); + } + } + + LOG_FMT(LMCB, "%s(%d): - removing braces on lines %zu and %zu\n", + __func__, __LINE__, br_open->GetOrigLine(), br_close->GetOrigLine()); + + for (Chunk *tmp_pc = br_open; + tmp_pc != br_close; + tmp_pc = tmp_pc->GetNextNcNnl(E_Scope::PREPROC)) + { + if (tmp_pc->GetBraceLevel() == 0) + { + fprintf(stderr, "%s(%d): brace level is ZERO, cannot be decremented, at line %zu, column %zu\n", + __func__, __LINE__, tmp_pc->GetOrigLine(), tmp_pc->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + tmp_pc->SetBraceLevel(tmp_pc->GetBraceLevel() - 1); + + if (tmp_pc->GetLevel() == 0) + { + fprintf(stderr, "%s(%d): tmp_pc->GetLevel() is ZERO, cannot be decremented, at line %zu, column %zu\n", + __func__, __LINE__, tmp_pc->GetOrigLine(), tmp_pc->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + tmp_pc->SetLevel(tmp_pc->GetLevel() - 1); + } + + next = br_open->GetPrev(E_Scope::PREPROC); + + Chunk::Delete(br_open); + Chunk::Delete(br_close); + + return(next->GetNext(E_Scope::PREPROC)); +} // mod_case_brace_remove + + +static Chunk *mod_case_brace_add(Chunk *cl_colon) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LMCB, "%s(%d): orig line %zu, orig col is %zu\n", + __func__, __LINE__, cl_colon->GetOrigLine(), cl_colon->GetOrigCol()); + + Chunk *pc = cl_colon; + Chunk *last = Chunk::NullChunkPtr; + // look for the case token to the colon + Chunk *cas_ = cl_colon->GetPrevType(CT_CASE, cl_colon->GetLevel()); + // look for the parent + Chunk *swit = cas_->GetParent(); + // look for the opening brace of the switch + Chunk *open = swit->GetNextType(CT_BRACE_OPEN, swit->GetLevel()); + // look for the closing brace of the switch + Chunk *clos = open->GetClosingParen(); + + // find the end of the case-block + pc = pc->GetNextNcNnl(E_Scope::PREPROC); + + while (pc->IsNotNullChunk()) + { + LOG_FMT(LMCB, "%s(%d): Text() is '%s', orig line %zu, orig col is %zu, pp level is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol(), pc->GetPpLevel()); + + if (pc->GetLevel() == cl_colon->GetLevel()) + { + if (pc->Is(CT_CASE)) + { + LOG_FMT(LMCB, "%s(%d): Text() is '%s', orig line %zu, orig col is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + last = calculate_closing_brace_position(cl_colon, pc); + break; + } + } + else if (pc->GetLevel() == cl_colon->GetLevel() - 1) + { + if (pc == clos) + { + LOG_FMT(LMCB, "%s(%d): Text() is '%s', orig line %zu, orig col is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + // end of switch is reached + last = calculate_closing_brace_position(cl_colon, pc); + LOG_FMT(LMCB, "%s(%d): last->Text() is '%s', orig line %zu, orig col is %zu\n", + __func__, __LINE__, last->Text(), last->GetOrigLine(), last->GetOrigCol()); + break; + } + } + pc = pc->GetNextNcNnl(E_Scope::PREPROC); + } + + if (last->IsNullChunk()) + { + LOG_FMT(LMCB, "%s(%d): - last is null chunk\n", __func__, __LINE__); + Chunk *next = cl_colon->GetNextNcNnl(E_Scope::PREPROC); + return(next); + } + LOG_FMT(LMCB, "%s(%d): last->Text() is '%s', orig line %zu, orig col is %zu\n", + __func__, __LINE__, last->Text(), last->GetOrigLine(), last->GetOrigCol()); + LOG_FMT(LMCB, "%s(%d): adding braces after '%s' on line %zu\n", + __func__, __LINE__, cl_colon->Text(), cl_colon->GetOrigLine()); + + Chunk chunk; + + chunk.SetType(CT_BRACE_OPEN); + chunk.SetParentType(CT_CASE); + chunk.SetOrigLine(cl_colon->GetOrigLine()); + chunk.SetOrigCol(cl_colon->GetOrigCol()); + chunk.SetLevel(cl_colon->GetLevel()); + chunk.SetPpLevel(cl_colon->GetPpLevel()); + chunk.SetBraceLevel(cl_colon->GetBraceLevel()); + chunk.SetFlags(pc->GetFlags() & PCF_COPY_FLAGS); + chunk.Str() = "{"; + Chunk *br_open = chunk.CopyAndAddAfter(cl_colon); + + chunk.SetType(CT_BRACE_CLOSE); + chunk.SetOrigLine(last->GetOrigLine()); + chunk.SetOrigCol(last->GetOrigCol()); + chunk.Str() = "}"; + Chunk *br_close = chunk.CopyAndAddAfter(last); + + for (pc = br_open->GetNext(E_Scope::PREPROC); + pc != br_close; + pc = pc->GetNext(E_Scope::PREPROC)) + { + pc->SetLevel(pc->GetLevel() + 1); + pc->SetBraceLevel(pc->GetBraceLevel() + 1); + } + + return(br_open); +} // mod_case_brace_add + + +static void mod_case_brace() +{ + LOG_FUNC_ENTRY(); + + Chunk *pc = Chunk::GetHead(); + + // Make sure to start outside of a preprocessor line (see issue #3366) + if (pc->IsPreproc()) + { + pc = pc->GetNextNcNnlNpp(); + } + + while ( pc != nullptr + && pc->IsNotNullChunk()) + { + Chunk *next = pc->GetNextNcNnl(E_Scope::PREPROC); + + if (next->IsNullChunk()) + { + return; + } + log_rule_B("mod_case_brace"); + + if ( options::mod_case_brace() == IARF_REMOVE + && pc->Is(CT_BRACE_OPEN) + && pc->GetParentType() == CT_CASE) + { + log_rule_B("mod_case_brace - add"); + pc = mod_case_brace_remove(pc); + } + else if ( (options::mod_case_brace() & IARF_ADD) + && pc->Is(CT_CASE_COLON) + && next->IsNot(CT_BRACE_OPEN) + && next->IsNot(CT_BRACE_CLOSE) + && next->IsNot(CT_CASE)) + { + log_rule_B("mod_case_brace - remove"); + pc = mod_case_brace_add(pc); + } + else + { + pc = pc->GetNextNcNnl(E_Scope::PREPROC); + } + } +} // mod_case_brace + + +static void process_if_chain(Chunk *br_start) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LBRCH, "%s(%d): if starts on line %zu, orig col is %zu.\n", + __func__, __LINE__, br_start->GetOrigLine(), br_start->GetOrigCol()); + + vector<Chunk *> braces; + + braces.reserve(16); + + bool must_have_braces = false; + bool has_unbraced_block = false; + + Chunk *pc = br_start; + + while ( pc != nullptr + && pc->IsNotNullChunk()) + { + LOG_CHUNK(LTOK, pc); + + if (pc->Is(CT_BRACE_OPEN)) + { + const bool tmp = can_remove_braces(pc); + LOG_FMT(LBRCH, "%s(%d): braces.size() is %zu, line is %zu, - can%s remove %s\n", + __func__, __LINE__, braces.size(), pc->GetOrigLine(), tmp ? "" : "not", + get_token_name(pc->GetType())); + + if ( !tmp + || options::mod_full_brace_if_chain() == 2) + { + must_have_braces = true; + } + } + else + { + const bool tmp = should_add_braces(pc); + + if (tmp) + { + must_have_braces = true; + } + LOG_FMT(LBRCH, "%s(%d): braces.size() is %zu, line is %zu, - %s %s\n", + __func__, __LINE__, braces.size(), pc->GetOrigLine(), tmp ? "should add" : "ignore", + get_token_name(pc->GetType())); + + has_unbraced_block = true; + } + + if ( options::mod_full_brace_if_chain() == 3 + && !has_unbraced_block) + { + must_have_braces = true; + } + braces.push_back(pc); + Chunk *br_close = pc->GetClosingParen(E_Scope::PREPROC); + + if (br_close->IsNullChunk()) + { + break; + } + braces.push_back(br_close); + + pc = br_close->GetNextNcNnl(E_Scope::PREPROC); + + if ( pc->IsNullChunk() + || pc->IsNot(CT_ELSE)) + { + break; + } + log_rule_B("mod_full_brace_if_chain_only"); + + if (options::mod_full_brace_if_chain_only()) + { + // There is an 'else' - we want full braces. + must_have_braces = true; + } + pc = pc->GetNextNcNnl(E_Scope::PREPROC); + + if (pc->Is(CT_ELSEIF)) + { + while ( pc->IsNot(CT_VBRACE_OPEN) + && pc->IsNot(CT_BRACE_OPEN)) + { + pc = pc->GetNextNcNnl(E_Scope::PREPROC); + } + } + + if (pc->IsNullChunk()) + { + break; + } + + if ( pc->IsNot(CT_BRACE_OPEN) + && pc->IsNot(CT_VBRACE_OPEN)) + { + break; + } + } + + if (must_have_braces) + { + LOG_FMT(LBRCH, "%s(%d): add braces on lines[%zu]:", + __func__, __LINE__, braces.size()); + + const auto ite = braces.rend(); + + for (auto itc = braces.rbegin(); itc != ite; ++itc) + { + const auto brace = *itc; + + brace->SetFlagBits(PCF_KEEP_BRACE); + + if (brace->IsVBrace()) + { + LOG_FMT(LBRCH, "%s(%d): %zu", + __func__, __LINE__, brace->GetOrigLine()); + convert_vbrace(brace); + } + else + { + LOG_FMT(LBRCH, "%s(%d): {%zu}", + __func__, __LINE__, brace->GetOrigLine()); + } + } + + LOG_FMT(LBRCH, "\n"); + } + else if (options::mod_full_brace_if_chain()) + { + log_rule_B("mod_full_brace_if_chain"); + LOG_FMT(LBRCH, "%s(%d): remove braces on lines[%zu]:\n", + __func__, __LINE__, braces.size()); + + /* + * This might run because either + * mod_full_brace_if_chain or mod_full_brace_if_chain_only + * is used. + * We only want to remove braces if the first one is active. + */ + log_rule_B("mod_full_brace_nl_block_rem_mlcond"); + const auto multiline_block = options::mod_full_brace_nl_block_rem_mlcond(); + + LOG_FMT(LBRCH, "%s(%d): remove braces on lines:\n", __func__, __LINE__); + + // Issue #2229 + const auto ite = braces.end(); + + for (auto itc = braces.begin(); itc != ite; ++itc) + { + const auto brace = *itc; + + if ( ( brace->Is(CT_BRACE_OPEN) + || brace->Is(CT_BRACE_CLOSE)) + && (brace->GetParentType() != CT_BRACED_INIT_LIST) + && (multiline_block ? !paren_multiline_before_brace(brace) : true)) + { + LOG_FMT(LBRCH, "%s(%d): brace orig line is %zu, orig col is %zu\n", + __func__, __LINE__, brace->GetOrigLine(), brace->GetOrigCol()); + convert_brace(brace); + } + else + { + LOG_FMT(LBRCH, "%s(%d): brace orig line is %zu, orig col is %zu\n", + __func__, __LINE__, brace->GetOrigLine(), brace->GetOrigCol()); + } + } + } +} // process_if_chain + + +static void mod_full_brace_if_chain() +{ + LOG_FUNC_ENTRY(); + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if ( pc->IsBraceOpen() + && pc->GetParentType() == CT_IF) + { + process_if_chain(pc); + } + } +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/braces.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/braces.h new file mode 100644 index 00000000..763b6470 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/braces.h @@ -0,0 +1,33 @@ +/** + * @file braces.h + * prototypes for braces.cpp + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef BRACES_H_INCLUDED +#define BRACES_H_INCLUDED + +#include "uncrustify_types.h" + + +//! Change virtual braces into real braces +void do_braces(); + +/** + * See the preprocessor counterpart: + * add_long_preprocessor_conditional_block_comment + * in output.cpp + */ +void add_long_closebrace_comment(); + + +/** + * Adds a comment after the ref chunk + * Returns the added chunk or nullptr + */ +Chunk *insert_comment_after(Chunk *ref, E_Token cmt_type, const unc_text &cmt_text); + + +#endif /* BRACES_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/calculate_closing_brace_position.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/calculate_closing_brace_position.cpp new file mode 100644 index 00000000..db48a5e3 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/calculate_closing_brace_position.cpp @@ -0,0 +1,197 @@ +/** + * @file calculate_closing_brace_position.cpp + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#include "calculate_closing_brace_position.h" + +#include "chunk.h" + +using namespace uncrustify; + + +Chunk *calculate_closing_brace_position(const Chunk *cl_colon, Chunk *pc) +{ + LOG_FMT(LMCB, "%s(%d): cl_colon->Text() is '%s', orig line %zu, orig col is %zu, level is %zu\n", + __func__, __LINE__, cl_colon->Text(), cl_colon->GetOrigLine(), cl_colon->GetOrigCol(), cl_colon->GetLevel()); + LOG_FMT(LMCB, "%s(%d): pc->Text() is '%s', orig line %zu, orig col is %zu, level is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol(), pc->GetLevel()); + // end of block is reached + // look back over newline, preprocessor BUT NOT #endif + + // Issue #3058 + + // examine going back the tokens: look for a "brace closing" or a "semi colon" until the colon + // look back over comment, newline, preprocessor BUT NOT #endif + + size_t check_level = 0; + + if (pc->Is(CT_BRACE_CLOSE)) + { + check_level = pc->GetLevel() + 1; + } + else + { + check_level = pc->GetLevel(); + } + size_t erst_found = 0; + Chunk *is_brace_close = Chunk::NullChunkPtr; + Chunk *is_semicolon = Chunk::NullChunkPtr; + Chunk *is_comment = Chunk::NullChunkPtr; + Chunk *back = pc->GetPrevNnl(); + + while (back->IsNotNullChunk()) + { + if (back == cl_colon) + { + break; + } + + if (erst_found != 0) + { + break; + } + + if (back->GetLevel() == check_level) + { + if (back->IsBraceClose()) + { + // brace_close found + is_brace_close = back; + LOG_FMT(LMCB, "%s(%d): BRACE_CLOSE: line is %zu, col is %zu, level is %zu\n", + __func__, __LINE__, is_brace_close->GetOrigLine(), is_brace_close->GetOrigCol(), is_brace_close->GetLevel()); + erst_found = 3; + } + + if (back->Is(CT_SEMICOLON)) + { + // semicolon found + is_semicolon = back; + LOG_FMT(LMCB, "%s(%d): SEMICOLON: line is %zu, col is %zu, level is %zu\n", + __func__, __LINE__, is_semicolon->GetOrigLine(), is_semicolon->GetOrigCol(), is_semicolon->GetLevel()); + erst_found = 4; + } + + if (back->IsComment()) + { + // comment found + is_comment = back; + LOG_FMT(LMCB, "%s(%d): COMMENT: line is %zu, col is %zu, level is %zu\n", + __func__, __LINE__, back->GetOrigLine(), back->GetOrigCol(), back->GetLevel()); + } + } + back = back->GetPrev(); + } + LOG_FMT(LMCB, "%s(%d): erst_found is %zu\n", + __func__, __LINE__, erst_found); + Chunk *last = Chunk::NullChunkPtr; + + if ( erst_found == 3 + || erst_found == 4) + { + if (is_comment->IsNotNullChunk()) + { + Chunk *second = Chunk::NullChunkPtr; + + if (erst_found == 3) + { + second = is_brace_close; + } + else + { + // erst_found == 4 + second = is_semicolon; + } + + if (second->IsNotNullChunk()) + { + if (is_comment->GetOrigLine() == second->GetOrigLine()) + { + last = is_comment; + + if (cl_colon->GetOrigLine() == is_comment->GetOrigLine()) + { + last = is_comment->GetNext(); + } + } + else + { + last = pc->GetPrevNcNnl(); + } + } + else + { + LOG_FMT(LMCB, "\n\n%s(%d):\n", __func__, __LINE__); + fprintf(stderr, "FATAL: second is nullptr\n"); + fprintf(stderr, "Please make a report.\n"); + exit(EX_SOFTWARE); + } + } + else + { + last = pc->GetPrevNcNnl(); + } + } + else + { + LOG_FMT(LMCB, "\n\n%s(%d):\n", __func__, __LINE__); + fprintf(stderr, "FATAL: erst_found is not 3 or 4\n"); + fprintf(stderr, "Please make a report.\n"); + exit(EX_SOFTWARE); + } + + if (last->Is(CT_COMMENT_CPP)) // Issue #3058 + { + last = last->GetNext(); + } + LOG_FMT(LMCB, "%s(%d): last->Text() is '%s', orig line %zu, orig col is %zu\n", + __func__, __LINE__, last->Text(), last->GetOrigLine(), last->GetOrigCol()); + + if (last->IsPreproc()) + { + // we have a preprocessor token + while (last->IsNotNullChunk()) + { + LOG_FMT(LMCB, "%s(%d): Text() is '%s', orig line %zu, orig col is %zu\n", + __func__, __LINE__, last->Text(), last->GetOrigLine(), last->GetOrigCol()); + + if (last->Is(CT_PP_ENDIF)) + { + // look for the parent and compare the positions + Chunk *parent_last = last->GetParent(); + int comp = parent_last->ComparePosition(cl_colon); + LOG_FMT(LMCB, "%s(%d): comp is %d\n", + __func__, __LINE__, comp); + + if (comp == -1) + { + // cl_colon is after parent_last ==> + // the closing brace will be set before #endif + Chunk *pp_start = last->GetPpStart(); + last = pp_start->GetPrevNnl(); + LOG_FMT(LMCB, "%s(%d): Text() is '%s', orig line %zu, orig col is %zu\n", + __func__, __LINE__, last->Text(), last->GetOrigLine(), last->GetOrigCol()); + } + else if (comp == 1) + { + // cl_colon is before parent_last ==> + // the closing brace will be set after #endif + LOG_FMT(LMCB, "%s(%d): Text() is '%s', orig line %zu, orig col is %zu\n", + __func__, __LINE__, last->Text(), last->GetOrigLine(), last->GetOrigCol()); + } + break; + } + last = last->GetPrevNcNnl(); + LOG_FMT(LMCB, "%s(%d): Text() is '%s', orig line %zu, orig col is %zu\n", + __func__, __LINE__, last->Text(), last->GetOrigLine(), last->GetOrigCol()); + + if (!last->IsPreproc()) + { + break; + } + } + } + return(last); +} // calculate_closing_brace_position diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/calculate_closing_brace_position.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/calculate_closing_brace_position.h new file mode 100644 index 00000000..6d2b0f06 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/calculate_closing_brace_position.h @@ -0,0 +1,18 @@ +/** + * @file calculate_closing_brace_position.h + * prototype for calculate_closing_brace_position.cpp + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#ifndef CALCULATE_CLOSING_BRACE_POSITION_H_INCLUDED +#define CALCULATE_CLOSING_BRACE_POSITION_H_INCLUDED + +#include "uncrustify_types.h" + + +Chunk *calculate_closing_brace_position(const Chunk *cl_colon, Chunk *pc); + + +#endif /* CALCULATE_CLOSING_BRACE_POSITION_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/change_int_types.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/change_int_types.cpp new file mode 100644 index 00000000..06875edb --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/change_int_types.cpp @@ -0,0 +1,186 @@ +/** + * @file change_int_types.cpp + * + * @author Alex Henrie + * @license GPL v2+ + */ + +#include "change_int_types.h" + +#include "chunk.h" +#include "uncrustify.h" + + +using namespace uncrustify; + + +static bool is_storage_keyword(const Chunk *pc) +{ + return( strcmp(pc->Text(), "auto") == 0 + || strcmp(pc->Text(), "const") == 0 + || strcmp(pc->Text(), "extern") == 0 + || strcmp(pc->Text(), "mutable") == 0 + || strcmp(pc->Text(), "register") == 0 + || strcmp(pc->Text(), "static") == 0 + || strcmp(pc->Text(), "thread_local") == 0 + || strcmp(pc->Text(), "typedef") == 0 + || strcmp(pc->Text(), "volatile") == 0 + || strcmp(pc->Text(), "_Atomic") == 0 + || strcmp(pc->Text(), "_Thread_local") == 0); +} + + +static bool is_non_integer(const Chunk *pc) +{ + return( strcmp(pc->Text(), "char") == 0 + || strcmp(pc->Text(), "double") == 0); +} + + +static bool find_non_storage_siblings(const Chunk *pc, Chunk * &prev, Chunk * &next) +{ + prev = pc->GetPrevNcNnl(); + next = pc->GetNextNcNnl(); + + // Find the last token that was not a storage keyword + while (is_storage_keyword(prev)) + { + prev = prev->GetPrevNcNnl(); + } + + // Return false if the last token indicates that this is not an integer type + if (is_non_integer(prev)) + { + return(false); + } + + // Find the next token that is not a storage keyword + while (is_storage_keyword(next)) + { + next = next->GetNextNcNnl(); + } + + // Return false if the next token indicates that this is not an integer type + if (is_non_integer(next)) + { + return(false); + } + // Return true if this is indeed an integer type + return(true); +} + + +static void add_or_remove_int_keyword(Chunk *pc, Chunk *sibling, iarf_e action, E_Direction dir, Chunk * &int_keyword) +{ + if (strcmp(sibling->Text(), "int") == 0) + { + if (action == IARF_REMOVE) + { + if (sibling == int_keyword) + { + int_keyword = nullptr; + } + Chunk::Delete(sibling); + } + else if ( int_keyword != nullptr + && int_keyword != sibling) + { + // We added an int keyword, but now we see that there already was one. + // Keep one or the other but not both. + if (options::mod_int_prefer_int_on_left()) + { + Chunk::Delete(sibling); + } + else + { + Chunk::Delete(int_keyword); + int_keyword = sibling; + } + } + else + { + int_keyword = sibling; + } + } + else + { + if ( action == IARF_ADD + || action == IARF_FORCE) + { + if (int_keyword) + { + // There was already an int keyword. Either keep it and don't add a + // new one or delete it to make way for the new one. + if (options::mod_int_prefer_int_on_left()) + { + return; + } + else + { + Chunk::Delete(int_keyword); + } + } + + if (dir == E_Direction::BACKWARD) + { + int_keyword = pc->CopyAndAddBefore(pc); + } + else + { + int_keyword = pc->CopyAndAddAfter(pc); + } + int_keyword->Str() = "int"; + } + } +} // add_or_remove_int_keyword + + +void change_int_types() +{ + LOG_FUNC_ENTRY(); + + Chunk *prev; + Chunk *next; + Chunk *int_keyword = nullptr; + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + if (strcmp(pc->Text(), "short") == 0) + { + if (find_non_storage_siblings(pc, prev, next)) + { + add_or_remove_int_keyword(pc, prev, options::mod_int_short(), E_Direction::BACKWARD, int_keyword); + add_or_remove_int_keyword(pc, next, options::mod_short_int(), E_Direction::FORWARD, int_keyword); + } + } + else if (strcmp(pc->Text(), "long") == 0) + { + if (find_non_storage_siblings(pc, prev, next)) + { + add_or_remove_int_keyword(pc, prev, options::mod_int_long(), E_Direction::BACKWARD, int_keyword); + add_or_remove_int_keyword(pc, next, options::mod_long_int(), E_Direction::FORWARD, int_keyword); + } + } + else if (strcmp(pc->Text(), "signed") == 0) + { + if (find_non_storage_siblings(pc, prev, next)) + { + add_or_remove_int_keyword(pc, prev, options::mod_int_signed(), E_Direction::BACKWARD, int_keyword); + add_or_remove_int_keyword(pc, next, options::mod_signed_int(), E_Direction::FORWARD, int_keyword); + } + } + else if (strcmp(pc->Text(), "unsigned") == 0) + { + if (find_non_storage_siblings(pc, prev, next)) + { + add_or_remove_int_keyword(pc, prev, options::mod_int_unsigned(), E_Direction::BACKWARD, int_keyword); + add_or_remove_int_keyword(pc, next, options::mod_unsigned_int(), E_Direction::FORWARD, int_keyword); + } + } + else if ( strcmp(pc->Text(), "int") != 0 + && !is_storage_keyword(pc)) + { + int_keyword = nullptr; // We are no longer in a variable declaration + } + } +} // change_int_types diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/change_int_types.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/change_int_types.h new file mode 100644 index 00000000..b392a5d7 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/change_int_types.h @@ -0,0 +1,19 @@ +/** + * @file change_int_types.h + * prototypes for change_int_types.cpp + * + * @author Alex Henrie + * @license GPL v2+ + */ + +#ifndef CHANGE_INT_TYPES_H_INCLUDED +#define CHANGE_INT_TYPES_H_INCLUDED + + +/** + * @brief Add or remove redundant 'int' keyword of integer types + */ +void change_int_types(); + + +#endif /* CHANGE_INT_TYPES_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/char_table.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/char_table.h new file mode 100644 index 00000000..bcc30404 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/char_table.h @@ -0,0 +1,84 @@ +/** + * @file char_table.h + * A simple table to help tokenize stuff. + * Used to parse strings (paired char) and words. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef CHAR_TABLE_H_INCLUDED +#define CHAR_TABLE_H_INCLUDED + +#include "base_types.h" +#include <cstddef> + +/** + * bit0-7 = paired char + * bit8 = OK for keyword 1st char + * bit9 = OK for keyword 2+ char + */ +struct CharTable +{ + static size_t chars[128]; + + enum + { + KW1 = 0x0100, + KW2 = 0x0200, + }; + + + static inline size_t Get(size_t ch) + { + if (ch < ARRAY_SIZE(chars)) + { + return(chars[ch]); + } + /* + * HACK: If the top bit is set, then we are likely dealing with UTF-8, + * and since that is only allowed in identifiers, then assume that is + * what this is. This only prevents corruption, it does not properly + * handle UTF-8 because the byte length and screen size are assumed to be + * the same. + */ + return(KW1 | KW2); + } + + + static inline bool IsKw1(size_t ch) + { + return((Get(ch) & KW1) != 0); + } + + + static inline bool IsKw2(size_t ch) + { + return((Get(ch) & KW2) != 0); + } +}; + +#ifdef DEFINE_CHAR_TABLE +size_t CharTable::chars[128] = +{ + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // [........] + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // [........] + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // [........] + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // [........] + 0x000, 0x000, 0x022, 0x000, 0x300, 0x000, 0x000, 0x027, // [ !"#$%&'] + 0x029, 0x028, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // [()*+,-./] + 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, // [01234567] + 0x200, 0x200, 0x000, 0x000, 0x03e, 0x000, 0x03c, 0x000, // [89:;<=>?] + 0x200, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, // [@ABCDEFG] + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, // [HIJKLMNO] + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, // [PQRSTUVW] + 0x300, 0x300, 0x300, 0x05d, 0x000, 0x05b, 0x000, 0x300, // [XYZ[\]^_] + 0x060, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, // [`abcdefg] + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, // [hijklmno] + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, // [pqrstuvw] + 0x300, 0x300, 0x300, 0x07d, 0x000, 0x07b, 0x000, 0x000, // [xyz{|}~.] +}; +#endif /* DEFINE_CHAR_TABLE */ + + +#endif /* CHAR_TABLE_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/chunk.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/chunk.cpp new file mode 100644 index 00000000..125879b6 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/chunk.cpp @@ -0,0 +1,896 @@ +/** + * @file chunk.cpp + * Manages and navigates the list of chunks. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "chunk.h" + +#include "ListManager.h" +#include "prototypes.h" +#include "space.h" + +static ChunkListManager gChunkList; // global chunk list + + +/* + * Chunk class methods + */ + +// Null Chunk +Chunk Chunk::NullChunk(true); +Chunk *const Chunk::NullChunkPtr(&Chunk::NullChunk); + + +void Chunk::CopyFrom(const Chunk &o) +{ + m_type = o.m_type; + m_parentType = o.m_parentType; + m_origLine = o.m_origLine; + m_origCol = o.m_origCol; + m_origColEnd = o.m_origColEnd; + m_origPrevSp = o.m_origPrevSp; + m_column = o.m_column; + m_columnIndent = o.m_columnIndent; + m_nlCount = o.m_nlCount; + m_nlColumn = o.m_nlColumn; + m_level = o.m_level; + m_braceLevel = o.m_braceLevel; + m_ppLevel = o.m_ppLevel; + m_afterTab = o.m_afterTab; + + m_flags = o.m_flags; + m_alignmentData = o.m_alignmentData; + m_indentData = o.m_indentData; + + m_next = Chunk::NullChunkPtr; + m_prev = Chunk::NullChunkPtr; + m_parent = Chunk::NullChunkPtr; + + m_str = o.m_str; + m_trackingData = o.m_trackingData; +} + + +void Chunk::Reset() +{ + m_type = CT_NONE; + m_parentType = CT_NONE; + m_origLine = 0; + m_origCol = 0; + m_origColEnd = 0; + m_origPrevSp = 0; + m_column = 0; + m_columnIndent = 0; + m_nlCount = 0; + m_nlColumn = 0; + m_level = 0; + m_braceLevel = 0; + m_ppLevel = 999; // use a big value to find some errors + m_afterTab = false; + + m_flags = PCF_NONE; + memset(&m_alignmentData, 0, sizeof(m_alignmentData)); + memset(&m_indentData, 0, sizeof(m_indentData)); + + m_next = Chunk::NullChunkPtr; + m_prev = Chunk::NullChunkPtr; + m_parent = Chunk::NullChunkPtr; + + // for debugging purpose only + m_str.clear(); + m_trackingData = nullptr; +} + + +const char *Chunk::ElidedText(char *for_the_copy) const +{ + const char *test_it = Text(); + size_t test_it_length = strlen(test_it); + + size_t truncate_value = uncrustify::options::debug_truncate(); + + if (truncate_value != 0) + { + if (test_it_length > truncate_value) + { + memset(for_the_copy, 0, 1000); + + if (test_it_length < truncate_value + 30) + { + strncpy(for_the_copy, test_it, truncate_value - 30); + for_the_copy[truncate_value - 30] = 0; + } + else + { + strncpy(for_the_copy, test_it, truncate_value); + for_the_copy[truncate_value] = 0; + } + char *message = strcat(for_the_copy, " ... <The string is truncated>"); + + return(message); + } + else + { + return(test_it); + } + } + return(test_it); +} + + +Chunk *Chunk::GetNext(const E_Scope scope) const +{ + if (scope == E_Scope::ALL) + { + return(m_next); + } + Chunk *pc = m_next; + + if (TestFlags(PCF_IN_PREPROC)) + { + // If in a preproc, return a null chunk if trying to leave + if (!pc->TestFlags(PCF_IN_PREPROC)) + { + return(NullChunkPtr); + } + return(pc); + } + + // Not in a preproc, skip any preproc + while ( pc->IsNotNullChunk() + && pc->TestFlags(PCF_IN_PREPROC)) + { + pc = pc->m_next; + } + return(pc); +} // Chunk::GetNext + + +Chunk *Chunk::GetPrev(const E_Scope scope) const +{ + if (scope == E_Scope::ALL) + { + return(m_prev); + } + Chunk *pc = m_prev; + + if (TestFlags(PCF_IN_PREPROC)) + { + // If in a preproc, return a null chunk if trying to leave + if (!pc->TestFlags(PCF_IN_PREPROC)) + { + return(NullChunkPtr); + } + return(pc); + } + + // Not in a preproc, skip any preproc + while ( pc->IsNotNullChunk() + && pc->TestFlags(PCF_IN_PREPROC)) + { + pc = pc->m_prev; + } + return(pc); +} // Chunk::GetPrev + + +static void chunk_log(Chunk *pc, const char *text); + + +Chunk *Chunk::GetHead() +{ + return(gChunkList.GetHead()); +} + + +Chunk *Chunk::GetTail() +{ + return(gChunkList.GetTail()); +} + + +Chunk::T_SearchFnPtr Chunk::GetSearchFn(const E_Direction dir) +{ + return((dir == E_Direction::FORWARD) ? &Chunk::GetNext : &Chunk::GetPrev); +} + + +Chunk *Chunk::Search(const T_CheckFnPtr checkFn, const E_Scope scope, + const E_Direction dir, const bool cond) const +{ + T_SearchFnPtr searchFnPtr = GetSearchFn(dir); + Chunk *pc = const_cast<Chunk *>(this); + + do // loop over the chunk list + { + pc = (pc->*searchFnPtr)(scope); // in either direction while + } while ( pc->IsNotNullChunk() // the end of the list was not reached yet + && ((pc->*checkFn)() != cond)); // and the demanded chunk was not found either + + return(pc); // the latest chunk is the searched one +} + + +bool Chunk::IsOnSameLine(const Chunk *end) const +{ + if (IsNullChunk()) + { + return(false); + } + Chunk *tmp = GetNext(); + + while ( tmp->IsNotNullChunk() + && tmp != end) + { + if (tmp->Is(CT_NEWLINE)) + { + return(false); + } + tmp = tmp->GetNext(); + } + return(true); +} + + +Chunk *Chunk::SearchTypeLevel(const E_Token type, const E_Scope scope, + const E_Direction dir, const int level) const +{ + T_SearchFnPtr searchFnPtr = GetSearchFn(dir); + Chunk *pc = const_cast<Chunk *>(this); + + do // loop over the chunk list + { + pc = (pc->*searchFnPtr)(scope); // in either direction while + } while ( pc->IsNotNullChunk() // the end of the list was not reached yet + && (!pc->IsTypeAndLevel(type, level))); // and the chunk was not found either + + return(pc); // the latest chunk is the searched one +} + + +Chunk *Chunk::SearchStringLevel(const char *cStr, const size_t len, int level, + const E_Scope scope, const E_Direction dir) const +{ + T_SearchFnPtr searchFnPtr = GetSearchFn(dir); + Chunk *pc = const_cast<Chunk *>(this); + + do // loop over the chunk list + { + pc = (pc->*searchFnPtr)(scope); // in either direction while + } while ( pc->IsNotNullChunk() // the end of the list was not reached yet + && !pc->IsStringAndLevel(cStr, len, true, level)); // and the demanded chunk was not found either + + return(pc); // the latest chunk is the searched one +} + + +Chunk *Chunk::SearchPpa(const T_CheckFnPtr checkFn, const bool cond) const +{ + if (!TestFlags(PCF_IN_PREPROC)) + { + // if not in preprocessor, do a regular search + return(Search(checkFn, E_Scope::ALL, E_Direction::FORWARD, cond)); + } + Chunk *pc = GetNext(); + + while (pc->IsNotNullChunk()) + { + if (!pc->TestFlags(PCF_IN_PREPROC)) + { + // Bail if we run off the end of the preprocessor directive, but return + // the token because the caller may need to know where the search ended + assert(pc->Is(CT_NEWLINE)); + return(pc); + } + + if (pc->Is(CT_NL_CONT)) + { + // Skip line continuation + pc = pc->GetNext(); + continue; + } + + if ((pc->*checkFn)() == cond) + { + // Requested token was found + return(pc); + } + pc = pc->GetNext(); + } + // Ran out of tokens + return(Chunk::NullChunkPtr); +} + + +static void chunk_log_msg(Chunk *chunk, const log_sev_t log, const char *str) +{ + LOG_FMT(log, "%s orig line is %zu, orig col is %zu, ", + str, chunk->GetOrigLine(), chunk->GetOrigCol()); + + if (chunk->Is(CT_NEWLINE)) + { + LOG_FMT(log, "<Newline>,\n"); + } + else if (chunk->Is(CT_VBRACE_OPEN)) + { + LOG_FMT(log, "<VBRACE_OPEN>,\n"); + } + else if (chunk->Is(CT_VBRACE_CLOSE)) + { + LOG_FMT(log, "<VBRACE_CLOSE>,\n"); + } + else + { + LOG_FMT(log, "Text() is '%s', type is %s,\n", chunk->Text(), get_token_name(chunk->GetType())); + } +} + + +static void chunk_log(Chunk *pc, const char *text) +{ + if ( pc != nullptr + && pc->IsNotNullChunk() + && (cpd.unc_stage != unc_stage_e::TOKENIZE) + && (cpd.unc_stage != unc_stage_e::CLEANUP)) + { + const log_sev_t log = LCHUNK; + Chunk *prev = pc->GetPrev(); + Chunk *next = pc->GetNext(); + + chunk_log_msg(pc, log, text); + + if ( prev->IsNotNullChunk() + && next->IsNotNullChunk()) + { + chunk_log_msg(prev, log, " @ between"); + chunk_log_msg(next, log, " and"); + } + else if (next->IsNotNullChunk()) + { + chunk_log_msg(next, log, " @ before"); + } + else if (prev->IsNotNullChunk()) + { + chunk_log_msg(prev, log, " @ after"); + } + LOG_FMT(log, " stage is %s", // Issue #3034 + get_unc_stage_name(cpd.unc_stage)); + log_func_stack_inline(log); + } +} + + +void Chunk::Delete(Chunk * &pc) +{ + gChunkList.Remove(pc); + delete pc; + pc = Chunk::NullChunkPtr; +} + + +void Chunk::MoveAfter(Chunk *ref) +{ + LOG_FUNC_ENTRY(); + + if (ref == this) + { + return; + } + gChunkList.Remove(this); + gChunkList.AddAfter(this, ref); + + // Adjust the original column + m_column = ref->m_column + space_col_align(ref, this); + m_origCol = m_column; + m_origColEnd = m_origCol + Len(); +} + + +void Chunk::Swap(Chunk *other) +{ + gChunkList.Swap(this, other); +} + + +bool Chunk::IsAddress() const +{ + if ( IsNotNullChunk() + && ( Is(CT_BYREF) + || ( Len() == 1 + && m_str[0] == '&' + && IsNot(CT_OPERATOR_VAL)))) + { + Chunk *prevc = GetPrev(); + + if ( TestFlags(PCF_IN_TEMPLATE) + && ( prevc->Is(CT_COMMA) + || prevc->Is(CT_ANGLE_OPEN))) + { + return(false); + } + return(true); + } + return(false); +} + + +Chunk *Chunk::GetFirstChunkOnLine() const +{ + Chunk *pc = const_cast<Chunk *>(this); + Chunk *first = pc; + + pc = pc->GetPrev(); + + while ( pc->IsNotNullChunk() + && !pc->IsNewline()) + { + first = pc; + pc = pc->GetPrev(); + } + return(first); +} + + +bool Chunk::IsLastChunkOnLine() const +{ + if (this == Chunk::GetTail()) + { + return(true); + } + + // if the next chunk is a newline then pc is the last chunk on its line + if (GetNext()->Is(CT_NEWLINE)) + { + return(true); + } + return(false); +} + + +void Chunk::SwapLines(Chunk *other) +{ + // to swap lines we need to find the first chunk of the lines + Chunk *pc1 = GetFirstChunkOnLine(); + Chunk *pc2 = other->GetFirstChunkOnLine(); + + if ( pc1->IsNullChunk() + || pc2->IsNullChunk() + || pc1 == pc2) + { + return; + } + /* + * Example start: + * ? - start1 - a1 - b1 - nl1 - ? - ref2 - start2 - a2 - b2 - nl2 - ? + * ^- pc1 ^- pc2 + */ + Chunk *ref2 = pc2->GetPrev(); + + // Move the line started at pc2 before pc1 + while ( pc2->IsNotNullChunk() + && !pc2->IsNewline()) + { + Chunk *tmp = pc2->GetNext(); + gChunkList.Remove(pc2); + gChunkList.AddBefore(pc2, pc1); + pc2 = tmp; + } + /* + * Should now be: + * ? - start2 - a2 - b2 - start1 - a1 - b1 - nl1 - ? - ref2 - nl2 - ? + * ^- pc1 ^- pc2 + */ + + // Now move the line started at pc1 after ref2 + while ( pc1->IsNotNullChunk() + && !pc1->IsNewline()) + { + Chunk *tmp = pc1->GetNext(); + gChunkList.Remove(pc1); + + if (ref2->IsNotNullChunk()) + { + gChunkList.AddAfter(pc1, ref2); + } + else + { + gChunkList.AddHead(pc1); + } + ref2 = pc1; + pc1 = tmp; + } + /* + * Should now be: + * ? - start2 - a2 - b2 - nl1 - ? - ref2 - start1 - a1 - b1 - nl2 - ? + * ^- pc1 ^- pc2 + */ + + /* + * pc1 and pc2 should be the newlines for their lines. + * swap the chunks and the new line count so that the spacing remains the same. + */ + if ( pc1->IsNotNullChunk() + && pc2->IsNotNullChunk()) + { + size_t nlCount = pc1->GetNlCount(); + + pc1->SetNlCount(pc2->GetNlCount()); + pc2->SetNlCount(nlCount); + + pc1->Swap(pc2); + } +} // Chunk::SwapLines + + +void Chunk::SetResetFlags(T_PcfFlags resetBits, T_PcfFlags setBits) +{ + if (IsNotNullChunk()) + { + LOG_FUNC_ENTRY(); + const T_PcfFlags newFlags = (m_flags & ~resetBits) | setBits; + + if (m_flags != newFlags) + { + LOG_FMT(LSETFLG, + "%s(%d): %016llx^%016llx=%016llx\n" + "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s', type is %s,", + __func__, __LINE__, + static_cast<T_PcfFlags::int_t>(m_flags), + static_cast<T_PcfFlags::int_t>(m_flags ^ newFlags), + static_cast<T_PcfFlags::int_t>(newFlags), + __func__, __LINE__, m_origLine, m_origCol, Text(), get_token_name(m_type)); + LOG_FMT(LSETFLG, " parent type is %s,\n", + get_token_name(m_parentType)); + log_func_stack_inline(LSETFLG); + + LOG_FMT(LSETFLG, " before: "); + log_pcf_flags(LSETFLG, m_flags); + LOG_FMT(LSETFLG, " after: "); + log_pcf_flags(LSETFLG, newFlags); + m_flags = newFlags; + } + } +} + + +void Chunk::SetTypeReal(const E_Token token, const char *func, const int line) +{ + LOG_FUNC_ENTRY(); + + if ( IsNullChunk() + || m_type == token) + { + return; + } + LOG_FMT(LSETTYP, "%s(%d): orig line is %zu, orig col is %zu, Text() is ", + func, line, m_origLine, m_origCol); + + if (token == CT_NEWLINE) + { + LOG_FMT(LSETTYP, "<Newline>\n"); + } + else + { + LOG_FMT(LSETTYP, "'%s'\n", Text()); + } + LOG_FMT(LSETTYP, " type is %s, parent type is %s => new type is %s\n", + get_token_name(m_type), get_token_name(m_parentType), get_token_name(token)); + m_type = token; +} + + +void Chunk::SetParentTypeReal(const E_Token token, const char *func, const int line) +{ + LOG_FUNC_ENTRY(); + + if ( IsNullChunk() + || m_parentType == token) + { + return; + } + LOG_FMT(LSETPAR, "%s(%d): orig line is %zu, orig col is %zu, Text() is ", + func, line, m_origLine, m_origCol); + + if (token == CT_NEWLINE) + { + LOG_FMT(LSETPAR, "<Newline>\n"); + } + else + { + LOG_FMT(LSETPAR, "'%s'\n", Text()); + } + LOG_FMT(LSETPAR, " type is %s, parent type is %s => new parent type is %s\n", + get_token_name(m_type), get_token_name(m_parentType), get_token_name(token)); + m_parentType = token; +} + + +Chunk *Chunk::CopyAndAdd(Chunk *pos, const E_Direction dir) const +{ +#ifdef DEBUG + // test if this chunk is properly set + if (m_ppLevel == 999) + { + fprintf(stderr, "%s(%d): pp level is not set\n", __func__, __LINE__); + log_func_stack_inline(LSETFLG); + log_flush(true); + exit(EX_SOFTWARE); + } + + if (m_origLine == 0) + { + fprintf(stderr, "%s(%d): no line number\n", __func__, __LINE__); + log_func_stack_inline(LSETFLG); + log_flush(true); + exit(EX_SOFTWARE); + } + + if (m_origCol == 0) + { + fprintf(stderr, "%s(%d): no column number\n", __func__, __LINE__); + log_func_stack_inline(LSETFLG); + log_flush(true); + exit(EX_SOFTWARE); + } +#endif /* DEBUG */ + + Chunk *pc = new Chunk(*this); + + if ( pos != nullptr + && pos->IsNotNullChunk()) + { + (dir == E_Direction::FORWARD) ? gChunkList.AddAfter(pc, pos) : gChunkList.AddBefore(pc, pos); + } + else + { + (dir == E_Direction::FORWARD) ? gChunkList.AddHead(pc) : gChunkList.AddTail(pc); + } + chunk_log(pc, "CopyAndAdd(A):"); + return(pc); +} // Chunk::CopyAndAdd + + +Chunk *Chunk::GetNextNbsb() const +{ + Chunk *pc = const_cast<Chunk *>(this); + + while ( pc->Is(CT_TSQUARE) + || pc->Is(CT_SQUARE_OPEN)) + { + if (pc->Is(CT_SQUARE_OPEN)) + { + pc = pc->GetClosingParen(); + } + pc = pc->GetNextNcNnl(); + } + return(pc); +} + + +Chunk *Chunk::GetPrevNbsb() const +{ + Chunk *pc = const_cast<Chunk *>(this); + + while ( pc->Is(CT_TSQUARE) + || pc->Is(CT_SQUARE_CLOSE)) + { + if (pc->Is(CT_SQUARE_CLOSE)) + { + pc = pc->GetOpeningParen(); + } + pc = pc->GetPrevNcNnl(); + } + return(pc); +} + + +Chunk *Chunk::GetPpStart() const +{ + if (!IsPreproc()) + { + return(Chunk::NullChunkPtr); + } + Chunk *pc = const_cast<Chunk *>(this); + + while (pc->IsNot(CT_PREPROC)) + { + pc = pc->GetPrev(E_Scope::PREPROC); + } + return(pc); +} + + +Chunk *Chunk::SkipDcMember() const +{ + LOG_FUNC_ENTRY(); + + Chunk *pc = const_cast<Chunk *>(this); + Chunk *nxt = pc->Is(CT_DC_MEMBER) ? pc : pc->GetNextNcNnl(E_Scope::ALL); + + while (nxt->Is(CT_DC_MEMBER)) + { + pc = nxt->GetNextNcNnl(E_Scope::ALL); + + if (pc->IsNullChunk()) + { + return(Chunk::NullChunkPtr); + } + nxt = pc->GetNextNcNnl(E_Scope::ALL); + } + return(pc); +} + + +int Chunk::ComparePosition(const Chunk *other) const +{ + if (m_origLine < other->m_origLine) + { + return(-1); + } + else if (m_origLine == other->m_origLine) + { + if (m_origCol < other->m_origCol) + { + return(-1); + } + else if (m_origCol == other->m_origCol) + { + return(0); + } + } + return(1); +} + + +bool Chunk::IsOCForinOpenParen() const +{ + if ( language_is_set(LANG_OC) + && Is(CT_SPAREN_OPEN) + && GetPrevNcNnl()->Is(CT_FOR)) + { + Chunk *nxt = const_cast<Chunk *>(this); + + while ( nxt->IsNotNullChunk() + && nxt->IsNot(CT_SPAREN_CLOSE) + && nxt->IsNot(CT_IN)) + { + nxt = nxt->GetNextNcNnl(); + } + + if (nxt->Is(CT_IN)) + { + return(true); + } + } + return(false); +} + + +bool Chunk::IsStringAndLevel(const char *cStr, const size_t len, + bool caseSensitive, const int level) const +{ + return( ( level < 0 + || m_level == static_cast<size_t>(level)) + && Len() == len // the length is as expected + && ( ( caseSensitive + && memcmp(Text(), cStr, len) == 0) + || ( !caseSensitive + && strncasecmp(Text(), cStr, len) == 0))); // the strings are equal +} + + +Chunk *Chunk::GetClosingParen(E_Scope scope) const +{ + if ( Is(CT_PAREN_OPEN) + || Is(CT_SPAREN_OPEN) + || Is(CT_FPAREN_OPEN) + || Is(CT_TPAREN_OPEN) + || Is(CT_BRACE_OPEN) + || Is(CT_VBRACE_OPEN) + || Is(CT_ANGLE_OPEN) + || Is(CT_SQUARE_OPEN)) + { + return(GetNextType((E_Token)(m_type + 1), m_level, scope)); + } + return(const_cast<Chunk *>(this)); +} + + +Chunk *Chunk::GetOpeningParen(E_Scope scope) const +{ + if ( Is(CT_PAREN_CLOSE) + || Is(CT_SPAREN_CLOSE) + || Is(CT_FPAREN_CLOSE) + || Is(CT_TPAREN_CLOSE) + || Is(CT_BRACE_CLOSE) + || Is(CT_VBRACE_CLOSE) + || Is(CT_ANGLE_CLOSE) + || Is(CT_SQUARE_CLOSE)) + { + return(GetPrevType((E_Token)(m_type - 1), m_level, scope)); + } + return(const_cast<Chunk *>(this)); +} + + +bool Chunk::IsCppInheritanceAccessSpecifier() const +{ + return( language_is_set(LANG_CPP) + && ( Is(CT_ACCESS) + || Is(CT_QUALIFIER)) + && ( IsString("private") + || IsString("protected") + || IsString("public"))); +} + + +bool Chunk::IsColon() const +{ + return( Is(CT_ACCESS_COLON) + || Is(CT_ASM_COLON) + || Is(CT_BIT_COLON) + || Is(CT_CASE_COLON) + || Is(CT_CLASS_COLON) + || Is(CT_COLON) + || Is(CT_COND_COLON) + || Is(CT_CONSTR_COLON) + || Is(CT_CS_SQ_COLON) + || Is(CT_D_ARRAY_COLON) + || Is(CT_FOR_COLON) + || Is(CT_LABEL_COLON) + || Is(CT_OC_COLON) + || Is(CT_OC_DICT_COLON) + || Is(CT_TAG_COLON) + || Is(CT_WHERE_COLON)); +} + + +bool Chunk::IsDoxygenComment() const +{ + if (!IsComment()) + { + return(false); + } + + if (Len() < 3) + { + return(false); + } + // check the third character + const char *sComment = Text(); + return( (sComment[2] == '/') + || (sComment[2] == '!') + || (sComment[2] == '@')); +} + + +bool Chunk::IsTypeDefinition() const +{ + return( Is(CT_TYPE) + || Is(CT_PTR_TYPE) + || Is(CT_BYREF) + || Is(CT_DC_MEMBER) + || Is(CT_QUALIFIER) + || Is(CT_STRUCT) + || Is(CT_ENUM) + || Is(CT_UNION)); +} + + +bool Chunk::IsNewlineBetween(const Chunk *other) const +{ + Chunk *pc = const_cast<Chunk *>(this); + + while (pc != other) + { + if (pc->IsNewline()) + { + return(true); + } + pc = pc->GetNext(); + } + return(false); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/chunk.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/chunk.h new file mode 100644 index 00000000..fe705fe1 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/chunk.h @@ -0,0 +1,1801 @@ +/** + * @file chunk.h + * Manages and navigates the list of chunks. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef CHUNK_LIST_H_INCLUDED +#define CHUNK_LIST_H_INCLUDED + +#include "uncrustify_types.h" +// necessary to not sort it +#include "char_table.h" +#include "language_tools.h" + + +static constexpr int ANY_LEVEL = -1; + + +/** + * Specifies which chunks should/should not be found. + * ALL (default) + * - return the true next/prev + * + * PREPROC + * - If not in a preprocessor, skip over any encountered preprocessor stuff + * - If in a preprocessor, fail to leave (return Chunk::NullChunkPtr) + */ +enum class E_Scope : unsigned int +{ + ALL, //! search in all kind of chunks + PREPROC, //! search only in preprocessor chunks +}; + + +/** + * Specifies which direction or location an operation shall be performed. + */ +enum class E_Direction : unsigned int +{ + FORWARD, + BACKWARD +}; + + +class ChunkListManager; + +// This is the main type of this program +class Chunk +{ + friend ChunkListManager; + +public: + //! constructors + Chunk(bool null_c = false); // default + Chunk(const Chunk &o); // !!! partial copy: chunk is not linked to others + + Chunk &operator=(const Chunk &o); // !!! partial copy: chunk is not linked to others + + //! whether this is a null Chunk or not + bool IsNullChunk() const { return(null_chunk); } + bool IsNotNullChunk() const { return(!null_chunk); } + + //! sets all elements of the struct to their default value + void Reset(); + + + // --------- Access methods + + /** + * @brief returns the type of the chunk + */ + E_Token GetType() const; + + /** + * @brief Sets the chunk type + * @param token the type to set + * @param func the name of the function from where this method is called (for log purposes) + * @param line the line number from where this method is called (for log purposes) + */ + void SetTypeReal(const E_Token token, const char *func, const int line); + + /** + * @brief Returns the parent type of the chunk + */ + E_Token GetParentType() const; + + /** + * @brief Sets the type of the parent chunk + * @param token the type to set + * @param func the name of the function from where this method is called (for log purposes) + * @param line the line number from where this method is called (for log purposes) + */ + void SetParentTypeReal(const E_Token token, const char *func, const int line); + + /** + * @brief Returns the parent of the chunk + */ + Chunk *GetParent() const; + + /** + * @brief Sets the parent of the chunk + * @param parent the parent chunk to set + */ + void SetParent(Chunk *parent); + + /** + * @brief Returns the alignment data of the chunk as a const reference + */ + const T_AlignData &GetAlignmentData() const; + + /** + * @brief Returns the alignment data of the chunk as a modifiable reference + */ + T_AlignData &AlignmentData(); + + /** + * @brief Returns the indentation data of the chunk as a const reference + */ + const T_IndentData &GetIndentData() const; + + /** + * @brief Returns the indentation data of the chunk as a modifiable reference + */ + T_IndentData &IndentData(); + + /** + * @brief Returns the text data of the chunk as a const reference + */ + const unc_text &GetStr() const; + + /** + * @brief Returns the text data of the chunk as a modifiable reference + */ + unc_text &Str(); + + /** + * @brief returns the number of characters in the chunk text string + */ + size_t Len() const; + + /** + * @brief returns the content of the chunk text as C string + */ + const char *Text() const; + + /** + * Returns a filled up (if necessary) copy of the first chars of the Text() string + */ + const char *ElidedText(char *for_the_copy) const; + + /** + * @brief Returns the tracking data of the chunk as a const reference + */ + const track_list *GetTrackingData() const; + + /** + * @brief Returns the tracking data of the chunk as a modifiable reference + */ + track_list * &TrackingData(); + + /** + * @brief Returns the type of the parent chunk + */ + E_Token GetTypeOfParent() const; + + /** + * @brief Returns the chunk flags + */ + T_PcfFlags GetFlags() const; + + /** + * @brief Sets the chunk flags + * @param flags the new chunk flags + */ + void SetFlags(T_PcfFlags flags); + + /** + * @brief Tests if some chunk flags are set + * @param flags the flag bits to test + * @return true if the specified bits are set, false otherwise + */ + bool TestFlags(T_PcfFlags flags) const; + + /** + * @brief Resets some of the chunk flag bits + * @param resetBits the flag bits to reset + */ + void ResetFlagBits(T_PcfFlags resetBits); + + /** + * @brief Sets some of the chunk flag bits + * @param setBits the flag bits to set + */ + void SetFlagBits(T_PcfFlags setBits); + + /** + * @brief Sets and reset some of the chunk flag bits + * @param resetBits the flag bits to reset + * @param setBits the flag bits to set + */ + void UpdateFlagBits(T_PcfFlags resetBits, T_PcfFlags setBits); + + /** + * @brief Returns the line number of the chunk in the input file + */ + size_t GetOrigLine() const; + + /** + * @brief Sets the line number of the chunk in the input file + * @param line the line number of the chunk + */ + void SetOrigLine(size_t line); + + /** + * @brief Returns the column number of the chunk in the input file + */ + size_t GetOrigCol() const; + + /** + * @brief Sets the column number of the chunk in the input file + * @param col the column number of the chunk + */ + void SetOrigCol(size_t col); + + /** + * @brief Returns the end column number of the chunk in the input file + */ + size_t GetOrigColEnd() const; + + /** + * @brief Sets the end column number of the chunk in the input file + * @param col the end column number of the chunk + */ + void SetOrigColEnd(size_t col); + + /** + * @brief Returns the position of the whitespace before this chunk + */ + size_t GetOrigPrevSp() const; + + /** + * @brief Sets the position of the whitespace before this chunk + * @param col the end column number of the chunk in the input file + */ + void SetOrigPrevSp(size_t col); + + /** + * @brief Returns the column of the chunk + */ + size_t GetColumn() const; + + /** + * @brief Sets the column of the chunk + * @param col the column of the chunk + */ + void SetColumn(size_t col); + + /** + * @brief Returns the column indentation of the chunk + */ + size_t GetColumnIndent() const; + + /** + * @brief Sets the column indentation of the chunk + * @param col the column indentation of the chunk + */ + void SetColumnIndent(size_t col); + + /** + * @brief Returns the number of newlines in a CT_NEWLINE chunk + */ + size_t GetNlCount() const; + + /** + * @brief Sets the number of newlines in a CT_NEWLINE chunk + * @param cnt the number of newlines + */ + void SetNlCount(size_t cnt); + + /** + * @brief Returns the column of the newline entries + */ + size_t GetNlColumn() const; + + /** + * @brief Sets the column of the newline entries + * @param col the number of the column + */ + void SetNlColumn(size_t col); + + /** + * @brief Returns the level of the chunk + */ + size_t GetLevel() const; + + /** + * @brief Sets the level of the chunk + * @param col the level of the chunk + */ + void SetLevel(size_t level); + + /** + * @brief Returns the brace level of the chunk + */ + size_t GetBraceLevel() const; + + /** + * @brief Sets the brace level of the chunk + * @param level the brace level of the chunk + */ + void SetBraceLevel(size_t lvl); + + /** + * @brief Returns the preprocessor level of the chunk + */ + size_t GetPpLevel() const; + + /** + * @brief Sets the preprocessor level of the chunk + * @param level the preprocessor level of the chunk + */ + void SetPpLevel(size_t lvl); + + /** + * @brief Returns the after tab property of the chunk + */ + bool GetAfterTab() const; + + /** + * @brief Sets the after tab property of the chunk + * @param afterTab the after tab property of the chunk + */ + void SetAfterTab(bool afterTab); + + + // --------- Get* chunk functions + + /** + * @brief returns the head of the chunk list + * @return pointer to the first chunk + */ + static Chunk *GetHead(); + + /** + * @brief returns the tail of the chunk list + * @return pointer to the last chunk + */ + static Chunk *GetTail(); + + /** + * @brief returns the next chunk in a list of chunks + * @param scope code region to search in + * @return pointer to next chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetNext(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the previous chunk in a list of chunks + * @param scope code region to search in + * @return pointer to previous chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetPrev(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the next newline chunk + * @param scope code region to search in + * @return pointer to next newline chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetNextNl(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the prev newline chunk + * @param scope code region to search in + * @return pointer to prev newline chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetPrevNl(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the next non-newline chunk + * @param scope code region to search in + * @return pointer to next non-newline chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetNextNnl(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the prev non-newline chunk + * @param scope code region to search in + * @return pointer to prev non-newline chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetPrevNnl(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the next non-comment chunk + * @param scope code region to search in + * @return pointer to next non-comment chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetNextNc(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the prev non-comment chunk + * @param scope code region to search in + * @return pointer to prev non-comment chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetPrevNc(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the next non-comment and non-newline chunk + * @param scope code region to search in + * @return pointer to next non-comment and non-newline chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetNextNcNnl(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the prev non-comment and non-newline chunk + * @param scope code region to search in + * @return pointer to prev non-comment and non-newline chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetPrevNcNnl(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the next non-comment, non-newline, non-preprocessor chunk + * @param scope code region to search in + * @return pointer to next non-comment, non-newline, non-preprocessor chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetNextNcNnlNpp(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the prev non-comment, non-newline, non-preprocessor chunk + * @param scope code region to search in + * @return pointer to prev non-comment, non-newline, non-preprocessor chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetPrevNcNnlNpp(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the next non-preprocessor or non-comment, non-newline chunk + * @param scope code region to search in + * @return pointer to next non-preprocessor or non-comment, non-newline chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetNextNppOrNcNnl(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the prev non-preprocessor or non-comment, non-newline chunk + * @param scope code region to search in + * @return pointer to prev non-preprocessor or non-comment, non-newline chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetPrevNppOrNcNnl(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the next preprocessor aware non-comment and non-newline chunk + * Unlike Chunk::GetNextNcNnl, this will also ignore a line continuation if + * the starting chunk is in a preprocessor directive, and may return a newline + * if the search reaches the end of a preprocessor directive. + * @return pointer to next preprocessor aware non-comment and non-newline chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *PpaGetNextNcNnl() const; + + /** + * @brief returns the next non-comment, non-newline, non-empty text chunk + * @param scope code region to search in + * @return pointer to next non-comment, non-newline, non-empty text chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetNextNcNnlNet(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the prev non-comment, non-newline, non-empty text chunk + * @param scope code region to search in + * @return pointer to prev non-comment, non-newline, non-empty text chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetPrevNcNnlNet(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the prev non-comment, non-newline, non-ignored chunk + * @param scope code region to search in + * @return pointer to prev non-comment, non-newline, non-ignored chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetPrevNcNnlNi(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the next chunk not in or part of balanced square + * brackets. This handles stacked [] instances to accommodate + * multi-dimensional array declarations + * @param scope code region to search in + * @return nullptr or the next chunk not in or part of square brackets + */ + Chunk *GetNextNisq(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the next non-virtual brace chunk + * @param scope code region to search in + * @return pointer to next non-virtual brace chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetNextNvb(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the prev non-virtual brace chunk + * @param scope code region to search in + * @return pointer to prev non-virtual brace chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetPrevNvb(const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the next chunk of the given type at the level. + * @param type the type to look for + * @param level the level to match or ANY_LEVEL + * @param scope code region to search in + * @return pointer to the next matching chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetNextType(const E_Token type, const int level = ANY_LEVEL, const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the prev chunk of the given type at the level. + * @param type the type to look for + * @param level the level to match or ANY_LEVEL + * @param scope code region to search in + * @return pointer to the prev matching chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetPrevType(const E_Token type, int level = ANY_LEVEL, E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the next chunk that holds a given string at a given level. + * @param cStr string to search for + * @param len length of string + * @param level the level to match or ANY_LEVEL + * @param scope code region to search in + * @return pointer to the next matching chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetNextString(const char *cStr, const size_t len, const int level, const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the prev chunk that holds a given string at a given level. + * @param cStr string to search for + * @param len length of string + * @param level the level to match or ANY_LEVEL + * @param scope code region to search in + * @return pointer to the prev matching chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetPrevString(const char *cStr, const size_t len, const int level, const E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the next chunk that is not part of balanced square brackets. + * This handles stacked[] instances to accommodate multidimensional arrays. + * @return pointer to the next matching chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetNextNbsb() const; + + /** + * @brief returns the prev chunk that is not part of balanced square brackets. + * This handles stacked[] instances to accommodate multidimensional arrays. + * @return pointer to the prev matching chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetPrevNbsb() const; + + /** + * @brief returns the corresponding start chunk if the given chunk is within a + * preprocessor directive, or Chunk::NullChunkPtr otherwise. + * @return start chunk of the preprocessor directive or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetPpStart() const; + + /** + * @brief Finds the first chunk on the line the current chunk is on. + * This just backs up until a newline or nullptr is hit. + * + * given: [ a - b - c - n1 - d - e - n2 ] + * input: [ a | b | c | n1 ] => a + * input: [ d | e | n2 ] => d + * + * @return pointer to the first chunk on the line the current chunk is on. + */ + Chunk *GetFirstChunkOnLine() const; + + + // --------- Search functions + + /** + * @brief defines a member function pointer for a function of type + * Chunk *Chunk::function(const E_Scope scope) + * that will search for a new chunk + */ + typedef Chunk *(Chunk::*T_SearchFnPtr)(const E_Scope scope) const; + + /** + * @brief defines a member function pointer for a function of type + * bool Chunk::function() const; + * that checks whether a chunk satisty a specific condition + */ + typedef bool (Chunk::*T_CheckFnPtr)() const; + + /** + * @brief determines the search direction to use and returns a pointer + * to the corresponding search function. + * @param dir search direction + * @return pointer to search function + */ + static T_SearchFnPtr GetSearchFn(const E_Direction dir = E_Direction::FORWARD); + + /** + * @brief search for a chunk that satisfies a condition in a chunk list + * + * A generic function that traverses a chunks list either + * in forward or reverse direction. The traversal continues until a + * chunk satisfies the condition defined by the compare function. + * Depending on the parameter cond the condition will either be + * checked to be true or false. + * + * @param checkFn compare function + * @param scope code parts to consider for search + * @param dir search direction (forward or backward) + * @param cond success condition + * @return pointer to the found chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *Search(const T_CheckFnPtr checkFn, const E_Scope scope = E_Scope::ALL, const E_Direction dir = E_Direction::FORWARD, const bool cond = true) const; + + /** + * @brief search for a chunk that satisfies a condition in a chunk list, + * but being aware of preprocessor chucks. + * + * This function is similar to Search, except that it is tweaked to + * handle searches inside of preprocessor directives. Specifically, if the + * starting token is inside a preprocessor directive, it will ignore a line + * continuation, and will abort the search if it reaches the end of the + * directive. This function only searches forward. + * + * @param checkFn compare function + * @param cond success condition + * @return pointer to the found chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *SearchPpa(const T_CheckFnPtr checkFn, const bool cond = true) const; + + /** + * @brief search a chunk of a given type and level. Traverses a chunk list in the + * specified direction until a chunk of a given type and level is found. + * + * This function is a specialization of Chunk::Search. + * + * @param type category to search for + * @param scope code parts to consider for search + * @param dir search direction + * @param level nesting level to match or ANY_LEVEL + * @return pointer to the found chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *SearchTypeLevel(const E_Token type, const E_Scope scope = E_Scope::ALL, const E_Direction dir = E_Direction::FORWARD, const int level = ANY_LEVEL) const; + + /** + * @brief searches a chunk that holds a specific string + * + * Traverses a chunk list either in forward or backward direction until a chunk + * with the provided string was found. Additionally a nesting level can be + * provided to narrow down the search. + * + * @param cStr string that searched chunk needs to have + * @param len length of the string + * @param level nesting level of the searched chunk, ignored when negative + * @param scope code parts to consider for search + * @param dir search direction + * @return pointer to the found chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *SearchStringLevel(const char *cStr, const size_t len, const int level, const E_Scope scope = E_Scope::ALL, const E_Direction dir = E_Direction::FORWARD) const; + + /** + * @brief returns the closing match for the current paren/brace/square. + * @param scope chunk section to consider + * @return pointer to the next matching chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetClosingParen(E_Scope scope = E_Scope::ALL) const; + + /** + * @brief returns the opening match for the current paren/brace/square. + * @param scope chunk section to consider + * @return pointer to the prev matching chunk or Chunk::NullChunkPtr if no chunk was found + */ + Chunk *GetOpeningParen(E_Scope scope = E_Scope::ALL) const; + + + // --------- Is* functions + + /** + * @brief checks whether the chunk is a specific token + * @token the token to check for + * @return true if the chunk type matches the specified token, false otherwise + */ + bool Is(E_Token token) const; + + /** + * @brief checks whether the chunk token name is a specific string + * @param cStr string to compare token name with + * @param caseSensitive whether to do a case sensitive or insensitive comparison + * @return true if the chunk token name matches the specified string, false otherwise + */ + bool IsString(const char *cStr, bool caseSensitive = true) const; + + /** + * @brief checks whether the chunk is not a specific token + * @token the token to check for + * @return true if the chunk type does not matches the specified token, false otherwise + */ + bool IsNot(E_Token token) const; + + /** + * @brief checks whether the chunk is a newline + * @return true if the chunk is a newline, false otherwise + */ + bool IsNewline() const; + + /** + * @brief checks whether the chunk is a comment + * This means any kind of: + * - single line comment + * - multiline comment + * - C comment + * - C++ comment + */ + bool IsComment() const; + + /** + * @brief checks whether the chunk is valid and has an empty text + * @return true if the chunk is valid and has an empty text + */ + bool IsEmptyText() const; + + /** + * @brief checks whether the chunk is a preprocessor + * @return true if the chunk is a preprocessor, false otherwise + */ + bool IsPreproc() const; + + /** + * @brief checks whether the other chunk has the same preproc flags + * @return true if the other chunk has the same preproc flags + */ + bool IsSamePreproc(const Chunk *other) const; + + /** + * @brief checks whether the chunk is either a comment or a newline + * @return true if the chunk is either a comment or a newline, false otherwise + */ + bool IsCommentOrNewline() const; + + /** + * @brief checks whether the chunk is either a comment, a newline or ignored + * @return true if the chunk is either a comment, a newline or ignored, false otherwise + */ + bool IsCommentNewlineOrIgnored() const; + + /** + * @brief checks whether the chunk is a comment, a newline or a preprocessor + * @return true if the chunk is a comment, a newline or a preprocessor, false otherwise + */ + bool IsCommentNewlineOrPreproc() const; + + /** + * @brief checks whether the chunk is a preprocessor and either a comment or a newline + * @return true if the chunk is a preprocessor and either a comment or a newline, false otherwise + */ + bool IsCommentOrNewlineInPreproc() const; + + /** + * @brief checks whether the chunk is a comment, a newline or has an empty text + * @return true if the chunk is a comment, a newline or has an empty text + */ + bool IsCommentNewlineOrEmptyText() const; + + /** + * @brief checks whether the chunk is a single line comment + * @return true if the chunk is a single line comment + */ + bool IsSingleLineComment() const; + + /** + * @brief checks whether the chunk is a Doxygen comment + * @return true if the chunk is a Doxygen comment + */ + bool IsDoxygenComment() const; + + /** + * @brief checks whether the chunk is a square bracket + * @return true if the chunk is a square bracket + */ + bool IsSquareBracket() const; + + /** + * @brief checks whether the chunk is a virtual brace + * @return true if the chunk is a virtual brace + */ + bool IsVBrace() const; + + /** + * @brief checks whether the chunk matches a given type and level + * @param type category to search for + * @param level nesting level to match + * @return true if the chunk matches a given type and level + */ + bool IsTypeAndLevel(const E_Token type, const int level) const; + + /** + * @brief checks whether the chunk matches a given string and level + * @param cStr the expected string + * @param len length of the string + * @param caseSensitive whether to do a case sensitive or insensitive comparison + * @param level nesting level of the searched chunk, ignored when negative + * @return true if the chunk matches a given string and level + */ + bool IsStringAndLevel(const char *cStr, const size_t len, bool caseSensitive, const int level) const; + + /** + * @brief checks whether the chunk is a star/asterisk + * @return true if the chunk is a star/asterisk + */ + bool IsStar() const; + + /** + * @brief checks whether the chunk is a colon + * @return true if the chunk is a colon + */ + bool IsColon() const; + + /** + * @brief checks whether the chunk is a semicolon + * @return true if the chunk is a semicolon + */ + bool IsSemicolon() const; + + /** + * @brief checks whether the chunk is a pointer operator + * @return true if the chunk is a pointer operator + */ + bool IsPointerOperator() const; + + /** + * @brief checks whether the chunk is a pointer or a reference + * @return true if the chunk is a pointer or a reference + */ + bool IsPointerOrReference() const; + + /** + * @brief checks whether the chunk is an inheritance access specifier + * @return true if the chunk is an inheritance access specifier + */ + bool IsCppInheritanceAccessSpecifier() const; + + /** + * @brief checks whether the chunk is a pointer, reference or a qualifier + * @return true if the chunk is a pointer, reference or a qualifier + */ + bool IsPointerReferenceOrQualifier() const; + + /** + * @brief checks whether the chunk is an address + * @return true if the chunk is an address + */ + bool IsAddress() const; + + /** + * @brief checks whether the chunk is a MS reference + * @return true if the chunk is a MS reference + * NOTE: MS compilers for C++/CLI and WinRT use '^' instead of '*' + * for marking up reference types vs pointer types + */ + bool IsMsRef() const; + + /** + * @brief checks whether the chunk is nullable + * @return true if the chunk is nullable + */ + bool IsNullable() const; + + /** + * @brief Checks if a given chunk is the last on its line + * @return true or false depending on whether a given chunk is the last on its line + */ + bool IsLastChunkOnLine() const; + + /** + * @brief checks whether the current chunk is on same line of the given 'end' chunk. + * The current chunk must be before the 'end' chunk + * @param end the end chunk + * @return true if there is no newline between the current chunk and end chunk + */ + bool IsOnSameLine(const Chunk *end) const; + + /** + * @brief checks whether the chunk is an opening brace + * @return true if the chunk is an opening brace + */ + bool IsBraceOpen() const; + + /** + * @brief checks whether the chunk is a closing brace + * @return true if the chunk is a closing brace + */ + bool IsBraceClose() const; + + /** + * @brief checks whether the chunk is an opening parenthesis + * @return true if the chunk is an opening parenthesis + */ + bool IsParenOpen() const; + + /** + * @brief checks whether the chunk is a closing parenthesis + * @return true if the chunk is a closing parenthesis + */ + bool IsParenClose() const; + + /** + * @brief checks if a chunk points to the opening parentheses of a + * for (...in...) loop in Objective-C. + * @return true if the chunk is the opening parentheses of a for-in loop + */ + bool IsOCForinOpenParen() const; + + /** + * @brief checks whether the chunk is a type defining token + * @return true if the chunk is a type defining token + */ + bool IsTypeDefinition() const; + + /** + * @brief checks whether the chunk is a word + * @return true if the chunk is a word + */ + bool IsWord() const; + + /** + * @brief checks whether the chunk is an enum or an enum class + * @return true if the chunk is an enum or an enum class + */ + bool IsEnum() const; + + /** + * @brief checks whether the chunk is a class or a struct + * @return true if the chunk is a class or a struct + */ + bool IsClassOrStruct() const; + + /** + * @brief checks whether the chunk is a class, struct or union + * @return true if the chunk is a class, struct or union + */ + bool IsClassStructOrUnion() const; + + /** + * @brief checks whether the chunk is a class, enum, struct or union + * @return true if the chunk is a class, enum, struct or union + */ + bool IsClassEnumStructOrUnion() const; + + /** + * @brief checks whether there is a newline between this chunk and the other + * @return true if there is a newline between this chunk and the other + */ + bool IsNewlineBetween(const Chunk *other) const; + + + // --------- Util functions + + /** + * @brief delete the chunk from the chunk list + * @param pc the chunk to remove from the list + */ + static void Delete(Chunk * &pc); + + /** + * @brief add a copy of this chunk after the given position in a chunk list. + * @note If pos is NullChunk, add at the tail of the chunk list + * @param pos insert position in list + * @return pointer to the newly added chunk + */ + Chunk *CopyAndAddAfter(Chunk *pos) const; + + /** + * @brief add a copy of this chunk before the given position in a chunk list. + * @note If pos is NullChunk, add at the head of the chunk list + * @param pos insert position in list + * @return pointer to the newly added chunk + */ + Chunk *CopyAndAddBefore(Chunk *pos) const; + + /** + * @brief move the chunk after the reference position in the chunk list + * @param ref chunk after which to move the current chunk + */ + void MoveAfter(Chunk *ref); + + /** + * @brief swaps the place of this chunk with the given one + * @param other the other chunk + */ + void Swap(Chunk *other); + + /** + * @brief swaps the two lines that are started by the current chunk and the other chunk + * @param other the other chunk + */ + void SwapLines(Chunk *other); + + //! + /** + * @brief skips to the final word/type in a :: chain + * @return pointer to the chunk after the final word/type in a :: chain + */ + Chunk *SkipDcMember() const; + + /** + * @brief compare the positions of the chunk with another one + * @param other the other chunk + * @return returns -1 if this chunk comes first, +1 if it comes after, or 0. + */ + int ComparePosition(const Chunk *other) const; + + /** + * Returns true if it is safe to delete the newline token. + * The prev and next chunks must have the same PCF_IN_PREPROC flag AND + * the newline can't be after a C++ comment. + */ + bool SafeToDeleteNl() const; + + +protected: + // --------- Protected util functions + + /** + * @brief copy the values from another chunk. + * @NOTE: this is a partial copy only: the chunk is not linked to others + * @param o the chunk to copy from + */ + void CopyFrom(const Chunk &o); + + /** + * @brief add a copy of this chunk before/after the given position in a chunk list. + * @note If pos is NullChunk, add the new chuck either at the head or tail of the + * list based on the specified direction. + * @param pos insert position in list + * @param dir insert before or after the given position chunk + * @return pointer to the newly added chunk + */ + Chunk *CopyAndAdd(Chunk *pos, const E_Direction dir = E_Direction::FORWARD) const; + + /** + * @brief set and/or clear the chunk flags + * @param setBits the flag bits to set + * @param resetBits the flag bits to reset + */ + void SetResetFlags(T_PcfFlags resetBits, T_PcfFlags setBits); + + + // --------- Data members + E_Token m_type; //! type of the chunk itself + E_Token m_parentType; //! type of the parent chunk usually CT_NONE + size_t m_origLine; //! line number of chunk in input file + size_t m_origCol; //! column where chunk started in the input file, is always > 0 + size_t m_origColEnd; //! column where chunk ended in the input file, is always > 1 + size_t m_origPrevSp; //! whitespace before this token + size_t m_column; //! column of the chunk + size_t m_columnIndent; //! if 1st chunk on a line, set to the 'indent' column, which may + //! be less than the real column used to indent with tabs + size_t m_nlCount; //! number of newlines in CT_NEWLINE + size_t m_nlColumn; //! column of the subsequent newline entries(all of them should have the same column) + size_t m_level; //! nest level in {, (, or [. Only to help vim command } + size_t m_braceLevel; //! nest level in braces only + size_t m_ppLevel; //! nest level in preprocessor + bool m_afterTab; //! whether this token was after a tab + + T_PcfFlags m_flags; //! see PCF_xxx + T_AlignData m_alignmentData; //! alignment data of the chunk + T_IndentData m_indentData; //! indentation data of the chunk + + Chunk *m_next; //! pointer to next chunk in list + Chunk *m_prev; //! pointer to previous chunk in list + Chunk *m_parent; //! pointer to parent chunk (not always set) + + unc_text m_str; //! the token text + track_list *m_trackingData; //! for debugging purpose only + + +private: + const bool null_chunk; //! true for null chunks + + +public: + static Chunk NullChunk; //! Null Chunk + static Chunk *const NullChunkPtr; //! Pointer to the Null Chunk +}; + + +inline Chunk::Chunk(bool null_c) + : null_chunk(null_c) +{ + Reset(); +} + + +inline Chunk::Chunk(const Chunk &o) + : null_chunk(o.null_chunk) +{ + CopyFrom(o); +} + + +inline Chunk &Chunk::operator=(const Chunk &o) +{ + if (this != &o) + { + CopyFrom(o); + } + return(*this); +} + + +inline size_t Chunk::Len() const +{ + return(m_str.size()); +} + + +inline const char *Chunk::Text() const +{ + return(m_str.c_str()); +} + + +inline Chunk *Chunk::GetParent() const +{ + return(m_parent); +} + + +inline void Chunk::SetParent(Chunk *parent) +{ + if (this != parent) + { + m_parent = parent; + } +} + + +inline const T_AlignData &Chunk::GetAlignmentData() const +{ + return(m_alignmentData); +} + + +inline T_AlignData &Chunk::AlignmentData() +{ + return(m_alignmentData); +} + + +inline const T_IndentData &Chunk::GetIndentData() const +{ + return(m_indentData); +} + + +inline T_IndentData &Chunk::IndentData() +{ + return(m_indentData); +} + + +inline const unc_text &Chunk::GetStr() const +{ + return(m_str); +} + + +inline unc_text &Chunk::Str() +{ + return(m_str); +} + + +inline const track_list *Chunk::GetTrackingData() const +{ + return(m_trackingData); +} + + +inline track_list * &Chunk::TrackingData() +{ + return(m_trackingData); +} + + +inline E_Token Chunk::GetType() const +{ + return(m_type); +} + + +inline E_Token Chunk::GetParentType() const +{ + return(m_parentType); +} + + +inline E_Token Chunk::GetTypeOfParent() const +{ + if (GetParent()->IsNullChunk()) + { + return(CT_PARENT_NOT_SET); + } + return(GetParent()->GetType()); +} + + +inline T_PcfFlags Chunk::GetFlags() const +{ + return(m_flags); +} + + +inline void Chunk::SetFlags(T_PcfFlags flags) +{ + m_flags = flags; +} + + +inline bool Chunk::TestFlags(T_PcfFlags flags) const +{ + return(m_flags.test(flags)); +} + + +inline void Chunk::ResetFlagBits(T_PcfFlags resetBits) +{ + SetResetFlags(resetBits, PCF_NONE); +} + + +inline void Chunk::SetFlagBits(T_PcfFlags setBits) +{ + SetResetFlags(PCF_NONE, setBits); +} + + +inline void Chunk::UpdateFlagBits(T_PcfFlags resetBits, T_PcfFlags setBits) +{ + SetResetFlags(resetBits, setBits); +} + + +inline size_t Chunk::GetOrigLine() const +{ + return(m_origLine); +} + + +inline void Chunk::SetOrigLine(size_t line) +{ + m_origLine = line; +} + + +inline size_t Chunk::GetOrigCol() const +{ + return(m_origCol); +} + + +inline void Chunk::SetOrigCol(size_t col) +{ + m_origCol = col; +} + + +inline size_t Chunk::GetOrigColEnd() const +{ + return(m_origColEnd); +} + + +inline void Chunk::SetOrigColEnd(size_t col) +{ + m_origColEnd = col; +} + + +inline size_t Chunk::GetOrigPrevSp() const +{ + return(m_origPrevSp); +} + + +inline void Chunk::SetOrigPrevSp(size_t col) +{ + m_origPrevSp = col; +} + + +inline size_t Chunk::GetColumn() const +{ + return(m_column); +} + + +inline void Chunk::SetColumn(size_t col) +{ + m_column = col; +} + + +inline size_t Chunk::GetColumnIndent() const +{ + return(m_columnIndent); +} + + +inline void Chunk::SetColumnIndent(size_t col) +{ + m_columnIndent = col; +} + + +inline size_t Chunk::GetNlCount() const +{ + return(m_nlCount); +} + + +inline void Chunk::SetNlCount(size_t cnt) +{ + m_nlCount = cnt; +} + + +inline size_t Chunk::GetNlColumn() const +{ + return(m_nlColumn); +} + + +inline void Chunk::SetNlColumn(size_t col) +{ + m_nlColumn = col; +} + + +inline size_t Chunk::GetLevel() const +{ + return(m_level); +} + + +inline void Chunk::SetLevel(size_t level) +{ + m_level = level; +} + + +inline size_t Chunk::GetBraceLevel() const +{ + return(m_braceLevel); +} + + +inline void Chunk::SetBraceLevel(size_t lvl) +{ + m_braceLevel = lvl; +} + + +inline size_t Chunk::GetPpLevel() const +{ + return(m_ppLevel); +} + + +inline void Chunk::SetPpLevel(size_t lvl) +{ + m_ppLevel = lvl; +} + + +inline bool Chunk::GetAfterTab() const +{ + return(m_afterTab); +} + + +inline void Chunk::SetAfterTab(bool afterTab) +{ + m_afterTab = afterTab; +} + + +inline Chunk *Chunk::GetNextNl(const E_Scope scope) const +{ + return(Search(&Chunk::IsNewline, scope, E_Direction::FORWARD, true)); +} + + +inline Chunk *Chunk::GetPrevNl(const E_Scope scope) const +{ + return(Search(&Chunk::IsNewline, scope, E_Direction::BACKWARD, true)); +} + + +inline Chunk *Chunk::GetNextNnl(const E_Scope scope) const +{ + return(Search(&Chunk::IsNewline, scope, E_Direction::FORWARD, false)); +} + + +inline Chunk *Chunk::GetPrevNnl(const E_Scope scope) const +{ + return(Search(&Chunk::IsNewline, scope, E_Direction::BACKWARD, false)); +} + + +inline Chunk *Chunk::GetNextNc(const E_Scope scope) const +{ + return(Search(&Chunk::IsComment, scope, E_Direction::FORWARD, false)); +} + + +inline Chunk *Chunk::GetPrevNc(const E_Scope scope) const +{ + return(Search(&Chunk::IsComment, scope, E_Direction::BACKWARD, false)); +} + + +inline Chunk *Chunk::GetNextNcNnl(const E_Scope scope) const +{ + return(Search(&Chunk::IsCommentOrNewline, scope, E_Direction::FORWARD, false)); +} + + +inline Chunk *Chunk::GetPrevNcNnl(const E_Scope scope) const +{ + return(Search(&Chunk::IsCommentOrNewline, scope, E_Direction::BACKWARD, false)); +} + + +inline Chunk *Chunk::GetNextNcNnlNpp(const E_Scope scope) const +{ + return(Search(&Chunk::IsCommentNewlineOrPreproc, scope, E_Direction::FORWARD, false)); +} + + +inline Chunk *Chunk::GetPrevNcNnlNpp(const E_Scope scope) const +{ + return(Search(&Chunk::IsCommentNewlineOrPreproc, scope, E_Direction::BACKWARD, false)); +} + + +inline Chunk *Chunk::GetNextNppOrNcNnl(const E_Scope scope) const +{ + return(Search(&Chunk::IsCommentOrNewlineInPreproc, scope, E_Direction::FORWARD, false)); +} + + +inline Chunk *Chunk::GetPrevNppOrNcNnl(const E_Scope scope) const +{ + return(Search(&Chunk::IsCommentOrNewlineInPreproc, scope, E_Direction::BACKWARD, false)); +} + + +inline Chunk *Chunk::PpaGetNextNcNnl() const +{ + return(SearchPpa(&Chunk::IsCommentOrNewline, false)); +} + + +inline Chunk *Chunk::GetNextNcNnlNet(const E_Scope scope) const +{ + return(Search(&Chunk::IsCommentNewlineOrEmptyText, scope, E_Direction::FORWARD, false)); +} + + +inline Chunk *Chunk::GetPrevNcNnlNet(const E_Scope scope) const +{ + return(Search(&Chunk::IsCommentNewlineOrEmptyText, scope, E_Direction::BACKWARD, false)); +} + + +inline Chunk *Chunk::GetPrevNcNnlNi(const E_Scope scope) const +{ + return(Search(&Chunk::IsCommentNewlineOrIgnored, scope, E_Direction::BACKWARD, false)); +} + + +inline Chunk *Chunk::GetNextNisq(const E_Scope scope) const +{ + return(Search(&Chunk::IsSquareBracket, scope, E_Direction::FORWARD, false)); +} + + +inline Chunk *Chunk::GetNextType(const E_Token type, const int level, const E_Scope scope) const +{ + return(SearchTypeLevel(type, scope, E_Direction::FORWARD, level)); +} + + +inline Chunk *Chunk::GetPrevType(const E_Token type, const int level, const E_Scope scope) const +{ + return(SearchTypeLevel(type, scope, E_Direction::BACKWARD, level)); +} + + +inline Chunk *Chunk::GetNextString(const char *cStr, const size_t len, const int level, const E_Scope scope) const +{ + return(SearchStringLevel(cStr, len, level, scope, E_Direction::FORWARD)); +} + + +inline Chunk *Chunk::GetPrevString(const char *cStr, const size_t len, const int level, const E_Scope scope) const +{ + return(SearchStringLevel(cStr, len, level, scope, E_Direction::BACKWARD)); +} + + +inline Chunk *Chunk::GetNextNvb(const E_Scope scope) const +{ + return(Search(&Chunk::IsVBrace, scope, E_Direction::FORWARD, false)); +} + + +inline Chunk *Chunk::GetPrevNvb(const E_Scope scope) const +{ + return(Search(&Chunk::IsVBrace, scope, E_Direction::BACKWARD, false)); +} + + +inline bool Chunk::IsTypeAndLevel(const E_Token type, const int level) const +{ + return( ( level < 0 + || m_level == static_cast<size_t>(level)) + && m_type == type); +} + + +inline bool Chunk::Is(E_Token token) const +{ + return( IsNotNullChunk() + && m_type == token); +} + + +inline bool Chunk::IsString(const char *cStr, bool caseSensitive) const +{ + return(IsStringAndLevel(cStr, strlen(cStr), caseSensitive, ANY_LEVEL)); +} + + +inline bool Chunk::IsNot(E_Token token) const +{ + return(!Is(token)); +} + + +inline bool Chunk::IsNewline() const +{ + return( Is(CT_NEWLINE) + || Is(CT_NL_CONT)); +} + + +inline bool Chunk::IsComment() const +{ + return( Is(CT_COMMENT) + || Is(CT_COMMENT_MULTI) + || Is(CT_COMMENT_CPP)); +} + + +inline bool Chunk::IsEmptyText() const +{ + return( IsNotNullChunk() + && Len() == 0); +} + + +inline bool Chunk::IsPreproc() const +{ + return( IsNotNullChunk() + && TestFlags(PCF_IN_PREPROC)); +} + + +inline bool Chunk::IsCommentOrNewline() const +{ + return( IsComment() + || IsNewline()); +} + + +inline bool Chunk::IsCommentNewlineOrPreproc() const +{ + return( IsComment() + || IsNewline() + || IsPreproc()); +} + + +inline bool Chunk::IsCommentOrNewlineInPreproc() const +{ + return( IsPreproc() + && ( IsComment() + || IsNewline())); +} + + +inline bool Chunk::IsCommentNewlineOrEmptyText() const +{ + return( IsComment() + || IsNewline() + || IsEmptyText()); +} + + +inline bool Chunk::IsCommentNewlineOrIgnored() const +{ + return( IsComment() + || IsNewline() + || Is(CT_IGNORED)); +} + + +inline bool Chunk::IsSingleLineComment() const +{ + return( Is(CT_COMMENT) + || Is(CT_COMMENT_CPP)); +} + + +inline bool Chunk::IsSquareBracket() const +{ + return( Is(CT_SQUARE_OPEN) + || Is(CT_TSQUARE) + || Is(CT_SQUARE_CLOSE)); +} + + +inline bool Chunk::IsVBrace() const +{ + return( Is(CT_VBRACE_OPEN) + || Is(CT_VBRACE_CLOSE)); +} + + +inline bool Chunk::IsStar() const +{ + return( Len() == 1 + && m_str[0] == '*' + && IsNot(CT_OPERATOR_VAL)); +} + + +inline bool Chunk::IsSemicolon() const +{ + return( Is(CT_SEMICOLON) + || Is(CT_VSEMICOLON)); +} + + +inline bool Chunk::IsWord() const +{ + return( Len() >= 1 + && CharTable::IsKw1(m_str[0])); +} + + +inline bool Chunk::IsNullable() const +{ + return( language_is_set(LANG_CS | LANG_VALA) + && Len() == 1 + && m_str[0] == '?'); +} + + +inline bool Chunk::IsMsRef() const +{ + return( language_is_set(LANG_CPP) + && Len() == 1 + && m_str[0] == '^' + && IsNot(CT_OPERATOR_VAL)); +} + + +inline bool Chunk::IsPointerOperator() const +{ + return( IsStar() + || IsAddress() + || IsMsRef() + || IsNullable()); +} + + +inline bool Chunk::IsPointerOrReference() const +{ + return( IsPointerOperator() + || Is(CT_BYREF)); +} + + +inline bool Chunk::IsBraceOpen() const +{ + return( Is(CT_BRACE_OPEN) + || Is(CT_VBRACE_OPEN)); +} + + +inline bool Chunk::IsBraceClose() const +{ + return( Is(CT_BRACE_CLOSE) + || Is(CT_VBRACE_CLOSE)); +} + + +inline bool Chunk::IsParenOpen() const +{ + return( Is(CT_PAREN_OPEN) + || Is(CT_SPAREN_OPEN) + || Is(CT_PPAREN_OPEN) + || Is(CT_TPAREN_OPEN) + || Is(CT_FPAREN_OPEN) + || Is(CT_LPAREN_OPEN)); +} + + +inline bool Chunk::IsParenClose() const +{ + return( Is(CT_PAREN_CLOSE) + || Is(CT_SPAREN_CLOSE) + || Is(CT_PPAREN_CLOSE) + || Is(CT_TPAREN_CLOSE) + || Is(CT_FPAREN_CLOSE) + || Is(CT_LPAREN_CLOSE)); +} + + +inline bool Chunk::IsSamePreproc(const Chunk *other) const +{ + return( IsNotNullChunk() + && other->IsNotNullChunk() + && (TestFlags(PCF_IN_PREPROC) == other->TestFlags(PCF_IN_PREPROC))); +} + + +inline bool Chunk::SafeToDeleteNl() const +{ + Chunk *tmp = GetPrev(); + + if (tmp->Is(CT_COMMENT_CPP)) + { + return(false); + } + return(tmp->IsSamePreproc(GetNext())); +} + + +inline bool Chunk::IsEnum() const +{ + return( Is(CT_ENUM) + || Is(CT_ENUM_CLASS)); +} + + +inline bool Chunk::IsClassOrStruct() const +{ + return( Is(CT_CLASS) + || Is(CT_STRUCT)); +} + + +inline bool Chunk::IsClassStructOrUnion() const +{ + return( IsClassOrStruct() + || Is(CT_UNION)); +} + + +inline bool Chunk::IsClassEnumStructOrUnion() const +{ + return( IsClassStructOrUnion() + || IsEnum()); +} + + +inline Chunk *Chunk::CopyAndAddAfter(Chunk *ref) const +{ + return(CopyAndAdd(ref, E_Direction::FORWARD)); +} + + +inline Chunk *Chunk::CopyAndAddBefore(Chunk *ref) const +{ + return(CopyAndAdd(ref, E_Direction::BACKWARD)); +} + + +#define SetType(tt) SetTypeReal((tt), __unqualified_func__, __LINE__) + + +#define SetParentType(tt) SetParentTypeReal((tt), __unqualified_func__, __LINE__) + + +#endif /* CHUNK_LIST_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine.cpp new file mode 100644 index 00000000..d7f95472 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine.cpp @@ -0,0 +1,4088 @@ +/** + * @file combine.cpp + * Labels the chunks as needed. + * + * @author Ben Gardner + * @author Guy Maurel + * @license GPL v2+ + */ + +#include "combine.h" + +#include "combine_fix_mark.h" +#include "combine_skip.h" +#include "combine_tools.h" +#include "EnumStructUnionParser.h" +#include "flag_braced_init_list.h" +#include "flag_parens.h" +#include "lang_pawn.h" +#include "mark_question_colon.h" +#include "newlines.h" +#include "prototypes.h" +#include "tokenize_cleanup.h" +#include "unc_tools.h" + +#include <limits> + +constexpr static auto LCURRENT = LCOMBINE; + +using namespace std; +using namespace uncrustify; + + +/** + * Mark the parens and colons in: + * asm volatile ( "xx" : "xx" (l), "yy"(h) : ... ); + * + * @param pc the CT_ASM item + */ +static void flag_asm(Chunk *pc); + + +/** + * Combines two tokens into {{ and }} if inside parens and nothing is between + * either pair. + */ +static void check_double_brace_init(Chunk *bo1); + + +static void process_returns_and_throws(); + + +/** + * Processes a 'return' or 'throw' statement, labeling the parens and marking + * the parent. May remove or add parens around the return/throw statement. + * + * @param pc Pointer to the return or throw chunk + */ +static Chunk *process_return_or_throw(Chunk *pc); + + +/** + * Process an ObjC 'class' + * pc is the chunk after '@implementation' or '@interface' or '@protocol'. + * Change colons, etc. Processes stuff until '@end'. + * Skips anything in braces. + */ +static void handle_oc_class(Chunk *pc); + + +/** + * Mark Objective-C blocks (aka lambdas or closures) + * The syntax and usage is exactly like C function pointers + * but instead of an asterisk they have a caret as pointer symbol. + * Although it may look expensive this functions is only triggered + * on appearance of an OC_BLOCK_CARET for LANG_OC. + * repeat(10, ^{ putc('0'+d); }); + * typedef void (^workBlk_t)(void); + * + * @param pc points to the '^' + */ +static void handle_oc_block_literal(Chunk *pc); + + +/** + * Mark Objective-C block types. + * The syntax and usage is exactly like C function pointers + * but instead of an asterisk they have a caret as pointer symbol. + * typedef void (^workBlk_t)(void); + * const char * (^workVar)(void); + * -(void)Foo:(void(^)())blk { } + * + * This is triggered when the sequence '(' '^' is found. + * + * @param pc points to the '^' + */ +static void handle_oc_block_type(Chunk *pc); + + +/** + * Process an ObjC message spec/dec + * + * Specs: + * -(void) foo ARGS; + * + * Declaration: + * -(void) foo ARGS { } + * + * LABEL : (ARGTYPE) ARGNAME + * + * ARGS is ': (ARGTYPE) ARGNAME [MOREARGS...]' + * MOREARGS is ' [ LABEL] : (ARGTYPE) ARGNAME ' + * -(void) foo: (int) arg: { } + * -(void) foo: (int) arg: { } + * -(void) insertObject:(id)anObject atIndex:(int)index + */ +static void handle_oc_message_decl(Chunk *pc); + + +/** + * Process an ObjC message send statement: + * [ class func: val1 name2: val2 name3: val3] ; // named params + * [ class func: val1 : val2 : val3] ; // unnamed params + * [ class <proto> self method ] ; // with protocol + * [[NSMutableString alloc] initWithString: @"" ] // class from msg + * [func(a,b,c) lastObject ] // class from func + * + * Mainly find the matching ']' and ';' and mark the colons. + * + * @param pc points to the open square '[' + */ +static void handle_oc_message_send(Chunk *pc); + + +//! Process @Property values and re-arrange them if necessary +static void handle_oc_property_decl(Chunk *pc); + +//! Process @available annotation +static void handle_oc_available(Chunk *pc); + +/** + * Process a type that is enclosed in parens in message declarations. + * TODO: handle block types, which get special formatting + * + * @param pc points to the open paren + * + * @return the chunk after the type + */ +static Chunk *handle_oc_md_type(Chunk *paren_open, E_Token ptype, T_PcfFlags flags, bool &did_it); + +/** + * Process an C# [] thingy: + * [assembly: xxx] + * [AttributeUsage()] + * [@X] + * + * Set the next chunk to a statement start after the close ']' + * + * @param pc points to the open square '[' + */ +static void handle_cs_square_stmt(Chunk *pc); + + +/** + * We are on a brace open that is preceded by a word or square close. + * Set the brace parent to CT_CS_PROPERTY and find the first item in the + * property and set its parent, too. + */ +static void handle_cs_property(Chunk *pc); + + +/** + * We hit a ']' followed by a WORD. This may be a multidimensional array type. + * Example: int[,,] x; + * If there is nothing but commas between the open and close, then mark it. + */ +static void handle_cs_array_type(Chunk *pc); + + +/** + * We are on the C++ 'template' keyword. + * What follows should be the following: + * + * template <class identifier> function_declaration; + * template <typename identifier> function_declaration; + * template <class identifier> class class_declaration; + * template <typename identifier> class class_declaration; + * + * Change the 'class' inside the <> to CT_TYPE. + * Set the parent to the class after the <> to CT_TEMPLATE. + * Set the parent of the semicolon to CT_TEMPLATE. + */ +static void handle_cpp_template(Chunk *pc); + + +/** + * Verify and then mark C++ lambda expressions. + * The expected format is '[...](...){...}' or '[...](...) -> type {...}' + * sq_o is '[' CT_SQUARE_OPEN or '[]' CT_TSQUARE + * Split the '[]' so we can control the space + */ +static void handle_cpp_lambda(Chunk *pc); + + +/** + * We are on the D 'template' keyword. + * What follows should be the following: + * + * template NAME ( TYPELIST ) { BODY } + * + * Set the parent of NAME to template, change NAME to CT_TYPE. + * Set the parent of the parens and braces to CT_TEMPLATE. + * Scan the body for each type in TYPELIST and change the type to CT_TYPE. + */ +static void handle_d_template(Chunk *pc); + + +/** + * A func wrap chunk and what follows should be treated as a function name. + * Create new text for the chunk and call it a CT_FUNCTION. + * + * A type wrap chunk and what follows should be treated as a simple type. + * Create new text for the chunk and call it a CT_TYPE. + */ +static void handle_wrap(Chunk *pc); + + +/** + * A proto wrap chunk and what follows should be treated as a function proto. + * + * RETTYPE PROTO_WRAP( NAME, PARAMS ); or RETTYPE PROTO_WRAP( NAME, (PARAMS) ); + * RETTYPE gets changed with make_type(). + * PROTO_WRAP is marked as CT_FUNC_PROTO or CT_FUNC_DEF. + * NAME is marked as CT_WORD. + * PARAMS is all marked as prototype parameters. + */ +static void handle_proto_wrap(Chunk *pc); + + +static bool is_oc_block(Chunk *pc); + + +/** + * Java assert statements are: "assert EXP1 [: EXP2] ;" + * Mark the parent of the colon and semicolon + */ +static void handle_java_assert(Chunk *pc); + + +static void flag_asm(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + Chunk *tmp = pc->GetNextNcNnl(E_Scope::PREPROC); + + if (tmp->IsNot(CT_QUALIFIER)) + { + return; + } + Chunk *po = tmp->GetNextNcNnl(E_Scope::PREPROC); + + if (!po->IsParenOpen()) + { + return; + } + Chunk *end = po->GetClosingParen(E_Scope::PREPROC); + + if (end->IsNullChunk()) + { + return; + } + po->SetParentType(CT_ASM); + end->SetParentType(CT_ASM); + + for ( tmp = po->GetNextNcNnl(E_Scope::PREPROC); + tmp->IsNotNullChunk() + && tmp != end; + tmp = tmp->GetNextNcNnl(E_Scope::PREPROC)) + { + if (tmp->Is(CT_COLON)) + { + tmp->SetType(CT_ASM_COLON); + } + else if (tmp->Is(CT_DC_MEMBER)) + { + // if there is a string on both sides, then this is two ASM_COLONs + if ( tmp->GetNextNcNnl(E_Scope::PREPROC)->Is(CT_STRING) + && tmp->GetPrevNcNnlNi(E_Scope::PREPROC)->Is(CT_STRING)) // Issue #2279 + { + Chunk nc; + + nc = *tmp; + + tmp->Str().resize(1); + tmp->SetOrigColEnd(tmp->GetOrigCol() + 1); + tmp->SetType(CT_ASM_COLON); + + nc.SetType(tmp->GetType()); + nc.Str().pop_front(); + nc.SetOrigCol(nc.GetOrigCol() + 1); + nc.SetColumn(nc.GetColumn() + 1); + nc.CopyAndAddAfter(tmp); + } + } + } + + tmp = end->GetNextNcNnl(E_Scope::PREPROC); + + if (tmp->IsNullChunk()) + { + return; + } + + if (tmp->Is(CT_SEMICOLON)) + { + tmp->SetParentType(CT_ASM); + } +} // flag_asm + + +void do_symbol_check(Chunk *prev, Chunk *pc, Chunk *next) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LFCNR, "%s(%d): prev is '%s' %s\n", + __func__, __LINE__, + prev->Text(), get_token_name(prev->GetType())); + log_pcf_flags(LFCNR, prev->GetFlags()); + LOG_FMT(LFCNR, "%s(%d): pc is '%s' %s\n", + __func__, __LINE__, + pc->Text(), get_token_name(pc->GetType())); + log_pcf_flags(LFCNR, pc->GetFlags()); + LOG_FMT(LFCNR, "%s(%d): next is '%s' %s\n", + __func__, __LINE__, + next->Text(), get_token_name(next->GetType())); + log_pcf_flags(LFCNR, next->GetFlags()); + + if ( pc->Is(CT_NOEXCEPT) // Issue #3284 + && next->Is(CT_ASSIGN)) // skip over noexcept + { + LOG_FMT(LFCNR, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc = next; + next = pc->GetNext(); + } + + // separate the uses of CT_ASSIGN sign '=' + // into CT_ASSIGN_DEFAULT_ARG, CT_ASSIGN_FUNC_PROTO + if ( pc->Is(CT_ASSIGN) + && pc->GetParentType() == CT_FUNC_PROTO + && ( pc->TestFlags(PCF_IN_FCN_DEF) // Issue #2236 + || pc->TestFlags(PCF_IN_CONST_ARGS))) + { + LOG_FMT(LFCNR, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + log_pcf_flags(LFCNR, pc->GetFlags()); + pc->SetType(CT_ASSIGN_DEFAULT_ARG); + return; + } + + if ( ( prev->Is(CT_FPAREN_CLOSE) + || ( ( prev->IsString("const") + || prev->IsString("override")) + && prev->GetPrev()->Is(CT_FPAREN_CLOSE))) + && pc->Is(CT_ASSIGN) + && ( next->Is(CT_DEFAULT) + || next->Is(CT_DELETE) + || next->IsString("0"))) + { + pc->SetType(CT_ASSIGN_FUNC_PROTO); + return; // cpp 30031 + } + + if (pc->Is(CT_OC_AT)) + { + if ( next->Is(CT_PAREN_OPEN) + || next->Is(CT_BRACE_OPEN) + || next->Is(CT_SQUARE_OPEN)) + { + flag_parens(next, PCF_OC_BOXED, next->GetType(), CT_OC_AT, false); + } + else + { + next->SetParentType(CT_OC_AT); + return; // objective-c_50095 + } + } + + // D stuff + if ( language_is_set(LANG_D) + && pc->Is(CT_QUALIFIER) + && pc->IsString("const") + && next->Is(CT_PAREN_OPEN)) + { + pc->SetType(CT_D_CAST); + set_paren_parent(next, pc->GetType()); + return; // d_40061 + } + + if ( next->Is(CT_PAREN_OPEN) + && ( pc->Is(CT_D_CAST) + || pc->Is(CT_DELEGATE) + || pc->Is(CT_ALIGN))) + { + // mark the parenthesis parent + Chunk *tmp = set_paren_parent(next, pc->GetType()); + + // For a D cast - convert the next item + if ( pc->Is(CT_D_CAST) + && tmp != nullptr) + { + if (tmp->Is(CT_STAR)) + { + tmp->SetType(CT_DEREF); + return; // d_40006 + } + else if (tmp->Is(CT_AMP)) + { + tmp->SetType(CT_ADDR); + return; // d_40060 + } + else if (tmp->Is(CT_MINUS)) + { + tmp->SetType(CT_NEG); + return; // d_40060 + } + else if (tmp->Is(CT_PLUS)) + { + tmp->SetType(CT_POS); + return; // d_40060 + } + } + + /* + * For a delegate, mark previous words as types and the item after the + * close paren as a variable def + */ + if (pc->Is(CT_DELEGATE)) + { + if (tmp != nullptr) + { + tmp->SetParentType(CT_DELEGATE); + + if (tmp->GetLevel() == tmp->GetBraceLevel()) + { + tmp->SetFlagBits(PCF_VAR_1ST_DEF); + } + } + + for (tmp = pc->GetPrevNcNnlNi(); tmp->IsNotNullChunk(); tmp = tmp->GetPrevNcNnlNi()) // Issue #2279 + { + if ( tmp->IsSemicolon() + || tmp->Is(CT_BRACE_OPEN) + || tmp->Is(CT_VBRACE_OPEN)) + { + break; + } + make_type(tmp); + } + + return; // c-sharp_10160 + } + + if ( pc->Is(CT_ALIGN) + && tmp != nullptr) + { + if (tmp->Is(CT_BRACE_OPEN)) + { + set_paren_parent(tmp, pc->GetType()); + return; // d_40024 + } + else if (tmp->Is(CT_COLON)) + { + tmp->SetParentType(pc->GetType()); + return; // d_40024 + } + } + } // paren open + cast/align/delegate + + if (pc->Is(CT_INVARIANT)) + { + if (next->Is(CT_PAREN_OPEN)) + { + next->SetParentType(pc->GetType()); + Chunk *tmp = next->GetNext(); + + if (tmp == nullptr) + { + tmp = Chunk::NullChunkPtr; + } + + while (tmp->IsNotNullChunk()) + { + if (tmp->Is(CT_PAREN_CLOSE)) + { + tmp->SetParentType(pc->GetType()); + break; + } + make_type(tmp); + tmp = tmp->GetNext(); + } + return; // d_40100 + } + else + { + pc->SetType(CT_QUALIFIER); + return; + } + } + + if ( prev->Is(CT_BRACE_OPEN) + && prev->GetParentType() != CT_CS_PROPERTY + && ( pc->Is(CT_GETSET) + || pc->Is(CT_GETSET_EMPTY))) + { + flag_parens(prev, PCF_NONE, CT_NONE, CT_GETSET, false); + return; + } + + if (pc->Is(CT_ASM)) + { + flag_asm(pc); + return; + } + + // clang stuff - A new derived type is introduced to C and, by extension, Objective-C, C++, and Objective-C++ + if (language_is_set(LANG_C | LANG_CPP | LANG_OC)) + { + if (pc->Is(CT_CARET)) + { + if ( pc->TestFlags(PCF_EXPR_START) + || pc->TestFlags(PCF_IN_PREPROC)) + { + handle_oc_block_literal(pc); + return; + } + } + } + + // Objective C stuff + if (language_is_set(LANG_OC)) + { + // Check for message declarations + if (pc->TestFlags(PCF_STMT_START)) + { + if ( ( pc->IsString("-") + || pc->IsString("+")) + && next->IsString("(")) + { + handle_oc_message_decl(pc); + return; + } + } + + if ( pc->TestFlags(PCF_EXPR_START) + || pc->TestFlags(PCF_IN_PREPROC)) + { + if (pc->Is(CT_SQUARE_OPEN)) + { + handle_oc_message_send(pc); + + // Only return early if the '[' was determined to be an OC MSG + // Otherwise, it could have been a lambda capture list (ie '[&]') + if (pc->GetParentType() == CT_OC_MSG) + { + return; // objective-c_50003 + } + } + } + + if (pc->Is(CT_OC_PROPERTY)) + { + handle_oc_property_decl(pc); + return; + } + + if (pc->Is(CT_OC_AVAILABLE)) + { + handle_oc_available(pc); + return; + } + } + + // C# and Vala stuff + if (language_is_set(LANG_CS | LANG_VALA)) + { + // '[assembly: xxx]' stuff + if ( language_is_set(LANG_CS) + && pc->TestFlags(PCF_EXPR_START) + && pc->Is(CT_SQUARE_OPEN)) + { + handle_cs_square_stmt(pc); + return; + } + + if ( language_is_set(LANG_CS) + && next->Is(CT_BRACE_OPEN) + && next->GetParentType() == CT_NONE + && ( pc->Is(CT_SQUARE_CLOSE) + || pc->Is(CT_ANGLE_CLOSE) + || pc->Is(CT_WORD))) + { + handle_cs_property(next); + return; + } + + if ( pc->Is(CT_SQUARE_CLOSE) + && next->Is(CT_WORD)) + { + handle_cs_array_type(pc); + return; + } + + if ( ( pc->Is(CT_LAMBDA) + || pc->Is(CT_DELEGATE)) + && next->Is(CT_BRACE_OPEN)) + { + set_paren_parent(next, pc->GetType()); + return; + } + + if ( language_is_set(LANG_CS) + && pc->Is(CT_WHEN) + && pc->GetNext()->IsNotNullChunk() + && pc->GetNext()->IsNot(CT_SPAREN_OPEN)) + { + pc->SetType(CT_WORD); + return; + } + } + + if ( language_is_set(LANG_JAVA) + && pc->Is(CT_LAMBDA) + && next->Is(CT_BRACE_OPEN)) + { + set_paren_parent(next, pc->GetType()); + return; + } + + if (pc->Is(CT_NEW)) + { + Chunk *ts = nullptr; + Chunk *tmp = next; + + if (tmp->Is(CT_TSQUARE)) + { + ts = tmp; + tmp = tmp->GetNextNcNnl(); + } + + if ( tmp->Is(CT_BRACE_OPEN) + || tmp->Is(CT_PAREN_OPEN)) + { + set_paren_parent(tmp, pc->GetType()); + + if (ts != nullptr) + { + ts->SetParentType(pc->GetType()); + } + } + return; + } + + // C++11 Lambda stuff + if ( language_is_set(LANG_CPP) + && ( pc->Is(CT_SQUARE_OPEN) + || pc->Is(CT_TSQUARE))) + { + handle_cpp_lambda(pc); + } + + // FIXME: which language does this apply to? + // Issue #2432 + if (!language_is_set(LANG_OC)) + { + if ( pc->Is(CT_ASSIGN) + && next->Is(CT_SQUARE_OPEN)) + { + set_paren_parent(next, CT_ASSIGN); + + // Mark one-liner assignment + Chunk *tmp = next; + + while ((tmp = tmp->GetNextNc())->IsNotNullChunk()) + { + if (tmp->IsNewline()) + { + break; + } + + if ( tmp->Is(CT_SQUARE_CLOSE) + && next->GetLevel() == tmp->GetLevel()) + { + tmp->SetFlagBits(PCF_ONE_LINER); + next->SetFlagBits(PCF_ONE_LINER); + break; + } + } + return; + } + } + + if (pc->Is(CT_ASSERT)) + { + handle_java_assert(pc); + return; + } + + if (pc->Is(CT_ANNOTATION)) + { + Chunk *tmp = pc->GetNextNcNnl(); + + if (tmp->IsParenOpen()) + { + set_paren_parent(tmp, CT_ANNOTATION); + } + return; + } + + if ( pc->Is(CT_SIZEOF) + && language_is_set(LANG_ALLC)) + { + Chunk *tmp = pc->GetNextNcNnl(); + + if (tmp->Is(CT_ELLIPSIS)) + { + tmp->SetParentType(CT_SIZEOF); + } + return; + } + + if ( pc->Is(CT_DECLTYPE) + && pc->GetParentType() != CT_FUNC_DEF) + { + Chunk *tmp = pc->GetNextNcNnl(); + + if (tmp->IsParenOpen()) + { + // decltype may be followed by a braced-init-list + tmp = set_paren_parent(tmp, CT_DECLTYPE); + + if (tmp->IsBraceOpen() && !pc->TestFlags(PCF_IN_LAMBDA)) + { + tmp = set_paren_parent(tmp, CT_BRACED_INIT_LIST); + + if ( tmp != nullptr + && tmp->IsNotNullChunk()) + { + tmp->ResetFlagBits(PCF_EXPR_START | PCF_STMT_START); + } + } + else + { + if ( tmp != nullptr + && tmp->Is(CT_WORD)) + { + tmp->SetFlagBits(PCF_VAR_1ST_DEF); + } + } + } + return; + } + + // A [] in C#, D and Vala only follows a type + if ( pc->Is(CT_TSQUARE) + && language_is_set(LANG_D | LANG_CS | LANG_VALA)) + { + if (prev->Is(CT_WORD)) + { + prev->SetType(CT_TYPE); + } + + if (next->Is(CT_WORD)) + { + next->SetFlagBits(PCF_VAR_1ST_DEF); + } + return; + } + + if ( pc->Is(CT_SQL_EXEC) + || pc->Is(CT_SQL_BEGIN) + || pc->Is(CT_SQL_END)) + { + mark_exec_sql(pc); + return; + } + + if (pc->Is(CT_PROTO_WRAP)) + { + handle_proto_wrap(pc); + return; + } + + // Handle the typedef + if (pc->Is(CT_TYPEDEF)) + { + fix_typedef(pc); + return; + } + + if ( pc->IsClassEnumStructOrUnion() + && prev->IsNot(CT_TYPEDEF)) + { + // Issue #3811 + // Sometimes the enum chunk can exist in a parameter (ie. `void foo(enum EnumType param)`) + // In this case we don't need to run the parser since we are not declaring an enum. + if (pc->IsEnum()) + { + const size_t level = pc->GetLevel(); + Chunk *tmp = pc; + + while (tmp->GetLevel() == level && tmp->IsNotNullChunk()) + { + tmp = tmp->GetNextNcNnl(); + } + + if (tmp->GetLevel() < level) + { + return; + } + } + EnumStructUnionParser parser; + parser.parse(pc); + return; + } + + if (pc->Is(CT_EXTERN)) + { + if (next->IsParenOpen()) + { + Chunk *tmp = flag_parens(next, PCF_NONE, CT_NONE, CT_EXTERN, true); + + if ( tmp != nullptr + && tmp->Is(CT_BRACE_OPEN)) + { + set_paren_parent(tmp, CT_EXTERN); + } + } + else + { + // next likely is a string (see tokenize_cleanup.cpp) + next->SetParentType(CT_EXTERN); + Chunk *tmp = next->GetNextNcNnl(); + + if (tmp->Is(CT_BRACE_OPEN)) + { + set_paren_parent(tmp, CT_EXTERN); + } + } + return; + } + + if (pc->Is(CT_TEMPLATE)) + { + if (language_is_set(LANG_D)) + { + handle_d_template(pc); + } + else + { + handle_cpp_template(pc); + } + return; + } + + if ( pc->Is(CT_WORD) + && next->Is(CT_ANGLE_OPEN) + && next->GetParentType() == CT_TEMPLATE) + { + mark_template_func(pc, next); + return; + } + + if ( pc->Is(CT_SQUARE_CLOSE) + && next->Is(CT_PAREN_OPEN)) + { + flag_parens(next, PCF_NONE, CT_FPAREN_OPEN, CT_NONE, false); + return; + } + + if (pc->Is(CT_TYPE_CAST)) + { + fix_type_cast(pc); + return; + } + + if ( pc->GetParentType() == CT_ASSIGN + && ( pc->Is(CT_BRACE_OPEN) + || pc->Is(CT_SQUARE_OPEN))) + { + // Mark everything in here as in assign + flag_parens(pc, PCF_IN_ARRAY_ASSIGN, pc->GetType(), CT_NONE, false); + return; + } + + if (pc->Is(CT_D_TEMPLATE)) + { + set_paren_parent(next, pc->GetType()); + return; + } + + /* + * A word before an open paren is a function call or definition. + * CT_WORD => CT_FUNC_CALL or CT_FUNC_DEF + */ + if (next->Is(CT_PAREN_OPEN)) + { + Chunk *tmp = next->GetNextNcNnl(); + + if ( language_is_set(LANG_C | LANG_CPP | LANG_OC) + && tmp->Is(CT_CARET)) + { + handle_oc_block_type(tmp); + + // This is the case where a block literal is passed as the first argument of a C-style method invocation. + if ( ( tmp->Is(CT_OC_BLOCK_CARET) + || tmp->Is(CT_CARET)) + && pc->Is(CT_WORD)) + { + LOG_FMT(LFCN, "%s(%d): (1) SET TO CT_FUNC_CALL: orig line is %zu, orig col is %zu, Text() '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc->SetType(CT_FUNC_CALL); + } + } + else if ( pc->Is(CT_WORD) + || pc->Is(CT_OPERATOR_VAL)) + { + pc->SetType(CT_FUNCTION); + } + else if (pc->Is(CT_FIXED)) + { + pc->SetType(CT_FUNCTION); + pc->SetParentType(CT_FIXED); + } + else if (pc->Is(CT_TYPE)) + { + /* + * If we are on a type, then we are either on a C++ style cast, an + * array reference, a function or we are on a function type. + * The only way to tell for sure is to find the close paren and see + * if it is followed by an open paren. + * "int(5.6)" + * "int()" + * "int(foo)(void)" + * + * FIXME: this check can be done better... + */ + LOG_FMT(LFCNR, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + + bool is_byref_array = false; + + if (language_is_set(LANG_CPP)) + { + // If the open paren is followed by an ampersand, an optional word, + // a close parenthesis, and an open square bracket, then it is an + // array being passed by reference, not a cast + tmp = next->GetNextNcNnl(); + + if (tmp->Is(CT_AMP)) + { + auto tmp2 = tmp->GetNextNcNnl(); + + if (tmp2->Is(CT_WORD)) + { + tmp2 = tmp2->GetNextNcNnl(); + } + + if (tmp2->Is(CT_PAREN_CLOSE)) + { + tmp2 = tmp2->GetNextNcNnl(); + + if (tmp2->Is(CT_SQUARE_OPEN)) + { + is_byref_array = true; + tmp->SetType(CT_BYREF); + } + } + } + } + + if (!is_byref_array) + { + tmp = next->GetNextType(CT_PAREN_CLOSE, next->GetLevel()); + + if (tmp->IsNotNullChunk()) + { + tmp = tmp->GetNext(); + + if (tmp->Is(CT_PAREN_OPEN)) + { + pc->SetType(CT_FUNCTION); + } + else + { + if ( pc->GetParentType() == CT_NONE + && !pc->TestFlags(PCF_IN_TYPEDEF)) + { + tmp = next->GetNextNcNnl(); + + if (tmp->Is(CT_PAREN_CLOSE)) + { + // we have TYPE() + pc->SetType(CT_FUNCTION); + } + else + { + // we have TYPE(...) + pc->SetType(CT_CPP_CAST); + set_paren_parent(next, CT_CPP_CAST); + } + } + } + } + } + } + } + + if (language_is_set(LANG_PAWN)) + { + if ( pc->Is(CT_FUNCTION) + && pc->GetBraceLevel() > 0) + { + LOG_FMT(LFCN, "%s(%d): (2) SET TO CT_FUNC_CALL: orig line is %zu, orig col is %zu, Text() '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc->SetType(CT_FUNC_CALL); + } + + if ( pc->Is(CT_STATE) + && next->Is(CT_PAREN_OPEN)) + { + set_paren_parent(next, pc->GetType()); + } + } + else + { + if ( ( pc->Is(CT_FUNCTION) + || pc->Is(CT_FUNC_DEF)) + && ( (pc->GetParentType() == CT_OC_BLOCK_EXPR) + || !is_oc_block(pc))) + { + mark_function(pc); + } + } + + // Detect C99 member stuff + if ( pc->Is(CT_MEMBER) + && ( prev->Is(CT_COMMA) + || prev->Is(CT_BRACE_OPEN))) + { + pc->SetType(CT_C99_MEMBER); + next->SetParentType(CT_C99_MEMBER); + return; + } + + // Mark function parens and braces + if ( pc->Is(CT_FUNC_DEF) + || pc->Is(CT_FUNC_CALL) + || pc->Is(CT_FUNC_CALL_USER) + || pc->Is(CT_FUNC_PROTO)) + { + Chunk *tmp = next; + + if (tmp->Is(CT_SQUARE_OPEN)) + { + tmp = set_paren_parent(tmp, pc->GetType()); + } + else if ( tmp->Is(CT_TSQUARE) + || tmp->GetParentType() == CT_OPERATOR) + { + tmp = tmp->GetNextNcNnl(); + } + + if ( tmp != nullptr + && tmp->IsNotNullChunk()) + { + if (tmp->IsParenOpen()) + { + tmp = flag_parens(tmp, PCF_NONE, CT_FPAREN_OPEN, pc->GetType(), false); + + if ( tmp != nullptr + && tmp->IsNotNullChunk()) + { + if (tmp->Is(CT_BRACE_OPEN)) + { + if ( tmp->GetParentType() != CT_DOUBLE_BRACE + && !pc->TestFlags(PCF_IN_CONST_ARGS)) + { + set_paren_parent(tmp, pc->GetType()); + } + } + else if ( tmp->IsSemicolon() + && pc->Is(CT_FUNC_PROTO)) + { + tmp->SetParentType(pc->GetType()); + } + } + } + } + return; + } + + // Mark the parameters in catch() + if ( pc->Is(CT_CATCH) + && next->Is(CT_SPAREN_OPEN)) + { + fix_fcn_def_params(next); + return; + } + + if ( pc->Is(CT_THROW) + && prev->Is(CT_FPAREN_CLOSE)) + { + pc->SetParentType(prev->GetParentType()); + + if (next->Is(CT_PAREN_OPEN)) + { + set_paren_parent(next, CT_THROW); + } + return; + } + + // Mark the braces in: "for_each_entry(xxx) { }" + if ( pc->Is(CT_BRACE_OPEN) + && pc->GetParentType() != CT_DOUBLE_BRACE + && prev->Is(CT_FPAREN_CLOSE) + && ( prev->GetParentType() == CT_FUNC_CALL + || prev->GetParentType() == CT_FUNC_CALL_USER) + && !pc->TestFlags(PCF_IN_CONST_ARGS)) + { + LOG_FMT(LFCN, "%s(%d): (3) SET TO CT_FUNC_CALL: orig line is %zu, orig col is %zu, Text() '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + set_paren_parent(pc, CT_FUNC_CALL); + return; + } + + /* + * Check for a close parenthesis followed by an open parenthesis, + * which means that we are on a function type declaration (C/C++ only?). + * Note that typedefs are already taken care of. + */ + if ( !pc->TestFlags(PCF_IN_TEMPLATE) // Issue #3252 + && pc->GetParentType() != CT_CPP_CAST + && pc->GetParentType() != CT_C_CAST + && !pc->TestFlags(PCF_IN_PREPROC) + && !is_oc_block(pc) + && pc->GetParentType() != CT_OC_MSG_DECL + && pc->GetParentType() != CT_OC_MSG_SPEC + && pc->IsString(")") + && next->IsString("(")) + { + if (language_is_set(LANG_D)) + { + flag_parens(next, PCF_NONE, CT_FPAREN_OPEN, CT_FUNC_CALL, false); + } + else + { + mark_function_type(pc); + } + return; + } + + if (pc->Is(CT_OC_CLASS)) + { + handle_oc_class(pc); + return; + } + // TODO: Check for stuff that can only occur at the start of an statement + + if (!language_is_set(LANG_D)) + { + /* + * Check a parenthesis pair to see if it is a cast. + * Note that SPAREN and FPAREN have already been marked. + */ + if ( pc->Is(CT_PAREN_OPEN) + && ( pc->GetParentType() == CT_NONE + || pc->GetParentType() == CT_OC_MSG + || pc->GetParentType() == CT_OC_BLOCK_EXPR + || pc->GetParentType() == CT_CS_SQ_STMT) // Issue # 1256 + && ( next->Is(CT_WORD) + || next->Is(CT_TYPE) + || next->Is(CT_STRUCT) + || next->Is(CT_QUALIFIER) + || next->Is(CT_MEMBER) + || next->Is(CT_DC_MEMBER) + || next->Is(CT_ENUM) + || next->Is(CT_UNION)) + && prev->IsNot(CT_DECLTYPE) + && prev->IsNot(CT_SIZEOF) + && prev->GetParentType() != CT_SIZEOF + && prev->GetParentType() != CT_OPERATOR + && !pc->TestFlags(PCF_IN_TYPEDEF)) + { + fix_casts(pc); + return; + } + } + + if (language_is_set(LANG_CPP)) + { + Chunk *nnext = next->GetNextNcNnl(); + + // handle parent_type of assigns in special functions (ro5 + pure virtual) + if ( pc->GetFlags().test_any(PCF_IN_STRUCT | PCF_IN_CLASS) + && pc->Is(CT_ASSIGN) + && nnext->Is(CT_SEMICOLON) + && ( next->Is(CT_DEFAULT) + || next->Is(CT_DELETE) + || ( next->Is(CT_NUMBER) + && next->IsString("0")))) + { + const size_t level = pc->GetLevel(); + bool found_status = false; + Chunk *pprev = pc->GetPrev(); + + for ( ; ( pprev->IsNotNullChunk() + && pprev->GetLevel() >= level + && pprev->IsNot(CT_SEMICOLON) + && pprev->IsNot(CT_ACCESS_COLON)) + ; pprev = pprev->GetPrev()) + { + if (pprev->GetLevel() != level) + { + continue; + } + + if (next->Is(CT_NUMBER)) + { + if ( pprev->Is(CT_QUALIFIER) + && pprev->IsString("virtual")) + { + found_status = true; + break; + } + } + else + { + if ( pprev->Is(CT_FUNC_CLASS_PROTO) // ctor/dtor + || pprev->Is(CT_FUNC_PROTO)) // normal function + { + found_status = true; + break; + } + } + } + + if (found_status) + { + pc->SetParentType(pprev->GetType()); + } + } + + if (detect_cpp_braced_init_list(pc, next)) + { + flag_cpp_braced_init_list(pc, next); + } + } + + // Check for stuff that can only occur at the start of an expression + if ( pc->TestFlags(PCF_EXPR_START) + || ( prev->TestFlags(PCF_EXPR_START) + && pc->GetParentType() == CT_OC_AT)) + { + // Change STAR, MINUS, and PLUS in the easy cases + if (pc->Is(CT_STAR)) + { + // issue #596 + // [0x100062020:IN_SPAREN,IN_FOR,STMT_START,EXPR_START,PUNCTUATOR] + // prev->GetType() is CT_COLON ==> CT_DEREF + if (prev->Is(CT_ANGLE_CLOSE)) + { + pc->SetType(CT_PTR_TYPE); + } + else if (prev->Is(CT_COLON)) + { + pc->SetType(CT_DEREF); + } + else + { + pc->SetType(CT_DEREF); + } + } + + if ( language_is_set(LANG_CPP) + && pc->Is(CT_CARET) + && prev->Is(CT_ANGLE_CLOSE)) + { + pc->SetType(CT_PTR_TYPE); + } + + if ( language_is_set(LANG_CS | LANG_VALA) + && pc->Is(CT_QUESTION) + && prev->Is(CT_ANGLE_CLOSE)) + { + pc->SetType(CT_PTR_TYPE); + } + + else if (pc->Is(CT_MINUS)) + { + pc->SetType(CT_NEG); + } + + else if (pc->Is(CT_PLUS)) + { + pc->SetType(CT_POS); + } + + else if (pc->Is(CT_INCDEC_AFTER)) + { + pc->SetType(CT_INCDEC_BEFORE); + } + + else if (pc->Is(CT_AMP)) + { + if (prev->Is(CT_ANGLE_CLOSE)) // Issue #2324 + { + pc->SetType(CT_BYREF); + } + else + { + pc->SetType(CT_ADDR); + } + } + + else if (pc->Is(CT_CARET)) + { + if (language_is_set(LANG_C | LANG_CPP | LANG_OC)) + { + // This is likely the start of a block literal + handle_oc_block_literal(pc); + } + } + } + + /* + * Change the parenthesis pair after a function/macro-function + * CT_PAREN_OPEN => CT_FPAREN_OPEN + */ + if (pc->Is(CT_MACRO_FUNC)) + { + flag_parens(next, PCF_IN_FCN_CALL, CT_FPAREN_OPEN, CT_MACRO_FUNC, false); + } + + if ( pc->Is(CT_MACRO_OPEN) + || pc->Is(CT_MACRO_ELSE) + || pc->Is(CT_MACRO_CLOSE)) + { + if (next->Is(CT_PAREN_OPEN)) + { + flag_parens(next, PCF_NONE, CT_FPAREN_OPEN, pc->GetType(), false); + } + } + + if ( pc->Is(CT_DELETE) + && next->Is(CT_TSQUARE)) + { + next->SetParentType(CT_DELETE); + } + + // Change CT_STAR to CT_PTR_TYPE or CT_ARITH or CT_DEREF + if ( pc->Is(CT_STAR) + || ( language_is_set(LANG_CPP) + && pc->Is(CT_CARET))) + { + if ( next->IsParenClose() + || next->Is(CT_COMMA)) + { + pc->SetType(CT_PTR_TYPE); + } + else if ( language_is_set(LANG_OC) + && next->Is(CT_STAR)) + { + /* + * Change pointer-to-pointer types in OC_MSG_DECLs + * from ARITH <===> DEREF to PTR_TYPE <===> PTR_TYPE + */ + pc->SetType(CT_PTR_TYPE); + pc->SetParentType(prev->GetParentType()); + + next->SetType(CT_PTR_TYPE); + next->SetParentType(pc->GetParentType()); + } + else if ( pc->Is(CT_STAR) + && ( prev->Is(CT_DECLTYPE) + || prev->Is(CT_SIZEOF) + || prev->Is(CT_DELETE) + || pc->GetParentType() == CT_SIZEOF)) + { + pc->SetType(CT_DEREF); + } + else if ( ( prev->Is(CT_WORD) + && chunk_ends_type(prev) + && !prev->TestFlags(PCF_IN_FCN_CTOR) + && !prev->TestFlags(PCF_IN_ARRAY_ASSIGN)) // Issue #3345 + || prev->Is(CT_DC_MEMBER) + || prev->Is(CT_PTR_TYPE)) + { + LOG_FMT(LFCNR, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n ", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + log_pcf_flags(LFCNR, pc->GetFlags()); + pc->SetType(CT_PTR_TYPE); + } + else if ( next->Is(CT_SQUARE_OPEN) + && !language_is_set(LANG_OC)) // Issue #408 + { + pc->SetType(CT_PTR_TYPE); + } + else if (pc->Is(CT_STAR)) + { + // Add check for CT_DC_MEMBER CT_WORD CT_STAR sequence + // to convert CT_WORD into CT_TYPE + // and CT_STAR into CT_PTR_TYPE + // look for an assign backward, function call, return to distinguish between + // double result = Constants::PI * factor; + // and + // ::some::name * foo; + if ( prev->Is(CT_WORD) + && prev->GetPrev()->Is(CT_DC_MEMBER) + && language_is_set(LANG_CPP)) + { + // Issue 1402 + bool is_multiplication = false; + Chunk *tmp = pc; + + while (tmp->IsNotNullChunk()) + { + if ( tmp->Is(CT_SEMICOLON) + || tmp->GetParentType() == CT_CLASS) + { + break; + } + else if ( tmp->Is(CT_ASSIGN) + || tmp->Is(CT_FUNC_CALL) + || tmp->Is(CT_RETURN)) + { + is_multiplication = true; + break; + } + tmp = tmp->GetPrevNcNnlNi(); // Issue #2279 + } + + if (is_multiplication) + { + // double result = Constants::PI * factor; + pc->SetType(CT_ARITH); + } + else + { + // ::some::name * foo; + prev->SetType(CT_TYPE); + pc->SetType(CT_PTR_TYPE); + } + } + + /* + * A star can have three meanings + * 1. CT_DEREF = pointer dereferencing + * 2. CT_PTR_TYPE = pointer definition + * 3. CT_ARITH = arithmetic multiplication + * + * most PCF_PUNCTUATOR chunks except a paren close would make this + * a deref. A paren close may end a cast or may be part of a macro fcn. + */ + if (prev->Is(CT_TYPE)) + { + pc->SetType(CT_PTR_TYPE); + } + else if ( pc->GetNext()->Is(CT_SEMICOLON) // Issue #2319 + || ( pc->GetNext()->Is(CT_STAR) + && pc->GetNext()->GetNext()->Is(CT_SEMICOLON))) + { + // example: + // using AbstractLinkPtr = AbstractLink*; + // using AbstractLinkPtrPtr = AbstractLink**; + pc->SetType(CT_PTR_TYPE); + } + else if ( ( pc->GetParentType() == CT_FUNC_DEF + && ( next->IsBraceOpen() + || pc->GetNext()->IsStar())) + || next->Is(CT_QUALIFIER)) // Issue #2648 + { + // example: + // auto getComponent(Color *color) -> Component * { + // auto getComponent(Color *color) -> Component ** { + // auto getComponent(Color *color) -> Component * _Nonnull + // only to help the vim command }} + pc->SetType(CT_PTR_TYPE); + } + else if ( pc->GetNext()->Is(CT_SEMICOLON) // Issue #2319 + || ( pc->GetNext()->Is(CT_STAR) + && pc->GetNext()->GetNext()->Is(CT_STAR))) + { + // more pointers are NOT yet possible + fprintf(stderr, "Too many pointers: the maximum level of pointer indirection is 3 (i.e., ***p)\n"); + fprintf(stderr, "at line %zu, column %zu.\n", pc->GetOrigLine(), pc->GetOrigCol()); + fprintf(stderr, "Please make a report.\n"); + log_flush(true); + exit(EX_SOFTWARE); + } + else if ( !prev->TestFlags(PCF_PUNCTUATOR) + || prev->Is(CT_INCDEC_AFTER) + || prev->Is(CT_SQUARE_CLOSE) + || prev->Is(CT_DC_MEMBER)) // Issue 1402 + { + pc->SetType(CT_ARITH); + } + else if ( !prev->IsParenClose() + || prev->Is(CT_SPAREN_CLOSE) + || prev->GetParentType() == CT_MACRO_FUNC) + { + pc->SetType(CT_DEREF); + } + else + { + pc->SetType(CT_ARITH); + } + + if (pc->TestFlags(PCF_IN_TYPEDEF)) // Issue #1255/#633 + { + Chunk *tmp = pc; + + while (tmp->IsNotNullChunk()) + { + if ( tmp->Is(CT_SEMICOLON) + || tmp->Is(CT_BRACE_OPEN) + || tmp->Is(CT_SQUARE_OPEN)) // Issue #3342 + { + break; + } + else if (tmp->Is(CT_TYPEDEF)) + { + pc->SetType(CT_PTR_TYPE); + } + tmp = tmp->GetPrevNcNnlNi(); // Issue #2279 + } + } + } + } + + if (pc->Is(CT_AMP)) + { + if (prev->Is(CT_DELETE)) + { + pc->SetType(CT_ADDR); + } + else if ( prev->Is(CT_TYPE) + || prev->Is(CT_QUALIFIER)) + { + pc->SetType(CT_BYREF); + } + else if ( prev->Is(CT_WORD) // Issue #3204 + && next->Is(CT_OPERATOR)) + { + pc->SetType(CT_BYREF); + } + else if ( next->Is(CT_FPAREN_CLOSE) + || next->Is(CT_COMMA)) + { + // fix the bug #654 + // connect(&mapper, SIGNAL(mapped(QString &)), this, SLOT(onSomeEvent(QString &))); + pc->SetType(CT_BYREF); + } + else if (pc->GetParentType() == CT_USING_ALIAS) + { + // fix the Issue # 1689 + // using reference = value_type &; + pc->GetPrev()->SetType(CT_TYPE); + pc->SetType(CT_BYREF); + } + else + { + // Issue # 1398 + if ( pc->TestFlags(PCF_IN_FCN_DEF) + && prev->Is(CT_WORD) + && pc->Is(CT_AMP) + && next->Is(CT_WORD)) + { + /* + * Change CT_WORD before CT_AMP before CT_WORD to CT_TYPE + */ + prev->SetType(CT_TYPE); + } + else if ( pc->TestFlags(PCF_IN_PREPROC) // Issue #3559 + && pc->Is(CT_AMP) + && next->Is(CT_WORD)) + { + //LOG_FMT(LGUY, " ++++++++++ pc->GetFlags(): "); + //log_pcf_flags(LGUY, pc->GetFlags()); + pc->SetType(CT_ADDR); + } + else + { + pc->SetType(CT_ARITH); + + if ( prev->Is(CT_WORD) + && !next->Is(CT_NUMBER)) // Issue #3407 + { + Chunk *tmp = prev->GetPrevNcNnlNi(); // Issue #2279 + + if (tmp->IsNotNullChunk()) + { + if ( tmp->IsSemicolon() + || tmp->Is(CT_BRACE_OPEN) + || tmp->Is(CT_QUALIFIER)) + { + pc->SetType(CT_BYREF); + prev->SetType(CT_TYPE); + + if (!( next->Is(CT_OPERATOR) + || next->Is(CT_TYPE) + || next->Is(CT_DC_MEMBER))) + { + LOG_FMT(LFCNR, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', set PCF_VAR_1ST\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + next->SetFlagBits(PCF_VAR_1ST); + } + } + else if (tmp->Is(CT_DC_MEMBER)) + { + prev->SetType(CT_TYPE); + } + } + } + } + } + } + + if ( pc->Is(CT_MINUS) + || pc->Is(CT_PLUS)) + { + if ( prev->Is(CT_POS) + || prev->Is(CT_NEG) + || prev->Is(CT_ARITH) + || prev->Is(CT_SHIFT)) + { + pc->SetType(pc->Is(CT_MINUS) ? CT_NEG : CT_POS); + } + else if (prev->Is(CT_OC_CLASS)) + { + pc->SetType((pc->Is(CT_MINUS)) ? CT_NEG : CT_POS); + } + else + { + pc->SetType(CT_ARITH); + } + } + + /* + * Bug # 634 + * Check for extern "C" NSString* i; + * NSString is a type + * change CT_WORD => CT_TYPE for pc + * change CT_STAR => CT_PTR_TYPE for pc-next + */ + if (pc->Is(CT_WORD)) // here NSString + { + Chunk *pcNext = pc->GetNext(); + Chunk *pcPrev = pc->GetPrev(); + + if (pcNext->Is(CT_STAR)) // here * + { + // compare text with "C" to find extern "C" instructions + if (pcPrev->Is(CT_STRING)) + { + if (unc_text::compare(pcPrev->Text(), "\"C\"") == 0) + { + if (pcPrev->GetPrev()->Is(CT_EXTERN)) + { + pc->SetType(CT_TYPE); // change CT_WORD => CT_TYPE + pcNext->SetType(CT_PTR_TYPE); // change CT_STAR => CT_PTR_TYPE + } + } + } + // Issue #322 STDMETHOD(GetValues)(BSTR bsName, REFDATA** pData); + Chunk *nnext = pcNext->GetNext(); + + if ( nnext->Is(CT_STAR) + && pc->TestFlags(PCF_IN_CONST_ARGS)) + { + // change CT_STAR => CT_PTR_TYPE + pcNext->SetType(CT_PTR_TYPE); + nnext->SetType(CT_PTR_TYPE); + } + + // Issue #222 whatever3 *(func_ptr)( whatever4 *foo2, ... + if ( nnext->Is(CT_WORD) + && pc->TestFlags(PCF_IN_FCN_DEF)) + { + // look for the opening parenthesis + // Issue 1403 + Chunk *tmp = pc->GetPrevType(CT_FPAREN_OPEN, pc->GetLevel() - 1); + + if ( tmp->IsNotNullChunk() + && tmp->GetParentType() != CT_FUNC_CTOR_VAR) + { + pcNext->SetType(CT_PTR_TYPE); + } + } + } + } + + /* + * Bug # 634 + * Check for __attribute__((visibility ("default"))) NSString* i; + * NSString is a type + * change CT_WORD => CT_TYPE for pc + * change CT_STAR => CT_PTR_TYPE for pc-next + */ + if (pc->Is(CT_WORD)) // here NSString + { + Chunk *pcNext = pc->GetNext(); + + if (pcNext->Is(CT_STAR)) // here * + { + Chunk *tmp = pc; + + while (tmp->IsNotNullChunk()) + { + if (tmp->Is(CT_ATTRIBUTE)) + { + LOG_FMT(LFCNR, "%s(%d): ATTRIBUTE found, type is %s, Text() '%s'\n", + __func__, __LINE__, get_token_name(tmp->GetType()), tmp->Text()); + LOG_FMT(LFCNR, "for token, type is %s, Text() '%s'\n", get_token_name(pc->GetType()), pc->Text()); + // change CT_WORD => CT_TYPE + pc->SetType(CT_TYPE); + // change CT_STAR => CT_PTR_TYPE + pcNext->SetType(CT_PTR_TYPE); + } + + if (tmp->TestFlags(PCF_STMT_START)) + { + // we are at beginning of the line + break; + } + tmp = tmp->GetPrev(); + } + } + } + + /* + * Issue # 1689 + * Check for using reference = value_type&; + * is it a Type alias, alias template? + */ + if (pc->Is(CT_USING)) + { + // look for CT_ASSIGN before CT_SEMICOLON at the end of the statement + + bool is_preproc = pc->TestFlags(PCF_IN_PREPROC); + auto const search_assign = [&pc, &is_preproc]() + { + for (Chunk *temp = pc; temp->IsNotNullChunk(); temp = temp->GetNextNcNnl()) + { + LOG_FMT(LFCNR, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, temp->GetOrigLine(), temp->GetOrigCol(), + temp->Text(), get_token_name(temp->GetType())); + + if (temp->Is(CT_ASSIGN)) + { + return(true); + } + + if ( temp->Is(CT_SEMICOLON) + || ( is_preproc + && ( !temp->TestFlags(PCF_IN_PREPROC) + || temp->Is(CT_PREPROC)))) + { + return(false); + } + } + + return(false); + }; + + const bool assign_found = language_is_set(LANG_D) || search_assign(); + + if (assign_found) + { + // it is a Type alias, alias template + for (Chunk *temp = pc; temp->IsNotNullChunk(); temp = temp->GetNextNcNnl()) + { + if (temp->GetParentType() == CT_NONE) + { + temp->SetParentType(CT_USING_ALIAS); + } + + if ( temp->Is(CT_SEMICOLON) + || ( is_preproc + && ( !temp->TestFlags(PCF_IN_PREPROC) + || temp->Is(CT_PREPROC)))) + { + break; + } + } + } + } + + // Issue #548: inline T && someFunc(foo * *p, bar && q) { } + if ( pc->Is(CT_BOOL) + && !pc->TestFlags(PCF_IN_PREPROC) + && pc->IsString("&&") + && chunk_ends_type(pc->GetPrev())) + { + Chunk *tmp = pc->GetPrev(); // Issue #2688 + LOG_FMT(LFCNR, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, tmp->GetOrigLine(), tmp->GetOrigCol(), + tmp->Text(), get_token_name(tmp->GetType())); + log_pcf_flags(LFCNR, tmp->GetFlags()); + // look for a type + + if (tmp->Is(CT_TYPE)) + { + LOG_FMT(LFCNR, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), + pc->Text(), get_token_name(pc->GetType())); + log_pcf_flags(LFCNR, pc->GetFlags()); + pc->SetType(CT_BYREF); + } + // look next, is there a "assign" before the ";" + Chunk *semi = pc->GetNextType(CT_SEMICOLON, pc->GetLevel()); // Issue #2688 + + if (semi->IsNotNullChunk()) + { + LOG_FMT(LFCNR, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, semi->GetOrigLine(), semi->GetOrigCol(), + semi->Text(), get_token_name(semi->GetType())); + + for (Chunk *test_it = pc; test_it != semi; test_it = test_it->GetNext()) + { + LOG_FMT(LFCNR, "%s(%d): test_it orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, test_it->GetOrigLine(), test_it->GetOrigCol(), + test_it->Text(), get_token_name(test_it->GetType())); + + if (test_it->Is(CT_ASSIGN)) + { + // the statement is an assignment + // && is before assign + pc->SetType(CT_BYREF); + break; + } + } + } + } + + // Issue #1704 + if ( pc->Is(CT_INCDEC_AFTER) + && pc->TestFlags(PCF_IN_PREPROC)) + { + Chunk *tmp_2 = pc->GetNext(); + LOG_FMT(LFCNR, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), + pc->Text(), get_token_name(pc->GetType())); + log_pcf_flags(LFTYPE, pc->GetFlags()); + + if (tmp_2->Is(CT_WORD)) + { + pc->SetType(CT_INCDEC_BEFORE); + } + } +} // do_symbol_check + + +static void check_double_brace_init(Chunk *bo1) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LJDBI, "%s(%d): orig line is %zu, orig col is %zu", __func__, __LINE__, bo1->GetOrigLine(), bo1->GetOrigCol()); + Chunk *pc = bo1->GetPrevNcNnlNi(); // Issue #2279 + + if (pc->IsNullChunk()) + { + return; + } + + if (pc->IsParenClose()) + { + Chunk *bo2 = bo1->GetNext(); + + if (bo2->IsNullChunk()) + { + return; + } + + if (bo2->Is(CT_BRACE_OPEN)) + { + // found a potential double brace + Chunk *bc2 = bo2->GetClosingParen(); + + if (bc2->IsNullChunk()) + { + return; + } + Chunk *bc1 = bc2->GetNext(); + + if (bc1->IsNullChunk()) + { + return; + } + + if (bc1->Is(CT_BRACE_CLOSE)) + { + LOG_FMT(LJDBI, " - end, orig line is %zu, orig col is %zu\n", bc2->GetOrigLine(), bc2->GetOrigCol()); + // delete bo2 and bc1 + bo1->Str() += bo2->GetStr(); + bo1->SetOrigColEnd(bo2->GetOrigColEnd()); + Chunk::Delete(bo2); + bo1->SetParentType(CT_DOUBLE_BRACE); + + bc2->Str() += bc1->GetStr(); + bc2->SetOrigColEnd(bc1->GetOrigColEnd()); + Chunk::Delete(bc1); + bc2->SetParentType(CT_DOUBLE_BRACE); + return; + } + } + } + LOG_FMT(LJDBI, " - no\n"); +} // check_double_brace_init + + +void fix_symbols() +{ + LOG_FUNC_ENTRY(); + Chunk *pc; + + cpd.unc_stage = unc_stage_e::FIX_SYMBOLS; + + mark_define_expressions(); + + bool is_cpp = language_is_set(LANG_CPP); + bool is_java = language_is_set(LANG_JAVA); + + for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + LOG_FMT(LFCNR, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + + if ( pc->Is(CT_FUNC_WRAP) + || pc->Is(CT_TYPE_WRAP)) + { + handle_wrap(pc); + } + + if (pc->Is(CT_ASSIGN)) + { + mark_lvalue(pc); + } + // a brace immediately preceded by word in C++11 is an initializer list though it may also + // by a type casting initializer list if the word is really a type; sadly uncrustify knows + // only built-in types and knows nothing of user-defined types + Chunk *prev = pc->GetPrevNcNnlNi(); // Issue #2279 + + if ( is_cpp + && pc->Is(CT_BRACE_OPEN) + && ( prev->Is(CT_WORD) + || prev->Is(CT_TYPE))) + { + mark_lvalue(pc); + } + + if ( is_java + && pc->Is(CT_BRACE_OPEN)) + { + check_double_brace_init(pc); + } + + if (pc->Is(CT_ATTRIBUTE)) + { + Chunk *next = pc->GetNextNcNnl(E_Scope::PREPROC); + + if ( next->IsNotNullChunk() + && next->Is(CT_PAREN_OPEN)) + { + flag_parens(next, PCF_NONE, CT_FPAREN_OPEN, CT_ATTRIBUTE, false); + } + } + } + + pc = Chunk::GetHead(); + + if (pc->IsCommentOrNewline()) + { + pc = pc->GetNextNcNnl(); + } + + while (pc->IsNotNullChunk()) + { + if (pc->Is(CT_IGNORED)) + { + pc = pc->GetNextNcNnl(); + continue; + } + LOG_FMT(LFCNR, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + Chunk *prev = pc->GetPrevNcNnlNi(E_Scope::PREPROC); // Issue #2279 + + if (prev->Is(CT_QUALIFIER)) + { + prev = prev->GetPrevNcNnlNi(E_Scope::PREPROC); // Issue #3513 + } + + if (prev->IsNullChunk()) + { + LOG_FMT(LFCNR, "%s(%d): WARNING: prev is NOT defined\n", __func__, __LINE__); + } + else + { + // Issue #2279 + LOG_FMT(LFCNR, "%s(%d): prev(ni) orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, prev->GetOrigLine(), prev->GetOrigCol(), prev->Text(), get_token_name(prev->GetType())); + } + Chunk *next = pc->GetNextNcNnl(E_Scope::PREPROC); + + if (next->IsNullChunk()) + { + LOG_FMT(LFCNR, "%s(%d): WARNING: next is NOT defined\n", __func__, __LINE__); + } + else + { + // Issue #2279 + LOG_FMT(LFCNR, "%s(%d): next orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, next->GetOrigLine(), next->GetOrigCol(), next->Text(), get_token_name(next->GetType())); + } + LOG_FMT(LFCNR, "%s(%d): do_symbol_check(%s, %s, %s)\n", + __func__, __LINE__, prev->Text(), pc->Text(), next->Text()); + do_symbol_check(prev, pc, next); + pc = pc->GetNextNcNnl(); + } + pawn_add_virtual_semicolons(); + process_returns_and_throws(); + + /* + * 2nd pass - handle variable definitions + * REVISIT: We need function params marked to do this (?) + */ + pc = Chunk::GetHead(); + int square_level = -1; + + while ( pc != nullptr + && pc->IsNotNullChunk()) + { + char copy[1000]; + LOG_FMT(LFCNR, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s, parent type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->ElidedText(copy), get_token_name(pc->GetType()), get_token_name(pc->GetParentType())); + + // Can't have a variable definition inside [ ] + if (square_level < 0) + { + if (pc->Is(CT_SQUARE_OPEN)) + { + square_level = pc->GetLevel(); + } + } + else + { + if (pc->GetLevel() <= static_cast<size_t>(square_level)) + { + square_level = -1; + } + } + + if ( pc->Is(CT_EXTERN) + && language_is_set(LANG_ALLC)) + { + Chunk *next = pc->GetNextNcNnl(); + + if (next->Is(CT_STRING)) + { + Chunk *tmp = next->GetNextNcNnl(); + + while (tmp->IsNotNullChunk()) + { + if ( tmp->Is(CT_TYPE) + || tmp->Is(CT_BRACE_OPEN) + || tmp->Is(CT_ATTRIBUTE)) + { + break; + } + + if (tmp->Is(CT_WORD)) + { + tmp->SetFlagBits(PCF_STMT_START | PCF_EXPR_START); + break; + } + tmp = tmp->GetNextNcNnl(); + } + } + } + + if ( pc->Is(CT_ATTRIBUTE) + && language_is_set(LANG_ALLC)) + { + Chunk *tmp = skip_attribute_next(pc); + + if (tmp->Is(CT_WORD)) + { + tmp->SetFlagBits(PCF_STMT_START | PCF_EXPR_START); + } + } + + if ( pc->Is(CT_BRACE_OPEN) // Issue #2332 + && pc->GetParentType() == CT_BRACED_INIT_LIST) + { + LOG_FMT(LFCNR, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', look for CT_BRACE_OPEN\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc = pc->GetNextType(CT_BRACE_CLOSE, pc->GetLevel()); + } + /* + * A variable definition is possible after at the start of a statement + * that starts with: DC_MEMBER, QUALIFIER, TYPE, or WORD + */ + // Issue #2279 + // Issue #2478 + LOG_FMT(LFCNR, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s, parent type is %s\n ", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->ElidedText(copy), get_token_name(pc->GetType()), get_token_name(pc->GetParentType())); + log_pcf_flags(LFCNR, pc->GetFlags()); + + if ( (square_level < 0) + && pc->TestFlags(PCF_STMT_START) + && ( pc->Is(CT_QUALIFIER) + || pc->Is(CT_TYPE) + || pc->Is(CT_TYPENAME) + || pc->Is(CT_DC_MEMBER) // Issue #2478 + || ( pc->Is(CT_WORD) + && !pc->TestFlags(PCF_IN_CONDITIONAL) // Issue #3558 +// && language_is_set(LANG_CPP) + ) + ) + && pc->GetParentType() != CT_BIT_COLON + && pc->GetParentType() != CT_ENUM + && !pc->TestFlags(PCF_IN_CLASS_BASE) + && !pc->TestFlags(PCF_IN_ENUM)) + { + pc = fix_variable_definition(pc); + } + else + { + pc = pc->GetNextNcNnl(); + } + } +} // fix_symbols + + +static void process_returns_and_throws() +{ + LOG_FUNC_ENTRY(); + Chunk *pc; + + pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + if ( pc->Is(CT_RETURN) + || pc->Is(CT_THROW)) + { + pc = process_return_or_throw(pc); + } + else + { + pc = pc->GetNext(); + } + } +} + + +static Chunk *process_return_or_throw(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + const char *nl_expr_name; + iarf_e nl_expr_value; + const char *mod_paren_name; + iarf_e mod_paren_value; + + if (pc->Is(CT_RETURN)) + { + nl_expr_name = "nl_return_expr"; + nl_expr_value = options::nl_return_expr(); + mod_paren_name = "mod_paren_on_return"; + mod_paren_value = options::mod_paren_on_return(); + } + else if (pc->Is(CT_THROW)) + { + nl_expr_name = "nl_throw_expr"; + nl_expr_value = options::nl_throw_expr(); + mod_paren_name = "mod_paren_on_throw"; + mod_paren_value = options::mod_paren_on_throw(); + } + else // should never happen + { + return(pc->GetNext()); + } + Chunk *next; + Chunk *temp; + Chunk *semi; + Chunk *cpar; + Chunk chunk; + + // grab next and bail if it is a semicolon + next = pc->PpaGetNextNcNnl(); + + if ( next->IsNullChunk() + || next->IsSemicolon() + || next->Is(CT_NEWLINE)) + { + return(next); + } + log_rule_B(nl_expr_name); + + if ( nl_expr_value != IARF_IGNORE + && !pc->TestFlags(PCF_IN_PREPROC)) + { + newline_iarf(pc, nl_expr_value); + } + + if (next->Is(CT_PAREN_OPEN)) + { + // See if the return/throw is fully paren'd + cpar = next->GetNextType(CT_PAREN_CLOSE, next->GetLevel()); + + if (cpar->IsNullChunk()) + { + return(Chunk::NullChunkPtr); + } + semi = cpar->PpaGetNextNcNnl(); + + if (semi->IsNullChunk()) + { + return(Chunk::NullChunkPtr); + } + + if ( semi->Is(CT_NEWLINE) + || semi->IsSemicolon()) + { + log_rule_B(mod_paren_name); + + if (mod_paren_value == IARF_REMOVE) + { + LOG_FMT(LRETURN, "%s(%d): removing parens on orig line %zu\n", + __func__, __LINE__, pc->GetOrigLine()); + + // lower the level of everything + for (temp = next; temp != cpar; temp = temp->GetNext()) + { + if (temp->GetLevel() == 0) + { + fprintf(stderr, "%s(%d): temp->GetLevel() is ZERO, cannot be decremented, at line %zu, column %zu\n", + __func__, __LINE__, temp->GetOrigLine(), temp->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + temp->SetLevel(temp->GetLevel() - 1); + } + + // delete the parenthesis + Chunk::Delete(next); + Chunk::Delete(cpar); + + // back up following chunks + temp = semi; + + while ( temp->IsNotNullChunk() + && temp->IsNot(CT_NEWLINE)) + { + temp->SetColumn(temp->GetColumn() - 2); + temp->SetOrigCol(temp->GetOrigCol() - 2); + temp->SetOrigColEnd(temp->GetOrigColEnd() - 2); + temp = temp->GetNext(); + } + } + else + { + LOG_FMT(LRETURN, "%s(%d): keeping parens on orig line %zu\n", + __func__, __LINE__, pc->GetOrigLine()); + + // mark & keep them + next->SetParentType(pc->GetType()); + cpar->SetParentType(pc->GetType()); + } + return(semi); + } + } + // We don't have a fully paren'd return/throw. Should we add some? + log_rule_B(mod_paren_name); + + if (!(mod_paren_value & IARF_ADD)) + { + return(next); + } + + // Issue #1917 + // Never add parens to a braced init list; that breaks the code + // return {args...}; // C++11 type elision; okay + // return ({args...}); // ill-formed + if ( language_is_set(LANG_CPP) + && next->Is(CT_BRACE_OPEN) + && next->GetParentType() == CT_BRACED_INIT_LIST) + { + LOG_FMT(LRETURN, "%s(%d): not adding parens around braced initializer" + " on orig line %zd\n", + __func__, __LINE__, pc->GetOrigLine()); + return(next); + } + // find the next semicolon on the same level + semi = next; + + if (pc->TestFlags(PCF_IN_PREPROC)) + { + while ((semi = semi->GetNext())->IsNotNullChunk()) + { + if (!semi->TestFlags(PCF_IN_PREPROC)) + { + break; + } + + if (semi->GetLevel() < pc->GetLevel()) + { + return(semi); + } + + if ( semi->IsSemicolon() + && pc->GetLevel() == semi->GetLevel()) + { + break; + } + } + } + else + { + while ((semi = semi->GetNext())->IsNotNullChunk()) + { + if (semi->GetLevel() < pc->GetLevel()) + { + return(semi); + } + + if ( semi->IsSemicolon() + && pc->GetLevel() == semi->GetLevel()) + { + break; + } + } + } + + if (semi) + { + // add the parenthesis + chunk.SetType(CT_PAREN_OPEN); + chunk.SetParentType(pc->GetType()); + chunk.Str() = "("; + chunk.SetLevel(pc->GetLevel()); + chunk.SetPpLevel(pc->GetPpLevel()); + chunk.SetBraceLevel(pc->GetBraceLevel()); + chunk.SetOrigLine(pc->GetOrigLine()); + chunk.SetOrigCol(next->GetOrigCol() - 1); + chunk.SetFlags(pc->GetFlags() & PCF_COPY_FLAGS); + chunk.CopyAndAddBefore(next); + + chunk.SetType(CT_PAREN_CLOSE); + chunk.Str() = ")"; + chunk.SetOrigLine(semi->GetOrigLine()); + chunk.SetOrigCol(semi->GetOrigCol() - 1); + cpar = chunk.CopyAndAddBefore(semi); + + LOG_FMT(LRETURN, "%s(%d): added parens on orig line %zu\n", + __func__, __LINE__, pc->GetOrigLine()); + + for (temp = next; temp != cpar; temp = temp->GetNext()) + { + temp->SetLevel(temp->GetLevel() + 1); + } + } + return(semi); +} // process_return_or_throw + + +static bool is_oc_block(Chunk *pc) +{ + return( pc != nullptr + && ( pc->GetParentType() == CT_OC_BLOCK_TYPE + || pc->GetParentType() == CT_OC_BLOCK_EXPR + || pc->GetParentType() == CT_OC_BLOCK_ARG + || pc->GetParentType() == CT_OC_BLOCK + || pc->Is(CT_OC_BLOCK_CARET) + || pc->GetNext()->Is(CT_OC_BLOCK_CARET) + || pc->GetPrev()->Is(CT_OC_BLOCK_CARET))); +} + + +void mark_comments() +{ + LOG_FUNC_ENTRY(); + + cpd.unc_stage = unc_stage_e::MARK_COMMENTS; + + bool prev_nl = true; + Chunk *cur = Chunk::GetHead(); + + while (cur->IsNotNullChunk()) + { + Chunk *next = cur->GetNextNvb(); + bool next_nl = next->IsNullChunk() || next->IsNewline(); + + if (cur->IsComment()) + { + if ( next_nl + && prev_nl) + { + cur->SetParentType(CT_COMMENT_WHOLE); + } + else if (next_nl) + { + cur->SetParentType(CT_COMMENT_END); + } + else if (prev_nl) + { + cur->SetParentType(CT_COMMENT_START); + } + else + { + cur->SetParentType(CT_COMMENT_EMBED); + } + } + prev_nl = cur->IsNewline(); + cur = next; + } +} + + +static void handle_cpp_template(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + Chunk *tmp = pc->GetNextNcNnl(); + + if (tmp->IsNot(CT_ANGLE_OPEN)) + { + return; + } + tmp->SetParentType(CT_TEMPLATE); + + size_t level = tmp->GetLevel(); + + tmp = tmp->GetNext(); + + while (tmp->IsNotNullChunk()) + { + if ( tmp->Is(CT_CLASS) + || tmp->Is(CT_STRUCT)) + { + tmp->SetType(CT_TYPE); + } + else if ( tmp->Is(CT_ANGLE_CLOSE) + && tmp->GetLevel() == level) + { + tmp->SetParentType(CT_TEMPLATE); + break; + } + tmp = tmp->GetNext(); + } + + if (tmp->IsNotNullChunk()) + { + tmp = tmp->GetNextNcNnl(); + + if (tmp->Is(CT_FRIEND)) + { + // Account for a template friend declaration + tmp->SetParentType(CT_TEMPLATE); + + tmp = tmp->GetNextNcNnl(); + } + + if (tmp->IsClassOrStruct()) + { + tmp->SetParentType(CT_TEMPLATE); + + // REVISIT: This may be a bit risky - might need to track the { }; + tmp = tmp->GetNextType(CT_SEMICOLON, tmp->GetLevel()); + + if (tmp->IsNotNullChunk()) + { + tmp->SetParentType(CT_TEMPLATE); + } + } + } +} // handle_cpp_template + + +static void handle_cpp_lambda(Chunk *sq_o) +{ + LOG_FUNC_ENTRY(); + + Chunk *ret = Chunk::NullChunkPtr; + + // abort if type of the previous token is not contained in this whitelist + Chunk *prev = sq_o->GetPrevNcNnlNi(); // Issue #2279 + + if (prev->IsNullChunk()) + { + LOG_FMT(LFCNR, "%s(%d): prev is nullptr\n", __func__, __LINE__); + } + + if ( prev->IsNullChunk() + || ( prev->IsNot(CT_ASSIGN) + && prev->IsNot(CT_COMMA) + && prev->IsNot(CT_PAREN_OPEN) // allow Js like self invoking lambda syntax: ([](){})(); + && prev->IsNot(CT_FPAREN_OPEN) + && prev->IsNot(CT_SQUARE_OPEN) + && prev->IsNot(CT_BRACE_OPEN) + && prev->IsNot(CT_SEMICOLON) + && prev->IsNot(CT_RETURN))) + { + LOG_FMT(LFCNR, "%s(%d): return\n", __func__, __LINE__); + return; + } + Chunk *sq_c = sq_o; // assuming '[]' + + if (sq_o->Is(CT_SQUARE_OPEN)) + { + // make sure there is a ']' + sq_c = sq_o->GetClosingParen(); + + if (sq_c->IsNullChunk()) + { + LOG_FMT(LFCNR, "%s(%d): return\n", __func__, __LINE__); + return; + } + } + Chunk *pa_o = sq_c->GetNextNcNnl(); + + // check to see if there is a lambda-specifier in the pa_o chunk; + // assuming chunk is CT_EXECUTION_CONTEXT, ignore lambda-specifier + while (pa_o->Is(CT_EXECUTION_CONTEXT)) + { + // set pa_o to next chunk after this specifier + pa_o = pa_o->GetNextNcNnl(); + } + + if (pa_o->IsNullChunk()) + { + LOG_FMT(LFCNR, "%s(%d): return\n", __func__, __LINE__); + return; + } + Chunk *pa_c = Chunk::NullChunkPtr; + + // lambda-declarator '( params )' is optional + if (pa_o->Is(CT_PAREN_OPEN)) + { + // and now find the ')' + pa_c = pa_o->GetClosingParen(); + + if (pa_c->IsNullChunk()) + { + LOG_FMT(LFCNR, "%s(%d): return\n", __func__, __LINE__); + return; + } + } + // Check for 'mutable' keyword: '[]() mutable {}' or []() mutable -> ret {} + Chunk *br_o = pa_c->IsNotNullChunk() ? pa_c->GetNextNcNnl() : pa_o; + + if (br_o->IsString("mutable")) + { + br_o = br_o->GetNextNcNnl(); + } + //TODO: also check for exception and attribute between [] ... {} + + // skip possible arrow syntax: '-> ret' + if (br_o->IsString("->")) + { + ret = br_o; + // REVISIT: really should check the stuff we are skipping + br_o = br_o->GetNextType(CT_BRACE_OPEN, br_o->GetLevel()); + } + + // skip possible CT_NOEXCEPT + if (br_o->Is(CT_NOEXCEPT)) // Issue #3321 + { + ret = br_o; + // REVISIT: really should check the stuff we are skipping + br_o = br_o->GetNextType(CT_BRACE_OPEN, br_o->GetLevel()); + } + + if (br_o->IsNullChunk()) + { + LOG_FMT(LFCNR, "%s(%d): br_o is null. Return\n", __func__, __LINE__); + return; + } + + if (br_o->IsNot(CT_BRACE_OPEN)) + { + LOG_FMT(LFCNR, "%s(%d): br_o is '%s'/%s\n", + __func__, __LINE__, + br_o->Text(), get_token_name(br_o->GetType())); + LOG_FMT(LFCNR, "%s(%d): return\n", __func__, __LINE__); + return; + } + // and now find the '}' + Chunk *br_c = br_o->GetClosingParen(); + + if (br_c->IsNullChunk()) + { + LOG_FMT(LFCNR, "%s(%d): return\n", __func__, __LINE__); + return; + } + + // This looks like a lambda expression + if (sq_o->Is(CT_TSQUARE)) + { + // split into two chunks + Chunk nc; + + nc = *sq_o; + sq_o->SetType(CT_SQUARE_OPEN); + sq_o->Str().resize(1); + /* + * bug # 664 + * + * The original m_origCol of CT_SQUARE_CLOSE is stored at m_origColEnd + * of CT_TSQUARE. CT_SQUARE_CLOSE m_origCol and m_origColEnd values + * are calculate from m_origColEnd of CT_TSQUARE. + */ + nc.SetOrigCol(sq_o->GetOrigColEnd() - 1); + nc.SetColumn(nc.GetOrigCol()); + nc.SetOrigColEnd(sq_o->GetOrigColEnd()); + sq_o->SetOrigColEnd(sq_o->GetOrigCol() + 1); + + nc.SetType(CT_SQUARE_CLOSE); + nc.Str().pop_front(); + sq_c = nc.CopyAndAddAfter(sq_o); + } + sq_o->SetParentType(CT_CPP_LAMBDA); + sq_c->SetParentType(CT_CPP_LAMBDA); + + if (pa_c->IsNotNullChunk()) + { + pa_o->SetType(CT_LPAREN_OPEN); // Issue #3054 + pa_o->SetParentType(CT_CPP_LAMBDA); + pa_o->SetParent(sq_o); + br_o->SetParent(sq_o); + pa_c->SetType(CT_LPAREN_CLOSE); + pa_c->SetParentType(CT_CPP_LAMBDA); + pa_c->SetParent(sq_o); + br_c->SetParent(sq_o); + } + br_o->SetParentType(CT_CPP_LAMBDA); + br_c->SetParentType(CT_CPP_LAMBDA); + + if (ret->IsNotNullChunk()) + { + ret->SetType(CT_CPP_LAMBDA_RET); + ret = ret->GetNextNcNnl(); + + while (ret != br_o) + { + make_type(ret); + ret = ret->GetNextNcNnl(); + } + } + + if (pa_c->IsNotNullChunk()) + { + fix_fcn_def_params(pa_o); + } + //handle self calling lambda paren + Chunk *call_pa_o = br_c->GetNextNcNnl(); + + if (call_pa_o->Is(CT_PAREN_OPEN)) + { + Chunk *call_pa_c = call_pa_o->GetClosingParen(); + + if (call_pa_c->IsNotNullChunk()) + { + call_pa_o->SetType(CT_FPAREN_OPEN); + call_pa_o->SetParentType(CT_FUNC_CALL); + call_pa_c->SetType(CT_FPAREN_CLOSE); + call_pa_c->SetParentType(CT_FUNC_CALL); + } + } + mark_cpp_lambda(sq_o); +} // handle_cpp_lambda + + +static void handle_d_template(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + Chunk *name = pc->GetNextNcNnl(); + Chunk *po = name->GetNextNcNnl(); + + if ( name->IsNullChunk() + || name->IsNot(CT_WORD)) + { + // TODO: log an error, expected NAME + return; + } + + if ( po->IsNullChunk() + || po->IsNot(CT_PAREN_OPEN)) + { + // TODO: log an error, expected '(' + return; + } + name->SetType(CT_TYPE); + name->SetParentType(CT_TEMPLATE); + po->SetParentType(CT_TEMPLATE); + + ChunkStack cs; + Chunk *tmp = get_d_template_types(cs, po); + + if ( tmp == nullptr + || tmp->IsNot(CT_PAREN_CLOSE)) + { + // TODO: log an error, expected ')' + return; + } + tmp->SetParentType(CT_TEMPLATE); + + tmp = tmp->GetNextNcNnl(); + + if (tmp->IsNot(CT_BRACE_OPEN)) + { + // TODO: log an error, expected '{' + return; + } + tmp->SetParentType(CT_TEMPLATE); + po = tmp; + tmp = tmp->GetNextNcNnl(); + + while ( tmp->IsNotNullChunk() + && tmp->GetLevel() > po->GetLevel()) + { + if ( tmp->Is(CT_WORD) + && chunkstack_match(cs, tmp)) + { + tmp->SetType(CT_TYPE); + } + tmp = tmp->GetNextNcNnl(); + } +// if (!tmp->Is(CT_BRACE_CLOSE)) +// { +// // TODO: log an error, expected '}' +// } + tmp->SetParentType(CT_TEMPLATE); +} // handle_d_template + + +Chunk *skip_template_next(Chunk *ang_open) +{ + if (ang_open == nullptr) + { + return(Chunk::NullChunkPtr); + } + + if (ang_open->Is(CT_ANGLE_OPEN)) + { + Chunk *pc = ang_open->GetNextType(CT_ANGLE_CLOSE, ang_open->GetLevel()); + + if (pc->IsNullChunk()) + { + return(Chunk::NullChunkPtr); + } + return(pc->GetNextNcNnl()); + } + return(ang_open); +} + + +static void handle_oc_class(Chunk *pc) +{ + enum class angle_state_e : unsigned int + { + NONE = 0, + OPEN = 1, // '<' found + CLOSE = 2, // '>' found + }; + + LOG_FUNC_ENTRY(); + Chunk *tmp; + bool hit_scope = false; + bool passed_name = false; // Did we pass the name of the class and now there can be only protocols, not generics + int generic_level = 0; // level of depth of generic + angle_state_e as = angle_state_e::NONE; + + LOG_FMT(LOCCLASS, "%s(%d): start [%s] [%s] line %zu\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetParentType()), pc->GetOrigLine()); + + if (pc->GetParentType() == CT_OC_PROTOCOL) + { + tmp = pc->GetNextNcNnl(); + + if (tmp->IsSemicolon()) + { + tmp->SetParentType(pc->GetParentType()); + LOG_FMT(LOCCLASS, "%s(%d): bail on semicolon\n", __func__, __LINE__); + return; + } + } + tmp = pc; + + while ( (tmp = tmp->GetNextNnl()) != nullptr + && tmp->IsNotNullChunk()) + { + LOG_FMT(LOCCLASS, "%s(%d): orig line is %zu, [%s]\n", + __func__, __LINE__, tmp->GetOrigLine(), tmp->Text()); + + if (tmp->Is(CT_OC_END)) + { + break; + } + + if (tmp->Is(CT_PAREN_OPEN)) + { + passed_name = true; + } + + if (tmp->IsString("<")) + { + tmp->SetType(CT_ANGLE_OPEN); + + if (passed_name) + { + tmp->SetParentType(CT_OC_PROTO_LIST); + } + else + { + tmp->SetParentType(CT_OC_GENERIC_SPEC); + generic_level++; + } + as = angle_state_e::OPEN; + } + + if (tmp->IsString(">")) + { + tmp->SetType(CT_ANGLE_CLOSE); + + if (passed_name) + { + tmp->SetParentType(CT_OC_PROTO_LIST); + as = angle_state_e::CLOSE; + } + else + { + tmp->SetParentType(CT_OC_GENERIC_SPEC); + + if (generic_level == 0) + { + fprintf(stderr, "%s(%d): generic_level is ZERO, cannot be decremented, at line %zu, column %zu\n", + __func__, __LINE__, tmp->GetOrigLine(), tmp->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + generic_level--; + + if (generic_level == 0) + { + as = angle_state_e::CLOSE; + } + } + } + + if (tmp->IsString(">>")) + { + tmp->SetType(CT_ANGLE_CLOSE); + tmp->SetParentType(CT_OC_GENERIC_SPEC); + split_off_angle_close(tmp); + generic_level -= 1; + + if (generic_level == 0) + { + as = angle_state_e::CLOSE; + } + } + + if ( tmp->Is(CT_BRACE_OPEN) + && tmp->GetParentType() != CT_ASSIGN) + { + as = angle_state_e::CLOSE; + tmp->SetParentType(CT_OC_CLASS); + tmp = tmp->GetNextType(CT_BRACE_CLOSE, tmp->GetLevel()); + + if ( tmp->IsNotNullChunk() + && tmp->GetParentType() != CT_ASSIGN) + { + tmp->SetParentType(CT_OC_CLASS); + } + } + else if (tmp->Is(CT_COLON)) + { + if (as != angle_state_e::OPEN) + { + passed_name = true; + } + tmp->SetType(hit_scope ? CT_OC_COLON : CT_CLASS_COLON); + + if (tmp->Is(CT_CLASS_COLON)) + { + tmp->SetParentType(CT_OC_CLASS); + } + } + else if ( tmp->IsString("-") + || tmp->IsString("+")) + { + as = angle_state_e::CLOSE; + + if (tmp->GetPrev()->IsNewline()) + { + tmp->SetType(CT_OC_SCOPE); + tmp->SetFlagBits(PCF_STMT_START); + hit_scope = true; + } + } + + if (as == angle_state_e::OPEN) + { + if (passed_name) + { + tmp->SetParentType(CT_OC_PROTO_LIST); + } + else + { + tmp->SetParentType(CT_OC_GENERIC_SPEC); + } + } + } + + if (tmp->Is(CT_BRACE_OPEN)) + { + tmp = tmp->GetNextType(CT_BRACE_CLOSE, tmp->GetLevel()); + + if (tmp->IsNotNullChunk()) + { + tmp->SetParentType(CT_OC_CLASS); + } + } +} // handle_oc_class + + +static void handle_oc_block_literal(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + if (pc == nullptr) + { + return; // let's be paranoid + } + Chunk *prev = pc->GetPrevNcNnlNi(); // Issue #2279 + Chunk *next = pc->GetNextNcNnl(); + + if ( prev->IsNullChunk() + || next->IsNullChunk()) + { + return; // let's be paranoid + } + /* + * block literal: '^ RTYPE ( ARGS ) { }' + * RTYPE and ARGS are optional + */ + LOG_FMT(LOCBLK, "%s(%d): block literal @ orig line is %zu, orig col is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + + Chunk *apo = Chunk::NullChunkPtr; // arg paren open + Chunk *bbo = Chunk::NullChunkPtr; // block brace open + Chunk *bbc; // block brace close + + LOG_FMT(LOCBLK, "%s(%d): + scan", __func__, __LINE__); + Chunk *tmp; + + for (tmp = next; tmp->IsNotNullChunk(); tmp = tmp->GetNextNcNnl()) + { + /* handle '< protocol >' */ + if (tmp->IsString("<")) + { + Chunk *ao = tmp; + Chunk *ac = ao->GetNextString(">", 1, ao->GetLevel()); + + if (ac->IsNotNullChunk()) + { + ao->SetType(CT_ANGLE_OPEN); + ao->SetParentType(CT_OC_PROTO_LIST); + ac->SetType(CT_ANGLE_CLOSE); + ac->SetParentType(CT_OC_PROTO_LIST); + + for (tmp = ao->GetNext(); tmp != ac; tmp = tmp->GetNext()) + { + tmp->SetLevel(tmp->GetLevel() + 1); + tmp->SetParentType(CT_OC_PROTO_LIST); + } + + tmp = ac->GetNextNcNnl(); + } + else + { + tmp = Chunk::NullChunkPtr; + } + } + LOG_FMT(LOCBLK, " '%s'", tmp->Text()); + + if ( tmp->GetLevel() < pc->GetLevel() + || tmp->Is(CT_SEMICOLON)) + { + LOG_FMT(LOCBLK, "[DONE]"); + break; + } + + if (tmp->GetLevel() == pc->GetLevel()) + { + if (tmp->IsParenOpen()) + { + apo = tmp; + LOG_FMT(LOCBLK, "[PAREN]"); + } + + if (tmp->Is(CT_BRACE_OPEN)) + { + LOG_FMT(LOCBLK, "[BRACE]"); + bbo = tmp; + break; + } + } + } + + // make sure we have braces + bbc = bbo->GetClosingParen(); + + if ( bbo->IsNullChunk() + || bbc->IsNullChunk()) + { + LOG_FMT(LOCBLK, " -- no braces found\n"); + return; + } + LOG_FMT(LOCBLK, "\n"); + + // we are on a block literal for sure + pc->SetType(CT_OC_BLOCK_CARET); + pc->SetParentType(CT_OC_BLOCK_EXPR); + + // handle the optional args + Chunk *lbp; // last before paren - end of return type, if any + + if (apo->IsNotNullChunk()) + { + Chunk *apc = apo->GetClosingParen(); // arg parenthesis close + + if (apc->IsParenClose()) + { + LOG_FMT(LOCBLK, " -- marking parens @ apo orig line is %zu, orig col is %zu and apc orig line is %zu, orig col is %zu\n", + apo->GetOrigLine(), apo->GetOrigCol(), apc->GetOrigLine(), apc->GetOrigCol()); + flag_parens(apo, PCF_OC_ATYPE, CT_FPAREN_OPEN, CT_OC_BLOCK_EXPR, true); + fix_fcn_def_params(apo); + } + lbp = apo->GetPrevNcNnlNi(); // Issue #2279 + } + else + { + lbp = bbo->GetPrevNcNnlNi(); // Issue #2279 + } + + // mark the return type, if any + while (lbp != pc) + { + LOG_FMT(LOCBLK, " -- lbp %s[%s]\n", lbp->Text(), get_token_name(lbp->GetType())); + make_type(lbp); + lbp->SetFlagBits(PCF_OC_RTYPE); + lbp->SetParentType(CT_OC_BLOCK_EXPR); + lbp = lbp->GetPrevNcNnlNi(); // Issue #2279 + } + // mark the braces + bbo->SetParentType(CT_OC_BLOCK_EXPR); + bbc->SetParentType(CT_OC_BLOCK_EXPR); + + // mark the OC_BLOCK + for (Chunk *tmp1 = bbo; tmp1 != bbc; tmp1 = tmp1->GetNextNcNnl()) + { + tmp1->SetFlagBits(PCF_OC_IN_BLOCK); + } +} // handle_oc_block_literal + + +static void handle_oc_block_type(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + if (pc == nullptr) + { + return; + } + + if (pc->TestFlags(PCF_IN_TYPEDEF)) + { + LOG_FMT(LOCBLK, "%s(%d): skip block type @ orig line is %zu, orig col is %zu, -- in typedef\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + return; + } + // make sure we have '( ^' + Chunk *tpo = pc->GetPrevNcNnlNi(); // type paren open Issue #2279 + + if (tpo->IsParenOpen()) + { + /* + * block type: 'RTYPE (^LABEL)(ARGS)' + * LABEL is optional. + */ + Chunk *tpc = tpo->GetClosingParen(); // type close paren (after '^') + Chunk *nam = tpc->GetPrevNcNnlNi(); // name (if any) or '^' Issue #2279 + Chunk *apo = tpc->GetNextNcNnl(); // arg open paren + Chunk *apc = apo->GetClosingParen(); // arg close paren + + /* + * If this is a block literal instead of a block type, 'nam' + * will actually be the closing bracket of the block. We run into + * this situation if a block literal is enclosed in parentheses. + */ + if (nam->IsBraceClose()) + { + return(handle_oc_block_literal(pc)); + } + + // Check apo is '(' or else this might be a block literal. Issue 2643. + if (!apo->IsParenOpen()) + { + return(handle_oc_block_literal(pc)); + } + + if (apc->IsParenClose()) + { + Chunk *aft = apc->GetNextNcNnl(); + E_Token pt; + + if (nam->IsString("^")) + { + nam->SetType(CT_PTR_TYPE); + pt = CT_FUNC_TYPE; + } + else if ( aft->Is(CT_ASSIGN) + || aft->Is(CT_SEMICOLON)) + { + nam->SetType(CT_FUNC_VAR); + pt = CT_FUNC_VAR; + } + else + { + nam->SetType(CT_FUNC_TYPE); + pt = CT_FUNC_TYPE; + } + LOG_FMT(LOCBLK, "%s(%d): block type @ orig line is %zu, orig col is %zu, Text() '%s'[%s]\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), nam->Text(), get_token_name(nam->GetType())); + pc->SetType(CT_PTR_TYPE); + pc->SetParentType(pt); //CT_OC_BLOCK_TYPE; + tpo->SetType(CT_TPAREN_OPEN); + tpo->SetParentType(pt); //CT_OC_BLOCK_TYPE; + tpc->SetType(CT_TPAREN_CLOSE); + tpc->SetParentType(pt); //CT_OC_BLOCK_TYPE; + apo->SetType(CT_FPAREN_OPEN); + apo->SetParentType(CT_FUNC_PROTO); + apc->SetType(CT_FPAREN_CLOSE); + apc->SetParentType(CT_FUNC_PROTO); + fix_fcn_def_params(apo); + mark_function_return_type(nam, tpo->GetPrevNcNnlNi(), pt); // Issue #2279 + } + } +} // handle_oc_block_type + + +static Chunk *handle_oc_md_type(Chunk *paren_open, E_Token ptype, T_PcfFlags flags, bool &did_it) +{ + Chunk *paren_close; + + if ( !paren_open->IsParenOpen() + || ((paren_close = paren_open->GetClosingParen())->IsNullChunk())) + { + did_it = false; + return(paren_open); + } + did_it = true; + + paren_open->SetParentType(ptype); + paren_open->SetFlagBits(flags); + paren_close->SetParentType(ptype); + paren_close->SetFlagBits(flags); + + for (Chunk *cur = paren_open->GetNextNcNnl(); + cur != paren_close; + cur = cur->GetNextNcNnl()) + { + LOG_FMT(LOCMSGD, " <%s|%s>", cur->Text(), get_token_name(cur->GetType())); + cur->SetFlagBits(flags); + make_type(cur); + } + + // returning the chunk after the paren close + return(paren_close->GetNextNcNnl()); +} + + +static void handle_oc_message_decl(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + bool did_it; + //bool in_paren = false; + //int paren_cnt = 0; + //int arg_cnt = 0; + + // Figure out if this is a spec or decl + Chunk *tmp = pc; + + if (tmp == nullptr) + { + tmp = Chunk::NullChunkPtr; + } + + while ((tmp = tmp->GetNext())->IsNotNullChunk()) + { + if (tmp->GetLevel() < pc->GetLevel()) + { + // should not happen + return; + } + + if ( tmp->Is(CT_SEMICOLON) + || tmp->Is(CT_BRACE_OPEN)) + { + break; + } + } + + if (tmp == nullptr) + { + return; + } + E_Token pt = tmp->Is(CT_SEMICOLON) ? CT_OC_MSG_SPEC : CT_OC_MSG_DECL; + + pc->SetType(CT_OC_SCOPE); + pc->SetParentType(pt); + + LOG_FMT(LOCMSGD, "%s(%d): %s @ orig line is %zu, orig col is %zu -", + __func__, __LINE__, get_token_name(pt), pc->GetOrigLine(), pc->GetOrigCol()); + + // format: -(TYPE) NAME [: (TYPE)NAME + + // handle the return type + tmp = handle_oc_md_type(pc->GetNextNcNnl(), pt, PCF_OC_RTYPE, did_it); + + if (!did_it) + { + LOG_FMT(LOCMSGD, " -- missing type parens\n"); + return; + } + + // expect the method name/label + if (tmp->IsNot(CT_WORD)) + { + LOG_FMT(LOCMSGD, " -- missing method name\n"); + return; + } // expect the method name/label + + Chunk *label = tmp; + + tmp->SetType(pt); + tmp->SetParentType(pt); + pc = tmp->GetNextNcNnl(); + + LOG_FMT(LOCMSGD, " [%s]%s", pc->Text(), get_token_name(pc->GetType())); + + // if we have a colon next, we have args + if ( pc->Is(CT_COLON) + || pc->Is(CT_OC_COLON)) + { + pc = label; + + while (true) + { + // skip optional label + if ( pc->Is(CT_WORD) + || pc->Is(pt)) + { + pc->SetParentType(pt); + pc = pc->GetNextNcNnl(); + } + + // a colon must be next + if (!pc->IsString(":")) + { + break; + } + pc->SetType(CT_OC_COLON); + pc->SetParentType(pt); + pc = pc->GetNextNcNnl(); + + // next is the type in parens + LOG_FMT(LOCMSGD, " (%s)", pc->Text()); + tmp = handle_oc_md_type(pc, pt, PCF_OC_ATYPE, did_it); + + if (!did_it) + { + LOG_FMT(LWARN, "%s(%d): orig line is %zu, orig col is %zu expected type\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + break; + } + // attributes for a method parameter sit between the parameter type and the parameter name + pc = skip_attribute_next(tmp); + // we should now be on the arg name + pc->SetFlagBits(PCF_VAR_DEF); + LOG_FMT(LOCMSGD, " arg[%s]", pc->Text()); + pc = pc->GetNextNcNnl(); + } + } + LOG_FMT(LOCMSGD, " end[%s]", pc->Text()); + + if (pc->Is(CT_BRACE_OPEN)) + { + pc->SetParentType(pt); + pc = pc->GetClosingParen(); + + if (pc->IsNotNullChunk()) + { + pc->SetParentType(pt); + } + } + else if (pc->Is(CT_SEMICOLON)) + { + pc->SetParentType(pt); + } + LOG_FMT(LOCMSGD, "\n"); +} // handle_oc_message_decl + + +static void handle_oc_message_send(Chunk *os) +{ + LOG_FUNC_ENTRY(); + + Chunk *cs = Chunk::NullChunkPtr; + + if (os != nullptr) + { + cs = os->GetNext(); + } + + while ( cs->IsNotNullChunk() + && cs->GetLevel() > os->GetLevel()) + { + cs = cs->GetNext(); + } + + if ( cs->IsNullChunk() + || cs->IsNot(CT_SQUARE_CLOSE)) + { + return; + } + LOG_FMT(LOCMSG, "%s(%d): orig line is %zu, orig col is %zu\n", + __func__, __LINE__, os->GetOrigLine(), os->GetOrigCol()); + + Chunk *tmp = cs->GetNextNcNnl(); + + if (tmp->IsSemicolon()) + { + tmp->SetParentType(CT_OC_MSG); + } + // expect a word first thing or [...] + tmp = Chunk::NullChunkPtr; + + if (os != nullptr) + { + tmp = os->GetNextNcNnl(); + } + + if ( tmp->Is(CT_SQUARE_OPEN) + || tmp->Is(CT_PAREN_OPEN) + || tmp->Is(CT_OC_AT)) + { + Chunk *tt = tmp->GetNextNcNnl(); + + if ( tmp->Is(CT_OC_AT) + && tt->IsNotNullChunk()) + { + if ( tt->Is(CT_PAREN_OPEN) + || tt->Is(CT_BRACE_OPEN) + || tt->Is(CT_SQUARE_OPEN)) + { + tmp = tt; + } + else + { + LOG_FMT(LOCMSG, "%s(%d): tmp orig line is %zu, orig col is %zu, expected identifier, not '%s' [%s]\n", + __func__, __LINE__, tmp->GetOrigLine(), tmp->GetOrigCol(), + tmp->Text(), get_token_name(tmp->GetType())); + return; + } + } + tmp = tmp->GetClosingParen(); + } + else if ( tmp->IsNot(CT_WORD) + && tmp->IsNot(CT_TYPE) + && tmp->IsNot(CT_THIS) + && tmp->IsNot(CT_STAR) + && tmp->IsNot(CT_STRING)) + { + LOG_FMT(LOCMSG, "%s(%d): orig line is %zu, orig col is %zu, expected identifier, not '%s' [%s]\n", + __func__, __LINE__, tmp->GetOrigLine(), tmp->GetOrigCol(), + tmp->Text(), get_token_name(tmp->GetType())); + return; + } + else + { + if (tmp->IsStar()) // Issue #2722 + { + tmp->SetType(CT_PTR_TYPE); + tmp = tmp->GetNextNcNnl(); + } + Chunk *tt = tmp->GetNextNcNnl(); + + if (tt->IsParenOpen()) + { + LOG_FMT(LFCN, "%s(%d): (18) SET TO CT_FUNC_CALL: orig line is %zu, orig col is %zu, Text() '%s'\n", + __func__, __LINE__, tmp->GetOrigLine(), tmp->GetOrigCol(), tmp->Text()); + tmp->SetType(CT_FUNC_CALL); + tmp = set_paren_parent(tt, CT_FUNC_CALL)->GetPrevNcNnlNi(); // Issue #2279 + } + else + { + tmp->SetType(CT_OC_MSG_CLASS); + } + } + os->SetParentType(CT_OC_MSG); + os->SetFlagBits(PCF_IN_OC_MSG); + cs->SetParentType(CT_OC_MSG); + cs->SetFlagBits(PCF_IN_OC_MSG); + + // handle '< protocol >' + tmp = tmp->GetNextNcNnl(); + + if (tmp->IsString("<")) + { + Chunk *ao = tmp; + Chunk *ac = ao->GetNextString(">", 1, ao->GetLevel()); + + if (ac->IsNotNullChunk()) + { + ao->SetType(CT_ANGLE_OPEN); + ao->SetParentType(CT_OC_PROTO_LIST); + ac->SetType(CT_ANGLE_CLOSE); + ac->SetParentType(CT_OC_PROTO_LIST); + + for (tmp = ao->GetNext(); tmp != ac; tmp = tmp->GetNext()) + { + tmp->SetLevel(tmp->GetLevel() + 1); + tmp->SetParentType(CT_OC_PROTO_LIST); + } + + tmp = ac->GetNextNcNnl(); + } + else + { + tmp = Chunk::NullChunkPtr; + } + } + // handle 'object.property' and 'collection[index]' + else + { + while (tmp->IsNotNullChunk()) + { + if (tmp->Is(CT_MEMBER)) // move past [object.prop1.prop2 + { + Chunk *typ = tmp->GetNextNcNnl(); + + if ( typ->Is(CT_WORD) + || typ->Is(CT_TYPE)) + { + tmp = typ->GetNextNcNnl(); + } + else + { + break; + } + } + else if (tmp->Is(CT_SQUARE_OPEN)) // move past [collection[index] + { + Chunk *tcs = tmp->GetNextNcNnl(); + + while ( tcs->IsNotNullChunk() + && tcs->GetLevel() > tmp->GetLevel()) + { + tcs = tcs->GetNextNcNnl(); + } + + if (tcs->Is(CT_SQUARE_CLOSE)) + { + tmp = tcs->GetNextNcNnl(); + } + else + { + break; + } + } + else + { + break; + } + } + } + + // [(self.foo.bar) method] + if (tmp->IsParenOpen()) + { + tmp = tmp->GetClosingParen()->GetNextNcNnl(); + } + + if ( tmp->Is(CT_WORD) + || tmp->Is(CT_ACCESS) + || tmp->Is(CT_TYPE)) + { + tmp->SetType(CT_OC_MSG_FUNC); + } + Chunk *prev = Chunk::NullChunkPtr; + + for (tmp = os->GetNext(); tmp != cs; tmp = tmp->GetNext()) + { + tmp->SetFlagBits(PCF_IN_OC_MSG); + + if (tmp->GetLevel() == cs->GetLevel() + 1) + { + if ( tmp->Is(CT_COLON) + || tmp->Is(CT_ACCESS_COLON)) + { + tmp->SetType(CT_OC_COLON); + + if ( prev->Is(CT_WORD) + || prev->Is(CT_ACCESS) + || prev->Is(CT_TYPE)) + { + // Might be a named param, check previous block + Chunk *pp = prev->GetPrev(); + + if ( pp->IsNotNullChunk() + && pp->IsNot(CT_OC_COLON) + && pp->IsNot(CT_ARITH) + && pp->IsNot(CT_SHIFT) + && pp->IsNot(CT_CARET)) + { + prev->SetType(CT_OC_MSG_NAME); + tmp->SetParentType(CT_OC_MSG_NAME); + } + } + } + } + prev = tmp; + } +} // handle_oc_message_send + + +static void handle_oc_available(Chunk *os) +{ + if (os != nullptr) + { + os = os->GetNext(); + } + else + { + os = Chunk::NullChunkPtr; + } + + while (os->IsNotNullChunk()) + { + E_Token origType = os->GetType(); + os->SetType(CT_OC_AVAILABLE_VALUE); + + if (origType == CT_PAREN_CLOSE) + { + break; + } + os = os->GetNext(); + } +} + + +static void handle_oc_property_decl(Chunk *os) +{ + log_rule_B("mod_sort_oc_properties"); + + if (options::mod_sort_oc_properties()) + { + typedef std::vector<Chunk *> ChunkGroup; + + Chunk *next = Chunk::NullChunkPtr; + + if (os != nullptr) + { + next = os->GetNext(); + } + Chunk *open_paren = nullptr; + + std::vector<ChunkGroup> class_chunks; // class + std::vector<ChunkGroup> thread_chunks; // atomic, nonatomic + std::vector<ChunkGroup> readwrite_chunks; // readwrite, readonly + std::vector<ChunkGroup> ref_chunks; // retain, copy, assign, weak, strong, unsafe_unretained + std::vector<ChunkGroup> getter_chunks; // getter + std::vector<ChunkGroup> setter_chunks; // setter + std::vector<ChunkGroup> nullability_chunks; // nonnull, nullable, null_unspecified, null_resettable + std::vector<ChunkGroup> other_chunks; // any words other than above + + if (next->Is(CT_PAREN_OPEN)) + { + open_paren = next; + next = next->GetNext(); + + /* + * Determine location of the property attributes + * NOTE: Did not do this in the combine.cpp do_symbol_check as + * I was not sure what the ramifications of adding a new type + * for each of the below types would be. It did break some items + * when I attempted to add them so this is my hack for now. + */ + while ( next->IsNotNullChunk() + && next->IsNot(CT_PAREN_CLOSE)) + { + if (next->Is(CT_OC_PROPERTY_ATTR)) + { + if ( next->IsString("atomic") + || next->IsString("nonatomic")) + { + ChunkGroup chunkGroup; + chunkGroup.push_back(next); + thread_chunks.push_back(chunkGroup); + } + else if ( next->IsString("readonly") + || next->IsString("readwrite")) + { + ChunkGroup chunkGroup; + chunkGroup.push_back(next); + readwrite_chunks.push_back(chunkGroup); + } + else if ( next->IsString("assign") + || next->IsString("retain") + || next->IsString("copy") + || next->IsString("strong") + || next->IsString("weak") + || next->IsString("unsafe_unretained")) + { + ChunkGroup chunkGroup; + chunkGroup.push_back(next); + ref_chunks.push_back(chunkGroup); + } + else if (next->IsString("getter")) + { + ChunkGroup chunkGroup; + + do + { + chunkGroup.push_back(next); + next = next->GetNext(); + } while ( next->IsNotNullChunk() + && next->IsNot(CT_COMMA) + && next->IsNot(CT_PAREN_CLOSE)); + + next = next->GetPrev(); + + // coverity CID 160946 + if (next->IsNullChunk()) + { + break; + } + getter_chunks.push_back(chunkGroup); + } + else if (next->IsString("setter")) + { + ChunkGroup chunkGroup; + + do + { + chunkGroup.push_back(next); + next = next->GetNext(); + } while ( next->IsNotNullChunk() + && next->IsNot(CT_COMMA) + && next->IsNot(CT_PAREN_CLOSE)); + + if (next->IsNotNullChunk()) + { + next = next->GetPrev(); + } + + if (next->IsNullChunk()) + { + break; + } + setter_chunks.push_back(chunkGroup); + } + else if ( next->IsString("nullable") + || next->IsString("nonnull") + || next->IsString("null_resettable") + || next->IsString("null_unspecified")) + { + ChunkGroup chunkGroup; + chunkGroup.push_back(next); + nullability_chunks.push_back(chunkGroup); + } + else if (next->IsString("class")) + { + ChunkGroup chunkGroup; + chunkGroup.push_back(next); + class_chunks.push_back(chunkGroup); + } + else + { + ChunkGroup chunkGroup; + chunkGroup.push_back(next); + other_chunks.push_back(chunkGroup); + } + } + else if (next->IsWord()) + { + if (next->IsString("class")) + { + ChunkGroup chunkGroup; + chunkGroup.push_back(next); + class_chunks.push_back(chunkGroup); + } + else + { + ChunkGroup chunkGroup; + chunkGroup.push_back(next); + other_chunks.push_back(chunkGroup); + } + } + next = next->GetNext(); + } + log_rule_B("mod_sort_oc_property_class_weight"); + int class_w = options::mod_sort_oc_property_class_weight(); + log_rule_B("mod_sort_oc_property_thread_safe_weight"); + int thread_w = options::mod_sort_oc_property_thread_safe_weight(); + log_rule_B("mod_sort_oc_property_readwrite_weight"); + int readwrite_w = options::mod_sort_oc_property_readwrite_weight(); + log_rule_B("mod_sort_oc_property_reference_weight"); + int ref_w = options::mod_sort_oc_property_reference_weight(); + log_rule_B("mod_sort_oc_property_getter_weight"); + int getter_w = options::mod_sort_oc_property_getter_weight(); + log_rule_B("mod_sort_oc_property_setter_weight"); + int setter_w = options::mod_sort_oc_property_setter_weight(); + log_rule_B("mod_sort_oc_property_nullability_weight"); + int nullability_w = options::mod_sort_oc_property_nullability_weight(); + + // + std::multimap<int, std::vector<ChunkGroup> > sorted_chunk_map; + sorted_chunk_map.insert(pair<int, std::vector<ChunkGroup> >(class_w, class_chunks)); + sorted_chunk_map.insert(pair<int, std::vector<ChunkGroup> >(thread_w, thread_chunks)); + sorted_chunk_map.insert(pair<int, std::vector<ChunkGroup> >(readwrite_w, readwrite_chunks)); + sorted_chunk_map.insert(pair<int, std::vector<ChunkGroup> >(ref_w, ref_chunks)); + sorted_chunk_map.insert(pair<int, std::vector<ChunkGroup> >(getter_w, getter_chunks)); + sorted_chunk_map.insert(pair<int, std::vector<ChunkGroup> >(setter_w, setter_chunks)); + sorted_chunk_map.insert(pair<int, std::vector<ChunkGroup> >(nullability_w, nullability_chunks)); + sorted_chunk_map.insert(pair<int, std::vector<ChunkGroup> >(std::numeric_limits<int>::min(), other_chunks)); + + Chunk *curr_chunk = open_paren; + + for (multimap<int, std::vector<ChunkGroup> >::reverse_iterator it = sorted_chunk_map.rbegin(); it != sorted_chunk_map.rend(); ++it) + { + std::vector<ChunkGroup> chunk_groups = (*it).second; + + for (auto chunk_group : chunk_groups) + { + for (auto chunk : chunk_group) + { + chunk->SetOrigPrevSp(0); + + if (chunk != curr_chunk) + { + chunk->MoveAfter(curr_chunk); + curr_chunk = chunk; + } + else + { + curr_chunk = curr_chunk->GetNext(); + } + } + + // add the parenthesis + Chunk endchunk; + endchunk.SetType(CT_COMMA); + endchunk.SetParentType(curr_chunk->GetParentType()); + endchunk.Str() = ","; + endchunk.SetLevel(curr_chunk->GetLevel()); + endchunk.SetPpLevel(curr_chunk->GetPpLevel()); + endchunk.SetBraceLevel(curr_chunk->GetBraceLevel()); + endchunk.SetOrigLine(curr_chunk->GetOrigLine()); + endchunk.SetOrigCol(curr_chunk->GetOrigCol()); + endchunk.SetColumn(curr_chunk->GetOrigColEnd() + 1); + endchunk.SetFlags(curr_chunk->GetFlags() & PCF_COPY_FLAGS); + endchunk.CopyAndAddAfter(curr_chunk); + curr_chunk = curr_chunk->GetNext(); + } + } + + // Remove the extra comma's that we did not move + while ( curr_chunk != nullptr + && curr_chunk->IsNotNullChunk() + && curr_chunk->IsNot(CT_PAREN_CLOSE)) + { + Chunk *rm_chunk = curr_chunk; + curr_chunk = curr_chunk->GetNext(); + Chunk::Delete(rm_chunk); + } + } + } + Chunk *tmp = Chunk::NullChunkPtr; + + if (os != nullptr) + { + tmp = os->GetNextNcNnl(); + } + + if (tmp->IsParenOpen()) + { + tmp = tmp->GetClosingParen()->GetNextNcNnl(); + } + fix_variable_definition(tmp); +} // handle_oc_property_decl + + +static void handle_cs_square_stmt(Chunk *os) +{ + LOG_FUNC_ENTRY(); + + if (os == nullptr) + { + os = Chunk::NullChunkPtr; + } + Chunk *cs = os->GetNext(); + + while ( cs->IsNotNullChunk() + && cs->GetLevel() > os->GetLevel()) + { + cs = cs->GetNext(); + } + + if ( cs->IsNullChunk() + || cs->IsNot(CT_SQUARE_CLOSE)) + { + return; + } + os->SetParentType(CT_CS_SQ_STMT); + cs->SetParentType(CT_CS_SQ_STMT); + + Chunk *tmp; + + for (tmp = os->GetNext(); tmp != cs; tmp = tmp->GetNext()) + { + tmp->SetParentType(CT_CS_SQ_STMT); + + if (tmp->Is(CT_COLON)) + { + tmp->SetType(CT_CS_SQ_COLON); + } + } + + tmp = cs->GetNextNcNnl(); + + if (tmp->IsNotNullChunk()) + { + tmp->SetFlagBits(PCF_STMT_START | PCF_EXPR_START); + } +} // handle_cs_square_stmt + + +static void handle_cs_property(Chunk *bro) +{ + LOG_FUNC_ENTRY(); + + set_paren_parent(bro, CT_CS_PROPERTY); + + bool did_prop = false; + Chunk *pc = bro; + + while ((pc = pc->GetPrevNcNnlNi())->IsNotNullChunk()) // Issue #2279 + { + if (pc->GetLevel() == bro->GetLevel()) + { + //prevent scanning back past 'new' in expressions like new List<int> {1,2,3} + // Issue # 1620, UNI-24090.cs + if (pc->Is(CT_NEW)) + { + break; + } + + if ( !did_prop + && ( pc->Is(CT_WORD) + || pc->Is(CT_THIS))) + { + pc->SetType(CT_CS_PROPERTY); + did_prop = true; + } + else + { + pc->SetParentType(CT_CS_PROPERTY); + make_type(pc); + } + + if (pc->TestFlags(PCF_STMT_START)) + { + break; + } + } + } +} + + +static void handle_cs_array_type(Chunk *pc) +{ + if ( pc == nullptr + || pc->IsNullChunk()) + { + return; + } + Chunk *prev = pc->GetPrev(); + + for ( ; + prev->Is(CT_COMMA); + prev = prev->GetPrev()) + { + // empty + } + + if (prev->Is(CT_SQUARE_OPEN)) + { + while (pc != prev) + { + pc->SetParentType(CT_TYPE); + pc = pc->GetPrev(); + } + prev->SetParentType(CT_TYPE); + } +} + + +static void handle_wrap(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + Chunk *opp = Chunk::NullChunkPtr; + + if (pc != nullptr) + { + opp = pc->GetNext(); + } + Chunk *name = opp->GetNext(); + Chunk *clp = name->GetNext(); + + log_rule_B("sp_func_call_paren"); + log_rule_B("sp_cpp_cast_paren"); + iarf_e pav = pc->Is(CT_FUNC_WRAP) ? + options::sp_func_call_paren() : + options::sp_cpp_cast_paren(); + + log_rule_B("sp_inside_fparen"); + log_rule_B("sp_inside_paren_cast"); + iarf_e av = pc->Is(CT_FUNC_WRAP) ? + options::sp_inside_fparen() : + options::sp_inside_paren_cast(); + + if ( clp->Is(CT_PAREN_CLOSE) + && opp->Is(CT_PAREN_OPEN) + && ( name->Is(CT_WORD) + || name->Is(CT_TYPE))) + { + const char *psp = (pav & IARF_ADD) ? " " : ""; + const char *fsp = (av & IARF_ADD) ? " " : ""; + + pc->Str().append(psp); + pc->Str().append("("); + pc->Str().append(fsp); + pc->Str().append(name->GetStr()); + pc->Str().append(fsp); + pc->Str().append(")"); + + pc->SetType(pc->Is(CT_FUNC_WRAP) ? CT_FUNCTION : CT_TYPE); + + pc->SetOrigColEnd(pc->GetOrigCol() + pc->Len()); + + Chunk::Delete(opp); + Chunk::Delete(name); + Chunk::Delete(clp); + } +} // handle_wrap + + +static void handle_proto_wrap(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + Chunk *opp = pc->GetNextNcNnl(); + Chunk *name = opp->GetNextNcNnl(); + Chunk *tmp = name->GetNextNcNnl()->GetNextNcNnl(); + Chunk *clp = opp->GetClosingParen(); + Chunk *cma = clp->GetNextNcNnl(); + + if ( opp->IsNullChunk() + || name->IsNullChunk() + || tmp->IsNullChunk() + || clp == nullptr + || cma->IsNullChunk() + || ( name->IsNot(CT_WORD) + && name->IsNot(CT_TYPE)) + || opp->IsNot(CT_PAREN_OPEN)) + { + return; + } + + if (cma->Is(CT_SEMICOLON)) + { + pc->SetType(CT_FUNC_PROTO); + } + else if (cma->Is(CT_BRACE_OPEN)) + { + LOG_FMT(LFCN, "%s(%d): (19) SET TO CT_FUNC_DEF: orig line is %zu, orig col is %zu, Text() '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc->SetType(CT_FUNC_DEF); + } + else + { + return; + } + opp->SetParentType(pc->GetType()); + clp->SetParentType(pc->GetType()); + + tmp->SetParentType(CT_PROTO_WRAP); + + if (tmp->Is(CT_PAREN_OPEN)) + { + fix_fcn_def_params(tmp); + } + else + { + fix_fcn_def_params(opp); + name->SetType(CT_WORD); + } + tmp = tmp->GetClosingParen(); + + if (tmp->IsNotNullChunk()) + { + tmp->SetParentType(CT_PROTO_WRAP); + } + // Mark return type (TODO: move to own function) + tmp = pc; + + while ((tmp = tmp->GetPrevNcNnlNi())->IsNotNullChunk()) // Issue #2279 + { + if ( !tmp->IsTypeDefinition() + && tmp->IsNot(CT_OPERATOR) + && tmp->IsNot(CT_WORD) + && tmp->IsNot(CT_ADDR)) + { + break; + } + tmp->SetParentType(pc->GetType()); + make_type(tmp); + } +} // handle_proto_wrap + + +/** + * Java assert statements are: "assert EXP1 [: EXP2] ;" + * Mark the parent of the colon and semicolon + */ +static void handle_java_assert(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + bool did_colon = false; + Chunk *tmp = pc; + + if (tmp == nullptr) + { + tmp = Chunk::NullChunkPtr; + } + + while ((tmp = tmp->GetNext())->IsNotNullChunk()) + { + if (tmp->GetLevel() == pc->GetLevel()) + { + if ( !did_colon + && tmp->Is(CT_COLON)) + { + did_colon = true; + tmp->SetParentType(pc->GetType()); + } + + if (tmp->Is(CT_SEMICOLON)) + { + tmp->SetParentType(pc->GetType()); + break; + } + } + } +} // handle_java_assert diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine.h new file mode 100644 index 00000000..5cab3494 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine.h @@ -0,0 +1,79 @@ +/** + * @file combine.h + * prototypes for combine.cpp + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef COMBINE_H_INCLUDED +#define COMBINE_H_INCLUDED + +#include "chunk.h" +#include "uncrustify_types.h" + +void mark_question_colon(); + + +/** + * Change CT_INCDEC_AFTER + WORD to CT_INCDEC_BEFORE + * Change number/word + CT_ADDR to CT_ARITH + * Change number/word + CT_STAR to CT_ARITH + * Change number/word + CT_NEG to CT_ARITH + * Change word + ( to a CT_FUNCTION + * Change struct/union/enum + CT_WORD => CT_TYPE + * Force parens on return. + * + * TODO: This could be done earlier. + * + * Patterns detected: + * STRUCT/ENUM/UNION + WORD :: WORD => TYPE + * WORD + '(' :: WORD => FUNCTION + */ +void fix_symbols(); + + +/** + * Examines the whole file and changes CT_COLON to + * CT_Q_COLON, CT_LABEL_COLON, or CT_CASE_COLON. + * It also changes the CT_WORD before CT_LABEL_COLON into CT_LABEL. + */ +void combine_labels(); + + +//! help function for mark_variable_definition... +bool go_on(Chunk *pc, Chunk *start); + + +//! Sets the parent for comments. +void mark_comments(); + + +void make_type(Chunk *pc); + + +/** + * Sets the parent of the open paren/brace/square/angle and the closing. + * Note - it is assumed that pc really does point to an open item and the + * close must be open + 1. + * + * @param start The open paren + * @param parent The type to assign as the parent + * + * @return The chunk after the close paren + */ +Chunk *set_paren_parent(Chunk *start, E_Token parent); + + +/** + * This is called on every chunk. + * First on all non-preprocessor chunks and then on each preprocessor chunk. + * It does all the detection and classifying. + * This is only called by fix_symbols. + * The three parameters never get the value nullptr. + * it is not necessary to test. + */ +void do_symbol_check(Chunk *prev, Chunk *pc, Chunk *next); + + +#endif /* COMBINE_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_fix_mark.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_fix_mark.cpp new file mode 100644 index 00000000..ebaedce0 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_fix_mark.cpp @@ -0,0 +1,2623 @@ +/** + * @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 *start) +{ + LOG_FUNC_ENTRY(); + Chunk *pc; + Chunk *prev; + Chunk *first; + Chunk *after; + Chunk *last = Chunk::NullChunkPtr; + Chunk *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->GetOrigLine(), start->GetOrigCol()); + + prev = start->GetPrevNcNnlNi(); // Issue #2279 + + if (prev->IsNullChunk()) + { + return; + } + + if (prev->Is(CT_PP_DEFINED)) + { + LOG_FMT(LCASTS, "%s(%d): -- not a cast - after defined\n", + __func__, __LINE__); + return; + } + + if (prev->Is(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 = start->GetNextNcNnl(); + first = pc; + + while ( pc->IsNotNullChunk() + && ( pc->IsTypeDefinition() + || pc->Is(CT_WORD) + || pc->Is(CT_QUALIFIER) + || pc->Is(CT_DC_MEMBER) + || pc->Is(CT_PP) + || pc->Is(CT_STAR) + || pc->Is(CT_QUESTION) + || pc->Is(CT_CARET) + || pc->Is(CT_TSQUARE) + || ( ( pc->Is(CT_ANGLE_OPEN) + || pc->Is(CT_ANGLE_CLOSE)) + && language_is_set(LANG_OC | LANG_JAVA | LANG_CS | LANG_VALA | LANG_CPP)) + || ( ( pc->Is(CT_QUESTION) + || pc->Is(CT_COMMA) + || pc->Is(CT_MEMBER)) + && language_is_set(LANG_JAVA | LANG_CS | LANG_VALA)) + || ( pc->Is(CT_COMMA) + && language_is_set(LANG_CPP)) + || pc->Is(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->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + + if ( pc->Is(CT_WORD) + || ( last->Is(CT_ANGLE_CLOSE) + && pc->Is(CT_DC_MEMBER))) + { + word_count++; + } + else if ( pc->Is(CT_DC_MEMBER) + || pc->Is(CT_MEMBER) + || pc->Is(CT_PP)) + { + // might be negative, such as with: + // a = val + (CFoo::bar_t)7; + word_count--; + } + last = pc; + pc = pc->GetNextNcNnl(); + count++; + } + + if ( pc->IsNullChunk() + || pc->IsNot(CT_PAREN_CLOSE) + || prev->Is(CT_OC_CLASS)) + { + LOG_FMT(LCASTS, "%s(%d): -- not a cast, hit type is %s\n", + __func__, __LINE__, pc->IsNullChunk() ? "Null chunk" : get_token_name(pc->GetType())); + 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 ( last->Is(CT_STAR) + || last->Is(CT_CARET) + || last->Is(CT_PTR_TYPE) + || last->Is(CT_TYPE) + || ( last->Is(CT_ANGLE_CLOSE) + && language_is_set(LANG_OC | LANG_JAVA | LANG_CS | LANG_VALA | LANG_CPP))) + { + 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->GetStr()[last->Len() - 2] == '_') + && (last->GetStr()[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) + && last->IsString("id")) + { + 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 = paren_close->GetNextNcNnl(); + after = pc; + + do + { + after = after->GetNextNcNnl(); + } while (after->Is(CT_PAREN_OPEN)); + + if (after->IsNullChunk()) + { + LOG_FMT(LCASTS, "%s(%d): -- not a cast - hit null chunk\n", + __func__, __LINE__); + return; + } + nope = false; + + if (pc->IsPointerOperator()) + { + // star (*) and address (&) are ambiguous + if ( after->Is(CT_NUMBER_FP) + || after->Is(CT_NUMBER) + || after->Is(CT_STRING) + || doubtful_cast) + { + nope = true; + } + } + else if (pc->Is(CT_MINUS)) + { + // (UINT8)-1 or (foo)-1 or (FOO)-'a' + if ( after->Is(CT_STRING) + || doubtful_cast) + { + nope = true; + } + } + else if (pc->Is(CT_PLUS)) + { + // (UINT8)+1 or (foo)+1 + if ( ( after->IsNot(CT_NUMBER) + && after->IsNot(CT_NUMBER_FP)) + || doubtful_cast) + { + nope = true; + } + } + else if ( pc->IsNot(CT_NUMBER_FP) + && pc->IsNot(CT_NUMBER) + && pc->IsNot(CT_WORD) + && pc->IsNot(CT_THIS) + && pc->IsNot(CT_TYPE) + && pc->IsNot(CT_PAREN_OPEN) + && pc->IsNot(CT_STRING) + && pc->IsNot(CT_DECLTYPE) + && pc->IsNot(CT_SIZEOF) + && pc->GetParentType() != CT_SIZEOF + && pc->IsNot(CT_FUNC_CALL) + && pc->IsNot(CT_FUNC_CALL_USER) + && pc->IsNot(CT_FUNCTION) + && pc->IsNot(CT_BRACE_OPEN) + && (!( pc->Is(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->GetType())); + 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->GetType())); + return; + } + } + // if the 'cast' is followed by a semicolon, comma, bool or close parenthesis, it isn't + pc = paren_close->GetNextNcNnl(); + + if (pc->IsNullChunk()) + { + return; + } + + if ( pc->IsSemicolon() + || pc->Is(CT_COMMA) + || pc->Is(CT_BOOL) // Issue #2151 + || pc->IsParenClose()) + { + LOG_FMT(LCASTS, "%s(%d): -- not a cast - followed by type %s\n", + __func__, __LINE__, get_token_name(pc->GetType())); + return; + } + start->SetParentType(CT_C_CAST); + paren_close->SetParentType(CT_C_CAST); + + LOG_FMT(LCASTS, "%s(%d): -- %s c-cast: (", + __func__, __LINE__, verb); + + for (pc = first; + pc->IsNotNullChunk() && pc != paren_close; + pc = pc->GetNextNcNnl()) + { + pc->SetParentType(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 = paren_close->GetNextNcNnl(); + + if (pc->IsNotNullChunk()) + { + pc->SetFlagBits(PCF_EXPR_START); + + if (pc->IsBraceOpen()) + { + set_paren_parent(pc, start->GetParentType()); + } + } +} // fix_casts + + +void fix_fcn_def_params(Chunk *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->GetType()), start->GetOrigLine(), start->GetLevel()); + + while ( start->IsNotNullChunk() + && !start->IsParenOpen()) + { + start = start->GetNextNcNnl(); + } + + if (start->IsNullChunk()) // Coverity CID 76003, 1100782 + { + return; + } + // ensure start chunk holds a single '(' character + assert( (start->Len() == 1) + && (start->GetStr()[0] == '(')); + + ChunkStack cs; + size_t level = start->GetLevel() + 1; + Chunk *pc = start->GetNextNcNnl(); + + while (pc->IsNotNullChunk()) + { + if ( ( (start->Len() == 1) + && (start->GetStr()[0] == ')')) + || pc->GetLevel() < level) + { + LOG_FMT(LFCNP, "%s(%d): bailed on Text() '%s', on orig line %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine()); + break; + } + LOG_FMT(LFCNP, "%s(%d): %s, Text() '%s' on orig line %zu, level %zu\n", + __func__, __LINE__, (pc->GetLevel() > level) ? "skipping" : "looking at", + pc->Text(), pc->GetOrigLine(), pc->GetLevel()); + + if (pc->GetLevel() > level) + { + pc = pc->GetNextNcNnl(); + continue; + } + + if ( pc->IsStar() + || pc->IsMsRef() + || pc->IsNullable()) + { + pc->SetType(CT_PTR_TYPE); + cs.Push_Back(pc); + } + else if ( language_is_set(LANG_CPP) // Issue #3662 + && ( pc->Is(CT_AMP) + || pc->IsString("&&"))) + { + pc->SetType(CT_BYREF); + cs.Push_Back(pc); + } + else if (pc->Is(CT_TYPE_WRAP)) + { + cs.Push_Back(pc); + } + else if ( pc->Is(CT_WORD) + || pc->Is(CT_TYPE)) + { + cs.Push_Back(pc); + } + else if ( pc->Is(CT_COMMA) + || pc->Is(CT_ASSIGN)) + { + mark_variable_stack(cs, LFCNP); + + if (pc->Is(CT_ASSIGN)) + { + // Mark assignment for default param spacing + pc->SetParentType(CT_FUNC_PROTO); + } + } + pc = pc->GetNextNcNnl(); + } + mark_variable_stack(cs, LFCNP); +} // fix_fcn_def_params + + +void fix_type_cast(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + if (start == nullptr) + { + return; + } + Chunk *pc = start->GetNextNcNnl(); + + if ( pc->IsNullChunk() + || pc->IsNot(CT_ANGLE_OPEN)) + { + return; + } + pc = pc->GetNextNcNnl(); + + while ( pc->IsNotNullChunk() + && pc->GetLevel() >= start->GetLevel()) + { + if ( pc->GetLevel() == start->GetLevel() + && pc->Is(CT_ANGLE_CLOSE)) + { + pc = pc->GetNextNcNnl(); + + if (pc->IsNullChunk()) + { + return; + } + + if (pc->IsString("(")) + { + set_paren_parent(pc, CT_TYPE_CAST); + } + return; + } + make_type(pc); + pc = pc->GetNextNcNnl(); + } +} // fix_type_cast + + +void fix_typedef(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + if (start == nullptr) + { + return; + } + LOG_FMT(LTYPEDEF, "%s(%d): typedef @ orig line %zu, orig col %zu\n", + __func__, __LINE__, start->GetOrigLine(), start->GetOrigCol()); + + Chunk *the_type = Chunk::NullChunkPtr; + Chunk *last_op = Chunk::NullChunkPtr; + + /* + * Mark everything in the typedef and scan for ")(", which makes it a + * function type + */ + for (Chunk *next = start->GetNextNcNnl(E_Scope::PREPROC) + ; next->IsNotNullChunk() && next->GetLevel() >= start->GetLevel() + ; next = next->GetNextNcNnl(E_Scope::PREPROC)) + { + next->SetFlagBits(PCF_IN_TYPEDEF); + + if (start->GetLevel() == next->GetLevel()) + { + if (next->IsSemicolon()) + { + next->SetParentType(CT_TYPEDEF); + break; + } + + if (next->Is(CT_ATTRIBUTE)) + { + break; + } + + if ( language_is_set(LANG_D) + && next->Is(CT_ASSIGN)) + { + next->SetParentType(CT_TYPEDEF); + break; + } + make_type(next); + + if (next->Is(CT_TYPE)) + { + the_type = next; + } + next->ResetFlagBits(PCF_VAR_1ST_DEF); + + if (*next->GetStr().c_str() == '(') + { + last_op = next; + } + } + } + + // avoid interpreting typedef NS_ENUM (NSInteger, MyEnum) as a function def + if ( last_op->IsNotNullChunk() + && !( language_is_set(LANG_OC) + && last_op->GetParentType() == CT_ENUM)) + { + flag_parens(last_op, PCF_NONE, CT_FPAREN_OPEN, CT_TYPEDEF, false); + fix_fcn_def_params(last_op); + + the_type = last_op->GetPrevNcNnlNi(E_Scope::PREPROC); // Issue #2279 + + if (the_type->IsNullChunk()) + { + return; + } + Chunk *open_paren = Chunk::NullChunkPtr; + + if (the_type->IsParenClose()) + { + open_paren = the_type->GetOpeningParen(); + mark_function_type(the_type); + the_type = the_type->GetPrevNcNnlNi(E_Scope::PREPROC); // Issue #2279 + + if (the_type->IsNullChunk()) + { + return; + } + } + else + { + // must be: "typedef <return type>func(params);" + the_type->SetType(CT_FUNC_TYPE); + } + the_type->SetParentType(CT_TYPEDEF); + + LOG_FMT(LTYPEDEF, "%s(%d): fcn typedef Text() '%s', on orig line %zu\n", + __func__, __LINE__, the_type->Text(), the_type->GetOrigLine()); + + // If we are aligning on the open parenthesis, grab that instead + log_rule_B("align_typedef_func"); + + if ( open_paren->IsNotNullChunk() + && 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->GetOrigLine(), the_type->GetOrigCol()); + the_type->SetFlagBits(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 *after = start->GetNextNcNnl(E_Scope::PREPROC); + + if (after->IsNullChunk()) + { + return; + } + + if ( after->IsNot(CT_ENUM) + && after->IsNot(CT_STRUCT) + && after->IsNot(CT_UNION)) + { + if ( the_type != nullptr + && the_type->IsNotNullChunk()) + { + // 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->GetOrigLine()); + the_type->SetFlagBits(PCF_ANCHOR); + } + return; + } + // We have a struct/union/enum, next should be either a type or { + Chunk *next = after->GetNextNcNnl(E_Scope::PREPROC); + + if (next->IsNullChunk()) + { + return; + } + + if (next->Is(CT_TYPE)) + { + next = next->GetNextNcNnl(E_Scope::PREPROC); + + if (next->IsNullChunk()) + { + return; + } + } + + if (next->Is(CT_BRACE_OPEN)) + { + // Skip to the closing brace + Chunk *br_c = next->GetNextType(CT_BRACE_CLOSE, next->GetLevel(), E_Scope::PREPROC); + + if (br_c->IsNotNullChunk()) + { + const E_Token tag = after->GetType(); + next->SetParentType(tag); + br_c->SetParentType(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 + && the_type->IsNotNullChunk()) + { + LOG_FMT(LTYPEDEF, "%s(%d): %s typedef Text() %s, on orig line %zu\n", + __func__, __LINE__, get_token_name(after->GetType()), the_type->Text(), + the_type->GetOrigLine()); + the_type->SetFlagBits(PCF_ANCHOR); + } +} // fix_typedef + + +Chunk *fix_variable_definition(Chunk *start) +{ + LOG_FUNC_ENTRY(); + Chunk *pc = start; + Chunk *end; + Chunk *tmp_pc; + ChunkStack cs; + int idx; + int ref_idx; + + LOG_FMT(LFVD, "%s(%d): start at pc orig line is %zu, orig col is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_pcf_flags(LFCNR, pc->GetFlags()); + + // Scan for words and types and stars oh my! + while ( pc->Is(CT_TYPE) + || pc->Is(CT_WORD) + || pc->Is(CT_QUALIFIER) + || pc->Is(CT_TYPENAME) + || pc->Is(CT_DC_MEMBER) + || pc->Is(CT_MEMBER) + || pc->Is(CT_PP) // Issue #3169 + || pc->IsPointerOperator()) + { + LOG_FMT(LFVD, "%s(%d): 1:pc->Text() '%s', type is %s\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType())); + cs.Push_Back(pc); + pc = pc->GetNextNcNnl(); + + if (pc->IsNullChunk()) + { + LOG_FMT(LFVD, "%s(%d): pc is null chunk\n", __func__, __LINE__); + return(Chunk::NullChunkPtr); + } + LOG_FMT(LFVD, "%s(%d): 2:pc->Text() '%s', type is %s\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType())); + + // Skip templates and attributes + pc = skip_template_next(pc); + + if (pc->IsNullChunk()) + { + LOG_FMT(LFVD, "%s(%d): pc is null chunk\n", __func__, __LINE__); + return(Chunk::NullChunkPtr); + } + LOG_FMT(LFVD, "%s(%d): 3:pc->Text() '%s', type is %s\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType())); + + pc = skip_attribute_next(pc); + + if (pc->IsNullChunk()) + { + LOG_FMT(LFVD, "%s(%d): pc is null chunk\n", __func__, __LINE__); + return(Chunk::NullChunkPtr); + } + LOG_FMT(LFVD, "%s(%d): 4:pc->Text() '%s', type is %s\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType())); + + if (language_is_set(LANG_JAVA)) + { + pc = skip_tsquare_next(pc); + + if (pc->IsNotNullChunk()) + { + LOG_FMT(LFVD, "%s(%d): 5:pc->Text() '%s', type is %s\n", __func__, __LINE__, pc->Text(), get_token_name(pc->GetType())); + } + else + { + pc = Chunk::NullChunkPtr; + } + } + } + end = pc; + + if (end->IsNullChunk()) + { + LOG_FMT(LFVD, "%s(%d): end is null chunk\n", __func__, __LINE__); + return(nullptr); + } + LOG_FMT(LFVD, "%s(%d): end->GetType() is %s\n", __func__, __LINE__, get_token_name(end->GetType())); + + if (end->Is(CT_FUNC_CTOR_VAR)) // Issue #3010 + { + return(end); + } + + if ( cs.Len() == 1 + && end->Is(CT_BRACE_OPEN) + && end->GetParentType() == CT_BRACED_INIT_LIST) + { + cs.Get(0)->m_pc->SetType(CT_TYPE); + } + + // Function defs are handled elsewhere + if ( (cs.Len() <= 1) + || end->Is(CT_FUNC_DEF) + || end->Is(CT_FUNC_PROTO) + || end->Is(CT_FUNC_CLASS_DEF) + || end->Is(CT_FUNC_CLASS_PROTO) + || end->Is(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->GetType() == CT_MEMBER) + || (cs.Get(cs.Len() - 2)->m_pc->GetType() == CT_DC_MEMBER))) + { + idx = cs.Len() - 2; + + while (idx > 0) + { + tmp_pc = cs.Get(idx)->m_pc; + + if ( tmp_pc->IsNot(CT_DC_MEMBER) + && tmp_pc->IsNot(CT_MEMBER)) + { + break; + } + idx--; + tmp_pc = cs.Get(idx)->m_pc; + + if ( tmp_pc->IsNot(CT_WORD) + && tmp_pc->IsNot(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->GetOrigLine()); + + for (size_t idxForCs = 0; idxForCs < cs.Len() - 1; idxForCs++) + { + tmp_pc = cs.Get(idxForCs)->m_pc; + make_type(tmp_pc); + tmp_pc->SetFlagBits(PCF_VAR_TYPE); + LOG_FMT(LFVD2, " Text() is '%s', type is %s", tmp_pc->Text(), get_token_name(tmp_pc->GetType())); + } + + 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, orig col is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + mark_variable_definition(cs.Get(cs.Len() - 1)->m_pc); + + if (end->Is(CT_COMMA)) + { + return(end->GetNextNcNnl()); + } + return(skip_to_next_statement(end)); +} // fix_variable_definition + + +void mark_cpp_constructor(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + Chunk *paren_open; + Chunk *tmp; + Chunk *after; + Chunk *var; + bool is_destr = false; + + tmp = pc->GetPrevNcNnlNi(); // Issue #2279 + + if ( tmp->Is(CT_INV) + || tmp->Is(CT_DESTRUCTOR)) + { + tmp->SetType(CT_DESTRUCTOR); + pc->SetParentType(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->GetOrigLine(), pc->GetOrigCol(), + is_destr ? "DE" : "CON", + pc->Text(), get_token_name(pc->GetType()), + tmp->Text(), get_token_name(tmp->GetType())); + + paren_open = skip_template_next(pc->GetNextNcNnl()); + + if (!paren_open->IsString("(")) + { + LOG_FMT(LWARN, "%s:%zu Expected '(', got: [%s]\n", + cpd.filename.c_str(), paren_open->GetOrigLine(), + 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->IsNotNullChunk() + && ( tmp->IsNot(CT_BRACE_OPEN) + || tmp->GetLevel() != paren_open->GetLevel()) + && !tmp->IsSemicolon()) + { + LOG_FMT(LFTOR, "%s(%d): tmp is '%s', orig line is %zu, orig col is %zu\n", + __func__, __LINE__, tmp->Text(), tmp->GetOrigLine(), tmp->GetOrigCol()); + tmp->SetFlagBits(PCF_IN_CONST_ARGS); + tmp = tmp->GetNextNcNnl(); + + if ( tmp->IsString(":") + && tmp->GetLevel() == paren_open->GetLevel()) + { + tmp->SetType(CT_CONSTR_COLON); + hit_colon = true; + } + + if ( hit_colon + && ( tmp->IsParenOpen() + || tmp->IsBraceOpen()) + && tmp->GetLevel() == paren_open->GetLevel()) + { + var = skip_template_prev(tmp->GetPrevNcNnlNi()); // Issue #2279 + + if ( var->Is(CT_TYPE) + || var->Is(CT_WORD)) + { + var->SetType(CT_FUNC_CTOR_VAR); + flag_parens(tmp, PCF_IN_FCN_CALL, CT_FPAREN_OPEN, CT_FUNC_CTOR_VAR, false); + } + } + } + + if (tmp->Is(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->GetOrigLine(), pc->GetOrigCol()); + } + else + { + tmp->SetParentType(CT_FUNC_CLASS_PROTO); + pc->SetType(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->GetOrigLine(), pc->GetOrigCol()); + } + tmp = pc->GetPrevNcNnlNi(); // Issue #2907 + + if (tmp->Is(CT_DESTRUCTOR)) + { + tmp->SetParentType(pc->GetType()); + tmp = tmp->GetPrevNcNnlNi(); + } + + while (tmp->Is(CT_QUALIFIER)) + { + tmp->SetParentType(pc->GetType()); + tmp = tmp->GetPrevNcNnlNi(); + } +} // mark_cpp_constructor + + +void mark_cpp_lambda(Chunk *square_open) +{ + if ( square_open->Is(CT_SQUARE_OPEN) + && square_open->GetParentType() == CT_CPP_LAMBDA) + { + auto *brace_close = square_open->GetNextType(CT_BRACE_CLOSE, square_open->GetLevel()); + + if (brace_close->GetParentType() == CT_CPP_LAMBDA) + { + for (auto *pc = square_open; pc != brace_close; pc = pc->GetNextNcNnl()) + { + pc->SetFlagBits(PCF_IN_LAMBDA); + } + } + } +} // mark_cpp_lambda + + +void mark_define_expressions() +{ + LOG_FUNC_ENTRY(); + + bool in_define = false; + bool first = true; + Chunk *pc = Chunk::GetHead(); + Chunk *prev = pc; + + while (pc->IsNotNullChunk()) + { + if (!in_define) + { + if ( pc->Is(CT_PP_DEFINE) + || pc->Is(CT_PP_IF) + || pc->Is(CT_PP_ELSE)) + { + in_define = true; + first = true; + } + } + else + { + if ( !pc->TestFlags(PCF_IN_PREPROC) + || pc->Is(CT_PREPROC)) + { + in_define = false; + } + else + { + if ( pc->IsNot(CT_MACRO) + && ( first + || prev->Is(CT_PAREN_OPEN) + || prev->Is(CT_ARITH) + || prev->Is(CT_SHIFT) + || prev->Is(CT_CARET) + || prev->Is(CT_ASSIGN) + || prev->Is(CT_COMPARE) + || prev->Is(CT_RETURN) + || prev->Is(CT_GOTO) + || prev->Is(CT_CONTINUE) + || prev->Is(CT_FPAREN_OPEN) + || prev->Is(CT_SPAREN_OPEN) + || prev->Is(CT_BRACE_OPEN) + || prev->IsSemicolon() + || prev->Is(CT_COMMA) + || prev->Is(CT_COLON) + || prev->Is(CT_QUESTION))) + { + pc->SetFlagBits(PCF_EXPR_START); + first = false; + } + } + } + prev = pc; + pc = pc->GetNext(); + } +} // mark_define_expressions + + +void mark_exec_sql(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + Chunk *tmp; + + // Change CT_WORD to CT_SQL_WORD + for (tmp = pc->GetNext(); tmp->IsNotNullChunk(); tmp = tmp->GetNext()) + { + tmp->SetParentType(pc->GetType()); + + if (tmp->Is(CT_WORD)) + { + tmp->SetType(CT_SQL_WORD); + } + + if (tmp->Is(CT_SEMICOLON)) + { + break; + } + } + + if ( pc->IsNot(CT_SQL_BEGIN) + || tmp->IsNullChunk() + || tmp->IsNot(CT_SEMICOLON)) + { + return; + } + + for (tmp = tmp->GetNext(); + tmp->IsNotNullChunk() && tmp->IsNot(CT_SQL_END); + tmp = tmp->GetNext()) + { + tmp->SetLevel(tmp->GetLevel() + 1); + } +} // mark_exec_sql + + +void mark_function_return_type(Chunk *fname, Chunk *start, E_Token parent_type) +{ + LOG_FUNC_ENTRY(); + Chunk *pc = start; + + if ( pc != nullptr + && pc->IsNotNullChunk()) + { + // 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->GetOrigLine(), fname->GetOrigCol()); + + Chunk *first = pc; + + while (pc->IsNotNullChunk()) + { + LOG_FMT(LFCNR, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s, ", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + log_pcf_flags(LFCNR, pc->GetFlags()); + + if (pc->Is(CT_ANGLE_CLOSE)) + { + pc = skip_template_prev(pc); + + if ( pc->IsNullChunk() + || pc->Is(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 ( ( !pc->IsTypeDefinition() + && pc->IsNot(CT_OPERATOR) + && pc->IsNot(CT_WORD) + && pc->IsNot(CT_ADDR)) + || pc->TestFlags(PCF_IN_PREPROC)) + { + break; + } + + if (!pc->IsPointerOperator()) + { + first = pc; + } + pc = pc->GetPrevNcNnlNi(); // 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 ( pc->Is(CT_PAREN_CLOSE) + && !pc->TestFlags(PCF_IN_PREPROC)) + { + first = pc->GetOpeningParen(); + is_return_tuple = true; + } + pc = first; + + while (pc->IsNotNullChunk()) + { + LOG_CHUNK(LTOK, pc); + + if (parent_type != CT_NONE) + { + pc->SetParentType(parent_type); + } + Chunk *prev = pc->GetPrevNcNnlNi(); // Issue #2279 + + if ( !is_return_tuple + || pc->IsNot(CT_WORD) + || ( prev->IsNullChunk() + && prev->IsNot(CT_TYPE))) + { + make_type(pc); + } + + if (pc == start) + { + break; + } + pc = pc->GetNextNcNnl(); + + //template angles should keep parent type CT_TEMPLATE + if (pc->Is(CT_ANGLE_OPEN)) + { + pc = pc->GetNextType(CT_ANGLE_CLOSE, pc->GetLevel()); + + if (pc == start) + { + break; + } + pc = pc->GetNextNcNnl(); + } + } + LOG_FMT(LFCNR, "\n"); + + // Back up and mark parent type on friend declarations + if ( parent_type != CT_NONE + && first + && first->TestFlags(PCF_IN_CLASS)) + { + pc = first->GetPrevNcNnlNi(); // Issue #2279 + + if (pc->Is(CT_FRIEND)) + { + LOG_FMT(LFCNR, "%s(%d): marking friend\n", __func__, __LINE__); + pc->SetParentType(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 = pc->GetPrevNcNnlNi(); // Issue #2279 + + if (pc->Is(CT_ANGLE_CLOSE)) + { + pc = skip_template_prev(pc); + + if (pc->Is(CT_TEMPLATE)) + { + LOG_FMT(LFCNR, "%s(%d): marking friend template\n", + __func__, __LINE__); + pc->SetParentType(parent_type); + } + } + } + } + } +} // mark_function_return_type + + +void mark_function(Chunk *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->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + Chunk *prev = pc->GetPrevNcNnlNi(); // Issue #2279 + Chunk *next = pc->GetNextNppOrNcNnl(); + + if (next->IsNullChunk()) + { + return; + } + Chunk *tmp; + Chunk *semi = nullptr; + Chunk *paren_open; + Chunk *paren_close; + + // Find out what is before the operator + if (pc->GetParentType() == CT_OPERATOR) + { + LOG_FMT(LFCN, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + log_pcf_flags(LGUY, pc->GetFlags()); + Chunk *pc_op = pc->GetPrevType(CT_OPERATOR, pc->GetLevel()); + + if ( pc_op->IsNotNullChunk() + && pc_op->TestFlags(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->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc->SetType(CT_FUNC_CALL); + } + + if (language_is_set(LANG_CPP)) + { + tmp = pc; + + while ((tmp = tmp->GetPrevNcNnlNi())->IsNotNullChunk()) // Issue #2279 + { + if ( tmp->Is(CT_BRACE_CLOSE) + || tmp->Is(CT_BRACE_OPEN) // Issue 575 + || tmp->Is(CT_SEMICOLON)) + { + break; + } + + if ( tmp->IsParenOpen() + && !pc->TestFlags(PCF_IN_PREPROC)) // Issue #2703 + { + LOG_FMT(LFCN, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s'\n", + __func__, __LINE__, tmp->GetOrigLine(), tmp->GetOrigCol(), 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->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc->SetType(CT_FUNC_CALL); + break; + } + + if (tmp->Is(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->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc->SetType(CT_FUNC_CALL); + break; + } + + if (tmp->Is(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->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc->SetType(CT_FUNC_DEF); + break; + } + + if (tmp->Is(CT_BRACE_OPEN)) + { + if (tmp->GetParentType() == 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->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc->SetType(CT_FUNC_CALL); + } + + if ( tmp->GetParentType() == CT_CLASS + || tmp->GetParentType() == 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->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc->SetType(CT_FUNC_DEF); + } + break; + } + } + + if ( tmp != nullptr + && pc->IsNot(CT_FUNC_CALL)) + { + // Mark the return type + tmp = tmp->GetNextNcNnl(); + + while ( tmp != pc + && tmp->IsNotNullChunk()) + { + make_type(tmp); // Mark the return type + tmp = tmp->GetNextNcNnl(); + } + } + } + } + + if ( next->IsPointerOperator() + || next->IsNewline()) + { + next = next->GetNextNppOrNcNnl(); + + if (next->IsNullChunk()) + { + return; + } + } + LOG_FMT(LFCN, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s, type is %s, parent type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), + get_token_name(pc->GetType()), get_token_name(pc->GetParentType())); + LOG_FMT(LFCN, " level is %zu, brace level is %zu, next->Text() '%s', next->GetType() is %s, next->GetLevel() is %zu\n", + pc->GetLevel(), pc->GetBraceLevel(), + next->Text(), get_token_name(next->GetType()), next->GetLevel()); + + if (pc->TestFlags(PCF_IN_CONST_ARGS)) + { + pc->SetType(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->GetOrigLine(), pc->GetOrigCol()); + next = skip_template_next(next); + + if (next == nullptr) + { + return; + } + flag_parens(next, PCF_NONE, CT_FPAREN_OPEN, pc->GetType(), 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 = pc->GetNextString("(", 1, pc->GetLevel()); + paren_close = paren_open->GetNextString(")", 1, pc->GetLevel()); + + if ( paren_open->IsNullChunk() + || paren_close->IsNullChunk()) + { + LOG_FMT(LFCN, "%s(%d): No parens found for [%s] on orig line %zu, orig col %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + return; + } + /* + * This part detects either chained function calls or a function ptr definition. + * MYTYPE (*func)(void); + * MYTYPE (*func(param))(void); + * MYTYPE (*func(param_call1)(param_call2))(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 or by a sequence of one or more expressions each within brackets. + * + * Otherwise, it must be chained function calls. + */ + tmp = paren_close->GetNextNcNnl(); + + if ( tmp->IsNotNullChunk() + && tmp->IsString("(")) + { + Chunk *tmp1; + Chunk *tmp2; + Chunk *tmp3; + + // skip over any leading class/namespace in: "T(F::*A)();" + tmp1 = next->GetNextNcNnl(); + + while (tmp1->IsNotNullChunk()) + { + tmp2 = tmp1->GetNextNcNnl(); + + if ( !tmp1->IsWord() + || tmp2->IsNot(CT_DC_MEMBER)) + { + break; + } + tmp1 = tmp2->GetNextNcNnl(); + } + tmp2 = tmp1->GetNextNcNnl(); + + if (tmp2->IsString(")")) + { + tmp3 = tmp2; + tmp2 = Chunk::NullChunkPtr; + } + else + { + tmp3 = tmp2->GetNextNcNnl(); + } + tmp3 = tmp3->GetNextNbsb(); + + // Issue #3852 + while (tmp3->IsString("(")) + { + tmp3 = tmp3->GetClosingParen(); + tmp3 = tmp3->GetNextNcNnl(); + } + + if ( tmp3->IsString(")") + && ( tmp1->IsStar() + || tmp1->IsMsRef() + || ( language_is_set(LANG_OC) + && tmp1->Is(CT_CARET))) + && ( tmp2->IsNullChunk() + || tmp2->Is(CT_WORD))) + { + if (tmp2->IsNotNullChunk()) + { + 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->GetOrigLine(), pc->GetOrigCol(), tmp2->Text(), pc->Text()); + tmp2->SetType(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->GetOrigLine(), paren_open->GetOrigCol()); + } + 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->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + + if (tmp2) + { + tmp2->SetType(CT_FUNC_TYPE); + } + flag_parens(paren_open, PCF_NONE, CT_PAREN_OPEN, CT_FUNC_TYPE, false); + } + pc->SetType(CT_TYPE); + tmp1->SetType(CT_PTR_TYPE); + pc->ResetFlagBits(PCF_VAR_1ST_DEF); + + if (tmp2->IsNotNullChunk()) + { + tmp2->SetFlagBits(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->GetOrigLine(), pc->GetOrigCol()); + } + + // Assume it is a function call if not already labeled + if (pc->Is(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->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + // look for an assignment. Issue #575 + Chunk *temp = pc->GetNextType(CT_ASSIGN, pc->GetLevel()); + + if (temp->IsNotNullChunk()) + { + LOG_FMT(LFCN, "%s(%d): assignment found, orig line is %zu, orig col is %zu, Text() '%s'\n", + __func__, __LINE__, temp->GetOrigLine(), temp->GetOrigCol(), 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->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc->SetType(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__, (pc->GetParentType() == CT_OPERATOR) ? "CT_FUNC_DEF" : "CT_FUNC_CALL", + pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc->SetType((pc->GetParentType() == 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->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + + if ( prev != nullptr + && prev->IsNotNullChunk()) + { + 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->GetOrigLine(), prev->GetOrigCol(), get_token_name(prev->GetType())); + } + else + { + prev = Chunk::NullChunkPtr; + } + + // Check for C++ function def + if ( pc->Is(CT_FUNC_CLASS_DEF) + || ( prev->IsNotNullChunk() + && ( prev->Is(CT_INV) + || prev->Is(CT_DC_MEMBER)))) + { + Chunk *destr = Chunk::NullChunkPtr; + + if (prev->Is(CT_INV)) + { + // TODO: do we care that this is the destructor? + prev->SetType(CT_DESTRUCTOR); + pc->SetType(CT_FUNC_CLASS_DEF); + + pc->SetParentType(CT_DESTRUCTOR); + + destr = prev; + // Point to the item previous to the class name + prev = prev->GetPrevNcNnlNpp(); + } + + if (prev->Is(CT_DC_MEMBER)) + { + prev = prev->GetPrevNcNnlNpp(); + + if (prev->IsNotNullChunk()) + { + 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->GetOrigLine(), prev->GetOrigCol(), + get_token_name(prev->GetType())); + 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->GetOrigLine(), prev->GetOrigCol(), + get_token_name(prev->GetType())); + 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->GetOrigLine(), prev->GetOrigCol(), + get_token_name(prev->GetType())); + } + + if ( prev->Is(CT_WORD) + || prev->Is(CT_TYPE)) + { + if (pc->GetStr().equals(prev->GetStr())) + { + 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->GetOrigLine(), pc->GetOrigCol(), + get_token_name(prev->GetType())); + pc->SetType(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->GetOrigLine(), prev->GetOrigCol(), + (destr->IsNotNullChunk()) ? "DE" : "CON", + prev->Text(), get_token_name(prev->GetType())); + + mark_cpp_constructor(pc); + return; + } + // Point to the item previous to the class name + prev = prev->GetPrevNcNnlNpp(); + } + } + } + + /* + * 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 ( pc->Is(CT_FUNC_CALL) + && ( pc->GetLevel() == pc->GetBraceLevel() + || pc->GetLevel() == 1) + && !pc->TestFlags(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->GetOrigLine(), pc->GetOrigCol(), + get_token_name(pc->GetType())); + + if (prev->IsNullChunk()) + { + LOG_FMT(LFCN, "%s(%d): Checking func call: prev is null chunk\n", + __func__, __LINE__); + } + else + { + LOG_FMT(LFCN, "%s(%d): Checking func call: prev->Text() '%s', prev->GetType() is %s\n", + __func__, __LINE__, prev->Text(), get_token_name(prev->GetType())); + } + // 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->IsNotNullChunk()) + { + LOG_FMT(LFCN, "%s(%d): next step with: prev orig line is %zu, orig col is %zu, Text() '%s'\n", + __func__, __LINE__, prev->GetOrigLine(), prev->GetOrigCol(), prev->Text()); + + if (pc->GetParentType() == CT_FIXED) + { + isa_def = true; + } + + if (prev->TestFlags(PCF_IN_PREPROC)) + { + prev = prev->GetPrevNcNnlNpp(); + continue; + } + + // Some code slips an attribute between the type and function + if ( prev->Is(CT_FPAREN_CLOSE) + && prev->GetParentType() == CT_ATTRIBUTE) + { + prev = skip_attribute_prev(prev); + continue; + } + + // skip const(TYPE) + if ( prev->Is(CT_PAREN_CLOSE) + && prev->GetParentType() == CT_D_CAST) + { + LOG_FMT(LFCN, "%s(%d): --> For sure a prototype or definition\n", + __func__, __LINE__); + isa_def = true; + break; + } + + if (prev->GetParentType() == CT_DECLSPEC) // Issue 1289 + { + prev = prev->GetOpeningParen(); + + if (prev->IsNotNullChunk()) + { + prev = prev->GetPrev(); + } + + if (prev->Is(CT_DECLSPEC)) + { + if (prev->IsNotNullChunk()) + { + prev = prev->GetPrev(); + } + } + } + + // 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 + && prev->Is(CT_MEMBER)) + { + isa_def = false; + } + + // get first chunk before: A::B::pc | this.B.pc | this->B->pc + if ( prev->Is(CT_DC_MEMBER) + || prev->Is(CT_MEMBER)) + { + while ( prev->Is(CT_DC_MEMBER) + || prev->Is(CT_MEMBER)) + { + prev = prev->GetPrevNcNnlNpp(); + + if ( prev->IsNullChunk() + || ( prev->IsNot(CT_WORD) + && prev->IsNot(CT_TYPE) + && prev->IsNot(CT_THIS))) + { + LOG_FMT(LFCN, "%s(%d): --? skipped MEMBER and landed on %s\n", + __func__, __LINE__, (prev->IsNullChunk()) ? "<null chunk>" : get_token_name(prev->GetType())); + 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 = prev->GetPrevNcNnlNpp(); + + if (prev->IsNullChunk()) + { + LOG_FMT(LFCN, "%s(%d): prev is null chunk\n", + __func__, __LINE__); + } + else + { + LOG_FMT(LFCN, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s'\n", + __func__, __LINE__, prev->GetOrigLine(), prev->GetOrigCol(), prev->Text()); + } + } + + if (prev->IsNullChunk()) + { + break; + } + } + + // If we are on a TYPE or WORD, then this could be a proto or def + if ( prev->Is(CT_TYPE) + || prev->Is(CT_WORD)) + { + if (!hit_star) + { + LOG_FMT(LFCN, "%s(%d): --> For sure a prototype or definition\n", + __func__, __LINE__); + isa_def = true; + break; + } + Chunk *prev_prev = prev->GetPrevNcNnlNpp(); + + if (!prev_prev->Is(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->GetOrigLine(), prev->GetOrigCol(), + get_token_name(prev->GetType()), get_token_name(prev->GetParentType())); + log_pcf_flags(LFCN, pc->GetFlags()); + isa_def = true; + } + } + + if (prev->IsPointerOperator()) + { + hit_star = true; + } + + if ( prev->IsNot(CT_OPERATOR) + && prev->IsNot(CT_TSQUARE) + && prev->IsNot(CT_ANGLE_CLOSE) + && prev->IsNot(CT_QUALIFIER) + && prev->IsNot(CT_TYPE) + && prev->IsNot(CT_WORD) + && !prev->IsPointerOperator()) + { + 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->GetOrigLine(), prev->GetOrigCol(), get_token_name(prev->GetType())); + + // certain tokens are unlikely to precede a prototype or definition + if ( prev->Is(CT_ARITH) + || prev->Is(CT_SHIFT) + || prev->Is(CT_ASSIGN) + || prev->Is(CT_COMMA) + || ( prev->Is(CT_STRING) + && prev->GetParentType() != CT_EXTERN) // fixes issue 1259 + || prev->Is(CT_STRING_MULTI) + || prev->Is(CT_NUMBER) + || prev->Is(CT_NUMBER_FP) + || prev->Is(CT_FPAREN_OPEN)) // issue #1464 + { + isa_def = false; + } + break; + } + + // Skip over template and attribute stuff + if (prev->Is(CT_ANGLE_CLOSE)) + { + prev = skip_template_prev(prev); + } + else + { + prev = prev->GetPrevNcNnlNpp(); + } + } + //LOG_FMT(LFCN, " -- stopped on %s [%s]\n", + // prev->Text(), get_token_name(prev->GetType())); + + // Fixes issue #1634 + if (prev->IsParenClose()) + { + Chunk *preproc = prev->GetNextNcNnl(); + + if (preproc->Is(CT_PREPROC)) + { + size_t pp_level = preproc->GetPpLevel(); + + if (preproc->GetNextNcNnl()->Is(CT_PP_ELSE)) + { + do + { + preproc = preproc->GetPrevNcNnlNi(); // Issue #2279 + + if (preproc->Is(CT_PP_IF)) + { + preproc = preproc->GetPrevNcNnlNi(); // Issue #2279 + + if (preproc->GetPpLevel() == pp_level) + { + prev = preproc->GetPrevNcNnlNpp(); + break; + } + } + } while (preproc->IsNotNullChunk()); + } + } + } + + if ( isa_def + && prev != nullptr + && prev->IsNotNullChunk() + && ( ( prev->IsParenClose() + && prev->GetParentType() != CT_D_CAST + && prev->GetParentType() != CT_MACRO_OPEN // Issue #2726 + && prev->GetParentType() != CT_MACRO_CLOSE) + || prev->Is(CT_ASSIGN) + || prev->Is(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->GetType())); + isa_def = false; + } + + // Fixes issue #1266, identification of a tuple return type in CS. + if ( !isa_def + && prev->Is(CT_PAREN_CLOSE) + && prev->GetNextNcNnl() == pc) + { + tmp = prev->GetOpeningParen(); + + while ( tmp->IsNotNullChunk() // Issue #2315 + && tmp != prev) + { + if ( tmp->Is(CT_COMMA) + && tmp->GetLevel() == prev->GetLevel() + 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->GetType())); + isa_def = true; + break; + } + tmp = tmp->GetNextNcNnl(); + } + } + + 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->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType())); + 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->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc->SetType(CT_FUNC_DEF); + + if ( prev == nullptr + || prev->IsNullChunk()) + { + prev = Chunk::GetHead(); + } + + for (tmp = prev; tmp->IsNotNullChunk() && tmp != pc; tmp = tmp->GetNextNcNnlNpp()) + { + LOG_FMT(LFCN, "%s(%d): Text() is '%s', type is %s\n", + __func__, __LINE__, tmp->Text(), get_token_name(tmp->GetType())); + make_type(tmp); + } + } + } + + if (pc->IsNot(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->GetType()), + pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + + tmp = flag_parens(next, PCF_IN_FCN_CALL, CT_FPAREN_OPEN, CT_FUNC_CALL, false); + + if ( tmp != nullptr + && tmp->Is(CT_BRACE_OPEN) + && tmp->GetParentType() != CT_DOUBLE_BRACE) + { + set_paren_parent(tmp, pc->GetType()); + } + 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->GetNextNcNnl(); + + while (tmp->IsNotNullChunk()) + { + // Only care about brace or semicolon on the same level + if (tmp->GetLevel() < pc->GetLevel()) + { + // No semicolon - guess that it is a prototype + pc->ResetFlagBits(PCF_VAR_1ST_DEF); + pc->SetType(CT_FUNC_PROTO); + break; + } + else if (tmp->GetLevel() == pc->GetLevel()) + { + if (tmp->Is(CT_BRACE_OPEN)) + { + // its a function def for sure + break; + } + else if (tmp->IsSemicolon()) + { + // Set the parent for the semicolon for later + semi = tmp; + pc->ResetFlagBits(PCF_VAR_1ST_DEF); + pc->SetType(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->GetOrigLine(), pc->GetOrigCol()); + break; + } + else if (pc->Is(CT_COMMA)) + { + pc->SetType(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->GetOrigLine(), pc->GetOrigCol()); + break; + } + } + tmp = tmp->GetNextNcNnl(); + } + + /* + * 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) + && pc->Is(CT_FUNC_PROTO) + && pc->GetParentType() != 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->GetType()), + get_token_name(paren_close->GetType())); + + /* + * Check the token at the start of the statement. If it's 'extern', we + * definitely have a function prototype. + */ + tmp = pc; + + while ( tmp->IsNotNullChunk() + && !tmp->TestFlags(PCF_STMT_START)) + { + tmp = tmp->GetPrevNcNnlNi(); // Issue #2279 + } + const bool is_extern = ( tmp->IsNotNullChunk() + && tmp->GetStr().equals("extern")); + + /* + * Scan the parameters looking for: + * - constant strings + * - numbers + * - non-type fields + * - function calls + */ + Chunk *ref = paren_open->GetNextNcNnl(); + Chunk *tmp2; + bool is_param = true; + tmp = ref; + + while (tmp != paren_close) + { + tmp2 = tmp->GetNextNcNnl(); + + if ( tmp->Is(CT_COMMA) + && (tmp->GetLevel() == (paren_open->GetLevel() + 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) + { + pc->SetType(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->GetOrigLine(), pc->GetOrigCol()); + } + else if (pc->GetBraceLevel() > 0) + { + Chunk *br_open = pc->GetPrevType(CT_BRACE_OPEN, pc->GetBraceLevel() - 1); + + if ( br_open->IsNotNullChunk() + && br_open->GetParentType() != CT_EXTERN + && br_open->GetParentType() != CT_NAMESPACE) + { + // Do a check to see if the level is right + prev = pc->GetPrevNcNnlNi(); // Issue #2279 + + if ( !prev->IsString("*") + && !prev->IsString("&")) + { + Chunk *p_op = pc->GetPrevType(CT_BRACE_OPEN, pc->GetBraceLevel() - 1); + + if ( p_op->IsNotNullChunk() + && p_op->GetParentType() != CT_CLASS + && p_op->GetParentType() != CT_STRUCT + && p_op->GetParentType() != CT_NAMESPACE) + { + pc->SetType(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->GetOrigLine(), pc->GetOrigCol()); + } + } + } + } + } + + if ( semi != nullptr + && semi->IsNotNullChunk()) + { + semi->SetParentType(pc->GetType()); + } + + // Issue # 1403, 2152 + if (paren_open->GetPrev()->Is(CT_FUNC_CTOR_VAR)) + { + flag_parens(paren_open, PCF_IN_FCN_CTOR, CT_FPAREN_OPEN, pc->GetType(), false); + } + else + { + flag_parens(paren_open, PCF_IN_FCN_DEF, CT_FPAREN_OPEN, pc->GetType(), false); + } + //flag_parens(paren_open, PCF_IN_FCN_DEF, CT_FPAREN_OPEN, pc->GetType(), true); + + if (pc->Is(CT_FUNC_CTOR_VAR)) + { + pc->SetFlagBits(PCF_VAR_1ST_DEF); + return; + } + + if (next->Is(CT_TSQUARE)) + { + next = next->GetNextNcNnl(); + + if (next->IsNullChunk()) + { + return; + } + } + // Mark parameters and return type + fix_fcn_def_params(next); + mark_function_return_type(pc, pc->GetPrevNcNnlNi(), pc->GetType()); // Issue #2279 + + /* mark C# where chunk */ + if ( language_is_set(LANG_CS) + && ( (pc->Is(CT_FUNC_DEF)) + || (pc->Is(CT_FUNC_PROTO)))) + { + tmp = paren_close->GetNextNcNnl(); + T_PcfFlags in_where_spec_flags = PCF_NONE; + + while ( tmp->IsNotNullChunk() + && tmp->IsNot(CT_BRACE_OPEN) + && tmp->IsNot(CT_SEMICOLON)) + { + mark_where_chunk(tmp, pc->GetType(), tmp->GetFlags() | in_where_spec_flags); + in_where_spec_flags = tmp->GetFlags() & PCF_IN_WHERE_SPEC; + + tmp = tmp->GetNextNcNnl(); + } + } + + // Find the brace pair and set the parent + if (pc->Is(CT_FUNC_DEF)) + { + tmp = paren_close->GetNextNcNnl(); + + while ( tmp->IsNotNullChunk() + && tmp->IsNot(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->GetOrigLine(), tmp->GetOrigCol(), tmp->Text()); + tmp->SetParentType(CT_FUNC_DEF); + + if (!tmp->IsSemicolon()) + { + tmp->SetFlagBits(PCF_OLD_FCN_PARAMS); + } + tmp = tmp->GetNextNcNnl(); + } + + if (tmp->Is(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->GetOrigLine(), tmp->GetOrigCol(), tmp->Text()); + tmp->SetParentType(CT_FUNC_DEF); + tmp = tmp->GetClosingParen(); + + if (tmp->IsNotNullChunk()) + { + 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->GetOrigLine(), tmp->GetOrigCol(), tmp->Text()); + tmp->SetParentType(CT_FUNC_DEF); + } + } + } +} // mark_function + + +bool mark_function_type(Chunk *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->GetType()), pc->Text(), + pc->GetOrigLine(), pc->GetOrigCol()); + + size_t star_count = 0; + size_t word_count = 0; + Chunk *ptrcnk = nullptr; + Chunk *tmp; + Chunk *apo; + Chunk *apc; + Chunk *aft; + bool anon = false; + E_Token pt, ptp; + + // Scan backwards across the name, which can only be a word and single star + Chunk *varcnk = pc->GetPrevNcNnlNi(); // Issue #2279 + + varcnk = varcnk->GetPrevNbsb(); + + if ( varcnk->IsNotNullChunk() + && !varcnk->IsWord()) + { + if ( language_is_set(LANG_OC) + && varcnk->IsString("^") + && varcnk->GetPrevNcNnlNi()->IsParenOpen()) // 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->GetType()), + varcnk->GetOrigLine(), varcnk->GetOrigCol()); + goto nogo_exit; + } + } + apo = pc->GetNextNcNnl(); + + if (apo->IsNullChunk()) + { + return(false); + } + apc = apo->GetClosingParen(); + + if ( apc->IsNotNullChunk() + && ( !apo->IsParenOpen() + || ((apc = apo->GetClosingParen())->IsNullChunk()))) + { + LOG_FMT(LFTYPE, "%s(%d): not followed by parens\n", __func__, __LINE__); + goto nogo_exit; + } + aft = apc->GetNextNcNnl(); + + if (aft->Is(CT_BRACE_OPEN)) + { + pt = CT_FUNC_DEF; + } + else if ( aft->Is(CT_SEMICOLON) + || aft->Is(CT_ASSIGN)) + { + pt = CT_FUNC_PROTO; + } + else + { + LOG_FMT(LFTYPE, "%s(%d): not followed by '{' or ';'\n", __func__, __LINE__); + goto nogo_exit; + } + ptp = pc->TestFlags(PCF_IN_TYPEDEF) ? CT_FUNC_TYPE : CT_FUNC_VAR; + + tmp = pc; + + while ((tmp = tmp->GetPrevNcNnlNi())->IsNotNullChunk()) // Issue #2279 + { + tmp = tmp->GetPrevNbsb(); + + LOG_FMT(LFTYPE, " -- type is %s, %s on orig line %zu, orig col is %zu", + get_token_name(tmp->GetType()), tmp->Text(), + tmp->GetOrigLine(), tmp->GetOrigCol()); + + if ( tmp->IsStar() + || tmp->Is(CT_PTR_TYPE) + || tmp->Is(CT_CARET)) + { + star_count++; + ptrcnk = tmp; + LOG_FMT(LFTYPE, " -- PTR_TYPE\n"); + } + else if ( tmp->IsWord() + || tmp->Is(CT_WORD) + || tmp->Is(CT_TYPE)) + { + word_count++; + LOG_FMT(LFTYPE, " -- TYPE(%s)\n", tmp->Text()); + } + else if (tmp->Is(CT_DC_MEMBER)) + { + word_count = 0; + LOG_FMT(LFTYPE, " -- :: reset word_count\n"); + } + else if (tmp->IsString("(")) + { + 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->GetType()), tmp->Text(), + tmp->GetOrigLine(), tmp->GetOrigCol()); + goto nogo_exit; + } + } + + // Fixes #issue 1577 + // Allow word count 2 in case 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(tmp->GetPrevNcNnlNi())) // Issue #2279 + { + goto nogo_exit; + } + + if (ptrcnk) + { + ptrcnk->SetType(CT_PTR_TYPE); + } + + if (!anon) + { + if (pc->TestFlags(PCF_IN_TYPEDEF)) + { + varcnk->SetType(CT_FUNC_TYPE); // Issue #3402 + } + else + { + varcnk->SetType(CT_FUNC_VAR); + varcnk->SetFlagBits(PCF_VAR_1ST_DEF); + } + } + pc->SetType(CT_TPAREN_CLOSE); + pc->SetParentType(ptp); + + apo->SetType(CT_FPAREN_OPEN); + apo->SetParentType(pt); + apc->SetType(CT_FPAREN_CLOSE); + apc->SetParentType(pt); + fix_fcn_def_params(apo); + + if (aft->IsSemicolon()) + { + aft->SetParentType(aft->TestFlags(PCF_IN_TYPEDEF) ? CT_TYPEDEF : CT_FUNC_VAR); + } + else if (aft->Is(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 = tmp->GetPrevNcNnlNi())->IsNotNullChunk()) // Issue #2279 + { + LOG_FMT(LFTYPE, " ++ type is %s, Text() '%s', on orig line %zu, orig col %zu\n", + get_token_name(tmp->GetType()), tmp->Text(), + tmp->GetOrigLine(), tmp->GetOrigCol()); + + if (*tmp->GetStr().c_str() == '(') + { + if (!pc->TestFlags(PCF_IN_TYPEDEF)) + { + tmp->SetFlagBits(PCF_VAR_1ST_DEF); + } + tmp->SetType(CT_TPAREN_OPEN); + tmp->SetParentType(ptp); + + tmp = tmp->GetPrevNcNnlNi(); // Issue #2279 + + if ( tmp->Is(CT_FUNCTION) + || tmp->Is(CT_FUNC_CALL) + || tmp->Is(CT_FUNC_CALL_USER) + || tmp->Is(CT_FUNC_DEF) + || tmp->Is(CT_FUNC_PROTO)) + { + tmp->SetType(CT_TYPE); + tmp->ResetFlagBits(PCF_VAR_1ST_DEF); + } + mark_function_return_type(varcnk, tmp, ptp); + break; + } + } + return(true); + +nogo_exit: + tmp = pc->GetNextNcNnl(); + + if (tmp->IsParenOpen()) + { + LOG_FMT(LFTYPE, "%s(%d): setting FUNC_CALL on orig line is %zu, orig col is %zu\n", + __func__, __LINE__, tmp->GetOrigLine(), tmp->GetOrigCol()); + flag_parens(tmp, PCF_NONE, CT_FPAREN_OPEN, CT_FUNC_CALL, false); + } + return(false); +} // mark_function_type + + +void mark_lvalue(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + if (pc->TestFlags(PCF_IN_PREPROC)) + { + return; + } + + for (Chunk *prev = pc->GetPrevNcNnlNi(); // Issue #2279 + prev->IsNotNullChunk(); + prev = prev->GetPrevNcNnlNi()) // Issue #2279 + { + if ( prev->GetLevel() < pc->GetLevel() + || prev->Is(CT_ACCESS_COLON) + || prev->Is(CT_ASSIGN) + || prev->Is(CT_BOOL) + || prev->Is(CT_COMMA) + || prev->IsCppInheritanceAccessSpecifier() + || prev->IsSemicolon() + || prev->IsString("(") + || prev->IsString("{") + || prev->IsString("[") + || prev->TestFlags(PCF_IN_PREPROC) + || prev->GetParentType() == CT_NAMESPACE + || prev->GetParentType() == CT_TEMPLATE) + { + break; + } + prev->SetFlagBits(PCF_LVALUE); + + if ( prev->GetLevel() == pc->GetLevel() + && prev->IsString("&")) + { + make_type(prev); + } + } +} // mark_lvalue + + +void mark_struct_union_body(Chunk *start) +{ + LOG_FUNC_ENTRY(); + Chunk *pc = start; + + while ( pc->IsNotNullChunk() + && pc->GetLevel() >= start->GetLevel() + && !( pc->GetLevel() == start->GetLevel() + && pc->Is(CT_BRACE_CLOSE))) + { + if ( pc->Is(CT_BRACE_OPEN) + || pc->Is(CT_BRACE_CLOSE) + || pc->Is(CT_SEMICOLON)) + { + pc = pc->GetNextNcNnl(); + + if (pc->IsNullChunk()) + { + break; + } + } + + if (pc->Is(CT_ALIGN)) + { + pc = skip_align(pc); // "align(x)" or "align(x):" + + if (pc->IsNullChunk()) + { + break; + } + } + else if (pc->Is(CT_AMP)) + { + pc = skip_expression(pc); + } + else + { + pc = fix_variable_definition(pc); + + if (pc->IsNullChunk()) + { + break; + } + } + } +} // mark_struct_union_body + + +void mark_template_func(Chunk *pc, Chunk *pc_next) +{ + LOG_FUNC_ENTRY(); + + // We know angle_close must be there... + Chunk *angle_close = pc_next->GetNextType(CT_ANGLE_CLOSE, pc->GetLevel()); + Chunk *after = angle_close->GetNextNcNnl(); + + if (after->IsNotNullChunk()) + { + if (after->IsString("(")) + { + if (angle_close->TestFlags(PCF_IN_FCN_CALL)) + { + LOG_FMT(LTEMPFUNC, "%s(%d): marking '%s' in line %zu as a FUNC_CALL\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine()); + 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->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc->SetType(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->GetOrigLine()); + // 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->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + pc->SetType(CT_FUNC_CALL); + mark_function(pc); + } + } + else if (after->Is(CT_WORD)) + { + // its a type! + pc->SetType(CT_TYPE); + pc->SetFlagBits(PCF_VAR_TYPE); + after->SetFlagBits(PCF_VAR_DEF); + } + } +} // mark_template_func + + +Chunk *mark_variable_definition(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + if (start == nullptr) + { + return(nullptr); + } + Chunk *pc = start; + T_PcfFlags 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->GetOrigLine(), pc->GetOrigCol(), pc->Text(), + get_token_name(pc->GetType())); + + // Issue #596 + bool bit_field_colon_is_present = false; + + while (go_on(pc, start)) + { + if ( pc->Is(CT_WORD) + || pc->Is(CT_FUNC_CTOR_VAR)) + { + auto const orig_flags = pc->GetFlags(); + + if (!pc->TestFlags(PCF_IN_ENUM)) + { + pc->SetFlagBits(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->GetOrigLine(), pc->GetOrigCol(), 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->GetOrigLine(), pc->Text(), + get_token_name(pc->GetType()), pc->GetOrigCol(), + pcf_flags_str(orig_flags).c_str(), + pcf_flags_str(pc->GetFlags()).c_str()); + } + else if ( !bit_field_colon_is_present // Issue #2689 + && ( pc->IsStar() + || pc->IsMsRef())) + { + pc->SetType(CT_PTR_TYPE); + } + else if (pc->IsAddress()) + { + pc->SetType(CT_BYREF); + } + else if ( pc->Is(CT_SQUARE_OPEN) + || pc->Is(CT_ASSIGN)) + { + pc = skip_expression(pc); + continue; + } + else if (pc->Is(CT_COLON)) + { + bit_field_colon_is_present = true; // Issue #2689 + } + pc = pc->GetNextNcNnl(); + } + 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 *var_name = cs.Pop_Back(); + + if ( var_name != nullptr + && var_name->GetPrev()->IsNotNullChunk() + && var_name->GetPrev()->GetType() == 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->GetOrigLine(), var_name->GetOrigCol()); + + size_t word_cnt = 0; + Chunk *word_type; + + while ((word_type = cs.Pop_Back()) != nullptr) + { + if ( word_type->Is(CT_WORD) + || word_type->Is(CT_TYPE)) + { + LOG_FMT(LFCNP, "%s(%d): parameter on orig line %zu, orig col %zu: <%s> as TYPE\n", + __func__, __LINE__, var_name->GetOrigLine(), var_name->GetOrigCol(), word_type->Text()); + word_type->SetType(CT_TYPE); + word_type->SetFlagBits(PCF_VAR_TYPE); + } + word_cnt++; + } + + if (var_name->Is(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->GetOrigLine(), var_name->GetOrigCol(), var_name->Text()); + var_name->SetFlagBits(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->GetOrigLine(), var_name->GetOrigCol(), var_name->Text()); + var_name->SetType(CT_TYPE); + var_name->SetFlagBits(PCF_VAR_TYPE); + } + } + } +} // mark_variable_stack + + +T_PcfFlags mark_where_chunk(Chunk *pc, E_Token parent_type, T_PcfFlags 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 (pc->Is(CT_WHERE)) + { + pc->SetType(CT_WHERE_SPEC); + pc->SetParentType(parent_type); + flags |= PCF_IN_WHERE_SPEC; + LOG_FMT(LFTOR, "%s: where-spec on line %zu\n", + __func__, pc->GetOrigLine()); + } + else if (flags.test(PCF_IN_WHERE_SPEC)) + { + if (pc->IsString(":")) + { + pc->SetType(CT_WHERE_COLON); + LOG_FMT(LFTOR, "%s: where-spec colon on line %zu\n", + __func__, pc->GetOrigLine()); + } + else if (pc->IsClassOrStruct()) + { + /* class/struct inside of a where-clause confuses parser for indentation; set it as a word so it looks like the rest */ + pc->SetType(CT_WORD); + } + } + + if (flags.test(PCF_IN_WHERE_SPEC)) + { + pc->SetFlagBits(PCF_IN_WHERE_SPEC); + } + return(flags); +} // mark_where_chunk diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_fix_mark.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_fix_mark.h new file mode 100644 index 00000000..dd6d26fa --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_fix_mark.h @@ -0,0 +1,196 @@ +/** + * @file combine_fix_mark.h + * + * @author Guy Maurel + * @license GPL v2+ + * extract from combine.cpp + */ + +#ifndef COMBINE_FIX_MARK_H_INCLUDED +#define COMBINE_FIX_MARK_H_INCLUDED + +#include "ChunkStack.h" + + +/** + * Checks to see if the current paren is part of a cast. + * We already verified that this doesn't follow function, TYPE, IF, FOR, + * SWITCH, or WHILE and is followed by WORD, TYPE, STRUCT, ENUM, or UNION. + * + * @param start Pointer to the open paren + */ +void fix_casts(Chunk *start); + + +/** + * Simply change any STAR to PTR_TYPE and WORD to TYPE + * + * @param start points to the open paren + */ +void fix_fcn_def_params(Chunk *start); + + +/** + * CT_TYPE_CAST follows this pattern: + * dynamic_cast<...>(...) + * + * Mark everything between the <> as a type and set the paren parent + */ +void fix_type_cast(Chunk *start); + + +/** + * We are on a typedef. + * If the next word is not enum/union/struct, then the last word before the + * next ',' or ';' or '__attribute__' is a type. + * + * typedef [type...] [*] type [, [*]type] ; + * typedef <return type>([*]func)(); + * typedef <return type>([*]func)(params); + * typedef <return type>(__stdcall *func)(); Bug # 633 MS-specific extension + * include the config-file "test/config/MS-calling_conventions.cfg" + * typedef <return type>func(params); + * typedef <enum/struct/union> [type] [*] type [, [*]type] ; + * typedef <enum/struct/union> [type] { ... } [*] type [, [*]type] ; + */ +void fix_typedef(Chunk *start); + + +/** + * We are on the start of a sequence that could be a variable definition + * - FPAREN_OPEN (parent == CT_FOR) + * - BRACE_OPEN + * - SEMICOLON + */ +Chunk *fix_variable_definition(Chunk *start); + + +void mark_cpp_constructor(Chunk *pc); + + +/** + * Mark all chunks belonging to a C++ lambda expression + * + * @param square_open points to a chunk of type CT_SQUARE_OPEN, and the parent type is + * assumed to have already been assigned the value CT_CPP_LAMBDA; + * under this assumption, the function marks all chunks as PCF_IN_LAMBDA + * until the corresponding closing CT_BRACE_CLOSE (with parent type + * CT_CPP_LAMBDA) is encountered + */ +void mark_cpp_lambda(Chunk *square_open); + + +/** + * Marks statement starts in a macro body. + * REVISIT: this may already be done + */ +void mark_define_expressions(); + + +/** + * Just mark every CT_WORD until a semicolon as CT_SQL_WORD. + * Adjust the levels if pc is CT_SQL_BEGIN + */ +void mark_exec_sql(Chunk *pc); + + +/** + * Changes the return type to type and set the parent. + * + * @param pc the last chunk of the return type + * @param parent_type CT_NONE (no change) or the new parent type + */ +void mark_function_return_type(Chunk *fname, Chunk *start, E_Token parent_type); + + +/** + * We are on a function word. we need to: + * - find out if this is a call or prototype or implementation + * - mark return type + * - mark parameter types + * - mark brace pair + * + * REVISIT: + * This whole function is a mess. + * It needs to be reworked to eliminate duplicate logic and determine the + * function type more directly. + * 1. Skip to the close paren and see what is after. + * a. semicolon - function call or function proto + * b. open brace - function call (ie, list_for_each) or function def + * c. open paren - function type or chained function call + * d. qualifier - function def or proto, continue to semicolon or open brace + * 2. Examine the 'parameters' to see if it can be a proto/def + * 3. Examine what is before the function name to see if it is a proto or call + * Constructor/destructor detection should have already been done when the + * 'class' token was encountered (see mark_class_ctor). + */ +void mark_function(Chunk *pc); + + +/** + * Process a function type that is not in a typedef. + * pc points to the first close paren. + * + * void (*func)(params); + * const char * (*func)(params); + * const char * (^func)(params); -- Objective C + * + * @param pc Points to the first closing paren + * + * @return whether a function type was processed + */ +bool mark_function_type(Chunk *pc); + + +/** + * Just hit an assign. Go backwards until we hit an open brace/paren/square or + * semicolon (TODO: other limiter?) and mark as a LValue. + */ +void mark_lvalue(Chunk *pc); + + +/** + * Examines the stuff between braces { }. + * There should only be variable definitions and methods. + * Skip the methods, as they will get handled elsewhere. + */ +void mark_struct_union_body(Chunk *start); + + +/** + * We are on a word followed by a angle open which is part of a template. + * If the angle close is followed by a open paren, then we are on a template + * function def or a template function call: + * Vector2<float>(...) [: ...[, ...]] { ... } + * Or we could be on a variable def if it's followed by a word: + * Renderer<rgb32> rend; + */ +void mark_template_func(Chunk *pc, Chunk *pc_next); + + +/** + * We are on the first word of a variable definition. + * Mark all the variable names with PCF_VAR_1ST and PCF_VAR_DEF as appropriate. + * Also mark any '*' encountered as a CT_PTR_TYPE. + * Skip over []. Go until a ';' is hit. + * + * Example input: + * int a = 3, b, c = 2; ## called with 'a' + * foo_t f = {1, 2, 3}, g = {5, 6, 7}; ## called with 'f' + * struct {...} *a, *b; ## called with 'a' or '*' + * myclass a(4); + */ +Chunk *mark_variable_definition(Chunk *start); + + +void mark_variable_stack(ChunkStack &cs, log_sev_t sev); + + +/** + * TODO: add doc cmt + * + */ +T_PcfFlags mark_where_chunk(Chunk *pc, E_Token parent_type, T_PcfFlags flags); + + +#endif /* COMBINE_FIX_MARK_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_labels.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_labels.cpp new file mode 100644 index 00000000..a49a1fd4 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_labels.cpp @@ -0,0 +1,446 @@ +/** + * @file combine_labels.cpp + * + * @author Guy Maurel + * @license GPL v2+ + * extract from combine.h + */ + +#include "combine_labels.h" + +#include "chunk.h" +#include "cs_top_is_question.h" +#include "unc_tools.h" +#include "uncrustify.h" + + +Chunk *chunk_get_next_local(Chunk *pc, E_Scope scope = E_Scope::ALL) +{ + Chunk *tmp = pc; + + if (tmp == nullptr) + { + tmp = Chunk::NullChunkPtr; + } + + do + { + tmp = tmp->GetNext(scope); + } while ( tmp->IsNotNullChunk() + && ( tmp->IsComment() + || tmp->Is(CT_NOEXCEPT))); + + return(tmp); +} + + +Chunk *chunk_get_prev_local(Chunk *pc, E_Scope scope = E_Scope::ALL) +{ + Chunk *tmp = pc; + + if (tmp == nullptr) + { + tmp = Chunk::NullChunkPtr; + } + + do + { + tmp = tmp->GetPrev(scope); + } while ( tmp->IsNotNullChunk() + && ( tmp->IsCommentOrNewline() + || tmp->Is(CT_NOEXCEPT))); + + return(tmp); +} + + +void combine_labels() +{ + LOG_FUNC_ENTRY(); + bool hit_case = false; + bool hit_class = false; + + cpd.unc_stage = unc_stage_e::COMBINE_LABELS; + + // stack to handle nesting inside of OC messages, which reset the scope + ChunkStack cs; + + Chunk *prev = Chunk::GetHead(); + + if (prev->IsNullChunk()) + { + return; + } + Chunk *cur = prev->GetNextNc(); + + if (cur->IsNullChunk()) + { + return; + } + Chunk *next = cur->GetNextNc(); + + // unlikely that the file will start with a label... + // prev cur next + while ( next != nullptr + && next->IsNotNullChunk()) + { + if (next->Is(CT_NEWLINE)) + { + LOG_FMT(LFCN, "%s(%d): next orig line is %zu, orig col is %zu, <Newline>, nl is %zu\n", + __func__, __LINE__, next->GetOrigLine(), next->GetOrigCol(), next->GetNlCount()); + } + else if (next->Is(CT_VBRACE_OPEN)) + { + LOG_FMT(LFCN, "%s(%d): next orig line is %zu, orig col is %zu, VBRACE_OPEN\n", + __func__, __LINE__, next->GetOrigLine(), next->GetOrigCol()); + } + else if (next->Is(CT_VBRACE_CLOSE)) + { + LOG_FMT(LFCN, "%s(%d): next orig line is %zu, orig col is %zu, VBRACE_CLOSE\n", + __func__, __LINE__, next->GetOrigLine(), next->GetOrigCol()); + } + else + { + LOG_FMT(LFCN, "%s(%d): next orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, next->GetOrigLine(), next->GetOrigCol(), next->Text(), get_token_name(next->GetType())); + } + + if ( !next->TestFlags(PCF_IN_OC_MSG) // filter OC case of [self class] msg send + && ( next->Is(CT_CLASS) + || next->Is(CT_OC_CLASS) + || next->Is(CT_TEMPLATE))) + { + hit_class = true; + } + + if ( next->IsSemicolon() + || next->Is(CT_BRACE_OPEN)) + { + hit_class = false; + } + + if ( prev->Is(CT_SQUARE_OPEN) + && prev->GetParentType() == CT_OC_MSG) + { + cs.Push_Back(prev); + } + else if ( next->Is(CT_SQUARE_CLOSE) + && next->GetParentType() == CT_OC_MSG) + { + // pop until we hit '[' + while (!cs.Empty()) + { + Chunk *t2 = cs.Top()->m_pc; + cs.Pop_Back(); + + if (t2->Is(CT_SQUARE_OPEN)) + { + break; + } + } + } + + if ( next->Is(CT_QUESTION) + && !next->TestFlags(PCF_IN_TEMPLATE)) + { + cs.Push_Back(next); + } + else if (next->Is(CT_CASE)) + { + if (cur->Is(CT_GOTO)) + { + // handle "goto case x;" + next->SetType(CT_QUALIFIER); + } + else + { + hit_case = true; + } + } + else if ( next->Is(CT_COLON) + || ( next->Is(CT_OC_COLON) + && cs_top_is_question(cs, next->GetLevel()))) + { + if (cur->Is(CT_DEFAULT)) + { + cur->SetType(CT_CASE); + hit_case = true; + } + + if ( cs_top_is_question(cs, next->GetLevel()) + && !cur->Is(CT_OC_MSG_NAME) + && next->TestFlags(PCF_IN_CONDITIONAL)) // Issue #3558 + { + //log_pcf_flags(LGUY, next->GetFlags()); + next->SetType(CT_COND_COLON); + cs.Pop_Back(); + } + else if (hit_case) + { + hit_case = false; + next->SetType(CT_CASE_COLON); + Chunk *tmp = next->GetNextNcNnlNpp(); // Issue #2150 + + if (tmp->Is(CT_BRACE_OPEN)) + { + tmp->SetParentType(CT_CASE); + tmp = tmp->GetNextType(CT_BRACE_CLOSE, tmp->GetLevel()); + + if (tmp->IsNotNullChunk()) + { + tmp->SetParentType(CT_CASE); + } + } + + if ( cur->Is(CT_NUMBER) + && prev->Is(CT_ELLIPSIS)) + { + Chunk *pre_elipsis = prev->GetPrevNcNnlNpp(); + + if (pre_elipsis->Is(CT_NUMBER)) + { + prev->SetType(CT_CASE_ELLIPSIS); + } + } + } + else if (cur->TestFlags(PCF_IN_WHERE_SPEC)) + { + /* leave colons in where-constraint clauses alone */ + } + else + { + LOG_FMT(LFCN, "%s(%d): prev->Text() is '%s', orig line is %zu, orig col is %zu\n", + __func__, __LINE__, prev->Text(), prev->GetOrigLine(), prev->GetOrigCol()); + LOG_FMT(LFCN, "%s(%d): cur->Text() is '%s', orig line is %zu, orig col is %zu\n", + __func__, __LINE__, cur->Text(), cur->GetOrigLine(), cur->GetOrigCol()); + LOG_FMT(LFCN, "%s(%d): next->Text() is '%s', orig line is %zu, orig col is %zu\n", + __func__, __LINE__, next->Text(), next->GetOrigLine(), next->GetOrigCol()); + Chunk *nextprev = chunk_get_prev_local(next); // Issue #2279 + + if (nextprev == nullptr) + { + return; + } + + if (language_is_set(LANG_PAWN)) + { + if ( cur->Is(CT_WORD) + || cur->Is(CT_BRACE_CLOSE)) + { + E_Token new_type = CT_TAG; + + Chunk *tmp = next->GetNextNc(); + + if (tmp->IsNullChunk()) + { + return; + } + + if ( prev->IsNewline() + && tmp->IsNewline()) + { + new_type = CT_LABEL; + next->SetType(CT_LABEL_COLON); + } + else + { + next->SetType(CT_TAG_COLON); + } + + if (cur->Is(CT_WORD)) + { + cur->SetType(new_type); + } + } + } + else if (next->TestFlags(PCF_IN_ARRAY_ASSIGN)) + { + next->SetType(CT_D_ARRAY_COLON); + } + else if (next->TestFlags(PCF_IN_FOR)) + { + next->SetType(CT_FOR_COLON); + } + else if (next->TestFlags(PCF_OC_BOXED)) + { + next->SetType(CT_OC_DICT_COLON); + } + else if (cur->Is(CT_WORD)) + { + Chunk *tmp = next->GetNextNc(E_Scope::PREPROC); + + // Issue #1187 + if (tmp->IsNullChunk()) + { + return; + } + LOG_FMT(LFCN, "%s(%d): orig line is %zu, orig col is %zu, tmp '%s': ", + __func__, __LINE__, tmp->GetOrigLine(), tmp->GetOrigCol(), + (tmp->Is(CT_NEWLINE)) ? "<Newline>" : tmp->Text()); + log_pcf_flags(LGUY, tmp->GetFlags()); + + if (next->TestFlags(PCF_IN_FCN_CALL)) + { + // Must be a macro thingy, assume some sort of label + next->SetType(CT_LABEL_COLON); + } + else if ( tmp->IsNullChunk() + || ( tmp->IsNot(CT_NUMBER) + && tmp->IsNot(CT_DECLTYPE) + && tmp->IsNot(CT_SIZEOF) + && tmp->GetParentType() != CT_SIZEOF + && !tmp->GetFlags().test_any(PCF_IN_STRUCT | PCF_IN_CLASS)) + || tmp->Is(CT_NEWLINE)) + { + /* + * the CT_SIZEOF isn't great - test 31720 happens to use a sizeof expr, + * but this really should be able to handle any constant expr + */ + // Fix for #1242 + // For MIDL_INTERFACE classes class name is tokenized as Label. + // Corrected the identification of Label in c style languages. + if ( language_is_set(LANG_C | LANG_CPP | LANG_CS) + && (!language_is_set(LANG_OC))) + { + Chunk *labelPrev = prev; + + if (labelPrev->Is(CT_NEWLINE)) + { + labelPrev = prev->GetPrevNcNnlNi(); // Issue #2279 + } + + if ( labelPrev->IsNotNullChunk() + && labelPrev->IsNot(CT_FPAREN_CLOSE)) + { + cur->SetType(CT_LABEL); + next->SetType(CT_LABEL_COLON); + } + } + else + { + cur->SetType(CT_LABEL); + next->SetType(CT_LABEL_COLON); + } + } + else if (next->GetFlags().test_any(PCF_IN_STRUCT | PCF_IN_CLASS | PCF_IN_TYPEDEF)) + { + next->SetType(CT_BIT_COLON); + + Chunk *nnext = next->GetNext(); + + if (nnext->IsNullChunk()) + { + return; + } + + while ((nnext = nnext->GetNext())->IsNotNullChunk()) + { + if (nnext->Is(CT_SEMICOLON)) + { + break; + } + + if (nnext->Is(CT_COLON)) + { + nnext->SetType(CT_BIT_COLON); + } + } + } + } + else if (nextprev->Is(CT_FPAREN_CLOSE)) + { + LOG_FMT(LFCN, "%s(%d): nextprev->Text() is '%s', orig line is %zu, orig col is %zu, type is %s\n", + __func__, __LINE__, nextprev->Text(), nextprev->GetOrigLine(), nextprev->GetOrigCol(), + get_token_name(nextprev->GetType())); + LOG_FMT(LFCN, "%s(%d): next->Text() is '%s', orig line is %zu, orig col is %zu, type is %s\n", + __func__, __LINE__, next->Text(), next->GetOrigLine(), next->GetOrigCol(), + get_token_name(next->GetType())); + + // Issue #2172 + if (next->GetParentType() == CT_FUNC_DEF) + { + LOG_FMT(LFCN, "%s(%d): it's a construct colon\n", __func__, __LINE__); + // it's a construct colon + next->SetType(CT_CONSTR_COLON); + } + else + { + LOG_FMT(LFCN, "%s(%d): it's a class colon\n", __func__, __LINE__); + // it's a class colon + next->SetType(CT_CLASS_COLON); + } + } + else if (next->GetLevel() > next->GetBraceLevel()) + { + // ignore it, as it is inside a paren + } + else if ( cur->Is(CT_TYPE) + || cur->Is(CT_ENUM) // Issue #2584 + || nextprev->Is(CT_TYPE) + || nextprev->Is(CT_ENUM)) // Issue #2584 + { + next->SetType(CT_BIT_COLON); + } + else if ( cur->Is(CT_ENUM) + || cur->Is(CT_ACCESS) + || cur->Is(CT_QUALIFIER) + || cur->GetParentType() == CT_ALIGN) + { + // ignore it - bit field, align or public/private, etc + } + else if ( cur->Is(CT_ANGLE_CLOSE) + || hit_class) + { + // ignore it - template thingy + } + else if (cur->GetParentType() == CT_SQL_EXEC) + { + // ignore it - SQL variable name + } + else if (next->GetParentType() == CT_ASSERT) + { + // ignore it - Java assert thing + } + else if (next->GetParentType() == CT_STRUCT) + { + // ignore it + } + else + { + Chunk *tmp = next->GetNextNcNnl(); + + //tmp = chunk_get_next_local(next); + if (tmp->IsNotNullChunk()) + { + LOG_FMT(LFCN, "%s(%d): tmp->Text() is '%s', orig line is %zu, orig col is %zu, type is %s\n", + __func__, __LINE__, tmp->Text(), tmp->GetOrigLine(), tmp->GetOrigCol(), + get_token_name(tmp->GetType())); + + if ( tmp->Is(CT_BASE) + || tmp->Is(CT_THIS)) + { + // ignore it, as it is a C# base thingy + } + else if (language_is_set(LANG_CS | LANG_D)) + { + // there should be a better solution for that + } + else + { + LOG_FMT(LWARN, "%s(%d): %s:%zu unexpected colon in col %zu n-parent=%s c-parent=%s l=%zu bl=%zu\n", + __func__, __LINE__, + cpd.filename.c_str(), next->GetOrigLine(), next->GetOrigCol(), + get_token_name(next->GetParentType()), + get_token_name(cur->GetParentType()), + next->GetLevel(), next->GetBraceLevel()); + exit(EX_SOFTWARE); + } + } + } + } + } + prev = cur; + cur = next; + next = chunk_get_next_local(next); + } +} // combine_labels diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_labels.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_labels.h new file mode 100644 index 00000000..5d5954b2 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_labels.h @@ -0,0 +1,21 @@ +/** + * @file combine_labels.h + * + * @author Guy Maurel + * @license GPL v2+ + * extract from combine.h + */ + +#ifndef COMBINE_LABELS_H_INCLUDED +#define COMBINE_LABELS_H_INCLUDED + + +/** + * Examines the whole file and changes CT_COLON to + * CT_Q_COLON, CT_LABEL_COLON, or CT_CASE_COLON. + * It also changes the CT_WORD before CT_LABEL_COLON into CT_LABEL. + */ +void combine_labels(); + + +#endif /* COMBINE_LABELS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_skip.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_skip.cpp new file mode 100644 index 00000000..878941ff --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_skip.cpp @@ -0,0 +1,242 @@ +/** + * @file combine_skip.cpp + * + * @author Guy Maurel + * @license GPL v2+ + * extract from combine.cpp + */ + +#include "combine_skip.h" + +#include "combine_tools.h" + + +Chunk *skip_align(Chunk *start) +{ + Chunk *pc = start; + + if (pc->Is(CT_ALIGN)) + { + pc = pc->GetNextNcNnl(); + + if (pc->Is(CT_PAREN_OPEN)) + { + pc = pc->GetNextType(CT_PAREN_CLOSE, pc->GetLevel()); + + if (pc->IsNotNullChunk()) + { + pc = pc->GetNextNcNnl(); + } + + if (pc->Is(CT_COLON)) + { + pc = pc->GetNextNcNnl(); + } + } + } + return(pc); +} + + +Chunk *skip_expression(Chunk *pc) +{ + return(skip_to_expression_end(pc)->GetNextNcNnl()); +} + + +Chunk *skip_expression_rev(Chunk *pc) +{ + return(skip_to_expression_start(pc)->GetPrevNcNnlNi()); +} + + +static Chunk *skip_to_expression_edge(Chunk *pc, Chunk *(Chunk::*GetNextFn)(E_Scope scope)const) +{ + Chunk *prev = pc; + + if (prev == nullptr) + { + prev = Chunk::NullChunkPtr; + } + + if (prev->IsNotNullChunk()) + { + std::size_t level = prev->GetLevel(); + Chunk *next = prev; + std::size_t template_nest = get_cpp_template_angle_nest_level(prev); + + while ( next->IsNotNullChunk() + && next->GetLevel() >= level) + { + /** + * if we encounter a comma or semicolon at the level of the starting chunk, + * return the current chunk + */ + if ( next->GetLevel() == level + && ( next->Is(CT_COMMA) + || next->IsSemicolon())) + { + break; + } + /** + * check the template nest level; if the current chunk's nest level + * is less than that of the starting chunk, return the current chunk + */ + auto next_template_nest = get_cpp_template_angle_nest_level(next); + + if (template_nest > next_template_nest) + { + break; + } + prev = next; + next = (next->*GetNextFn)(E_Scope::PREPROC); + } + } + return(prev); +} + + +Chunk *skip_to_expression_end(Chunk *pc) +{ + return(skip_to_expression_edge(pc, &Chunk::GetNextNcNnl)); +} + + +Chunk *skip_to_expression_start(Chunk *pc) +{ + return(skip_to_expression_edge(pc, &Chunk::GetPrevNcNnlNi)); +} + + +Chunk *skip_to_next_statement(Chunk *pc) +{ + if (pc == nullptr) + { + pc = Chunk::NullChunkPtr; + } + + while ( pc->IsNotNullChunk() + && !pc->IsSemicolon() + && pc->IsNot(CT_BRACE_OPEN) + && pc->IsNot(CT_BRACE_CLOSE)) + { + pc = pc->GetNextNcNnl(); + } + return(pc); +} + + +Chunk *skip_template_prev(Chunk *ang_close) +{ + if (ang_close->Is(CT_ANGLE_CLOSE)) + { + Chunk *pc = ang_close->GetPrevType(CT_ANGLE_OPEN, ang_close->GetLevel()); + return(pc->GetPrevNcNnlNi()); // Issue #2279 + } + return(ang_close); +} + + +Chunk *skip_tsquare_next(Chunk *ary_def) +{ + if (ary_def == nullptr) + { + return(Chunk::NullChunkPtr); + } + + if ( ary_def->Is(CT_SQUARE_OPEN) + || ary_def->Is(CT_TSQUARE)) + { + return(ary_def->GetNextNisq()); + } + return(ary_def); +} + + +Chunk *skip_attribute(Chunk *attr) +{ + Chunk *pc = attr; + + while (pc->Is(CT_ATTRIBUTE)) + { + pc = pc->GetNextNcNnl(); + + if (pc->Is(CT_FPAREN_OPEN)) + { + pc = pc->GetNextType(CT_FPAREN_CLOSE, pc->GetLevel()); + } + } + return(pc); +} + + +Chunk *skip_attribute_next(Chunk *attr) +{ + Chunk *next = skip_attribute(attr); + + if ( next != attr + && next->Is(CT_FPAREN_CLOSE)) + { + attr = next->GetNextNcNnl(); + } + + if (attr == nullptr) + { + return(Chunk::NullChunkPtr); + } + return(attr); +} + + +Chunk *skip_attribute_prev(Chunk *fp_close) +{ + Chunk *pc = fp_close; + + while (true) + { + if ( pc->Is(CT_FPAREN_CLOSE) + && pc->GetParentType() == CT_ATTRIBUTE) + { + pc = pc->GetPrevType(CT_ATTRIBUTE, pc->GetLevel()); + } + else if (pc->IsNot(CT_ATTRIBUTE)) + { + break; + } + pc = pc->GetPrevNcNnlNi(); // Issue #2279 + + if (pc->IsNullChunk()) // Issue #3356 + { + break; + } + } + return(pc); +} + + +Chunk *skip_declspec(Chunk *pc) +{ + if (pc->Is(CT_DECLSPEC)) + { + pc = pc->GetNextNcNnl(); + + if (pc->Is(CT_PAREN_OPEN)) + { + pc = pc->GetClosingParen(); + } + } + return(pc); +} + + +Chunk *skip_declspec_next(Chunk *pc) +{ + Chunk *next = skip_declspec(pc); + + if ( next != pc + && next->Is(CT_PAREN_CLOSE)) + { + pc = next->GetNextNcNnl(); + } + return(pc); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_skip.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_skip.h new file mode 100644 index 00000000..8bd9134e --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_skip.h @@ -0,0 +1,137 @@ +/** + * @file combine_skip.h + * + * @author Guy Maurel + * @license GPL v2+ + * extract from combine.cpp + */ + +#ifndef COMBINE_SKIP_H_INCLUDED +#define COMBINE_SKIP_H_INCLUDED + +#include "chunk.h" + + +/** + * Skips the D 'align()' statement and the colon, if present. + * align(2) int foo; -- returns 'int' + * align(4): -- returns 'int' + * int bar; + */ +Chunk *skip_align(Chunk *start); + + +/** + * Skips chunks in the forward direction and attempts to find the + * chunk associated with the end of the current expression; returns + * the first chunk to satisfy one of the following: + * 1) Chunk is a comma or semicolon at the level of the starting chunk + * 2) Preceding chunk is at higher template nest level relative to the + * current chunk under test + */ +Chunk *skip_expression(Chunk *pc); + + +/** + * Skips chunks in the reverse direction and attempts to find the + * chunk associated with the start of the current expression; returns + * the first chunk to satisfy one of the following: + * 1) Chunk is a comma or semicolon at the level of the starting chunk + * 2) Preceding chunk is at lower template nest level relative to the + * current chunk under test + */ +Chunk *skip_expression_rev(Chunk *pc); + + +/** + * Skips chunks in the forward direction and attempts to find the + * chunk associated with the end of the current expression; specifically, + * the function returns that which immediately precedes a chunk + * satisfying one of the following: + * 1) Next chunk is a comma or semicolon at the level of the starting chunk + * 2) Preceding chunk is at a higher template nest level relative to the + * subsequent chunk + */ +Chunk *skip_to_expression_end(Chunk *pc); + + +/** + * Skips chunks in the reverse direction and attempts to find the chunk + * associated with the start of the current expression; specifically, + * the function returns that which immediately follows a chunk + * satisfying one of the following: + * 1) Prior chunk is a comma or semicolon at the level of the starting chunk + * 2) Preceding chunk is at a lower template nest level relative to the + * subsequent chunk + */ +Chunk *skip_to_expression_start(Chunk *pc); + + +/** + * Skips over the rest of the template if ang_open is indeed a CT_ANGLE_OPEN. + * Points to the chunk after the CT_ANGLE_CLOSE. + * If the chunk isn't an CT_ANGLE_OPEN, then it is returned. + */ +Chunk *skip_template_next(Chunk *ang_open); + + +/** + * Skips over the rest of the template if ang_close is indeed a CT_ANGLE_CLOSE. + * Points to the chunk before the CT_ANGLE_OPEN + * If the chunk isn't an CT_ANGLE_CLOSE, then it is returned. + */ +Chunk *skip_template_prev(Chunk *ang_close); + + +//! Skips to the start of the next statement. +Chunk *skip_to_next_statement(Chunk *pc); + + +/** + * Skips the rest of the array definitions if ary_def is indeed a + * CT_TSQUARE or CT_SQUARE_OPEN + */ +Chunk *skip_tsquare_next(Chunk *ary_def); + + +/** + * If pc is CT_ATTRIBUTE, then skip it and everything preceding the closing + * paren; return the chunk marked CT_FPAREN_CLOSE + * If the chunk isn't a CT_ATTRIBUTE, then it is returned. + */ +Chunk *skip_attribute(Chunk *attr); + + +/** + * If attr is CT_ATTRIBUTE, then skip it and the parens and return the chunk + * after the CT_FPAREN_CLOSE. + * If the chunk isn't an CT_ATTRIBUTE, then it is returned. + */ +Chunk *skip_attribute_next(Chunk *attr); + + +/** + * If fp_close is a CT_FPAREN_CLOSE with a parent of CT_ATTRIBUTE, then skip it + * and the '__attribute__' thingy and return the chunk before CT_ATTRIBUTE. + * Otherwise return fp_close. + */ +Chunk *skip_attribute_prev(Chunk *fp_close); + + +/** + * If pc is CT_DECLSPEC, then skip it and everything preceding the closing + * paren; return the chunk marked CT_FPAREN_CLOSE + * If the chunk isn't a CT_DECLSPEC, then it is returned. + */ +Chunk *skip_declspec(Chunk *pc); + + +/** + * If pc is CT_DECLSPEC, then skip it and the parens and return the chunk + * after the CT_FPAREN_CLOSE. + * If the chunk isn't a CT_DECLSPEC, then it is returned. + */ +Chunk *skip_declspec_next(Chunk *pc); + + +#endif /* COMBINE_SKIP_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_tools.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_tools.cpp new file mode 100644 index 00000000..7adafe68 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_tools.cpp @@ -0,0 +1,581 @@ +/** + * @file combine_tools.cpp + * + * @author Guy Maurel + * @license GPL v2+ + * extract from combine.cpp + */ + +#include "combine_tools.h" + +#include "unc_ctype.h" +#include "uncrustify.h" + + +bool can_be_full_param(Chunk *start, Chunk *end) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LFPARAM, "%s(%d): start->Text() is '%s', type is %s\n", + __func__, __LINE__, start->Text(), get_token_name(start->GetType())); + LOG_FMT(LFPARAM, "%s(%d): end->Text() is '%s', type is %s\n", + __func__, __LINE__, end->Text(), get_token_name(end->GetType())); + + int word_count = 0; + int type_count = 0; + Chunk *pc = nullptr; + Chunk *first_word = nullptr; + bool first_word_set = false; + + for (pc = start; + pc != nullptr && pc->IsNotNullChunk() && pc != end; + pc = pc->GetNextNcNnl(E_Scope::PREPROC)) + { + LOG_FMT(LFPARAM, "%s(%d): pc->Text() is '%s', type is %s\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType())); + + if ( pc->Is(CT_QUALIFIER) + || pc->Is(CT_STRUCT) + || pc->Is(CT_ENUM) + || pc->Is(CT_UNION) + || pc->Is(CT_TYPENAME)) + { + LOG_FMT(LFPARAM, "%s(%d): <== %s! (yes)\n", + __func__, __LINE__, get_token_name(pc->GetType())); + return(true); + } + + if ( pc->Is(CT_WORD) + || pc->Is(CT_TYPE)) + { + ++word_count; + + if (!first_word_set) + { + first_word = pc; + first_word_set = true; + } + + if (pc->Is(CT_TYPE)) + { + ++type_count; + } + } + else if ( pc->Is(CT_MEMBER) + || pc->Is(CT_DC_MEMBER)) + { + if (word_count > 0) + { + --word_count; + } + } + else if ( pc != start + && pc->IsPointerOperator()) + { + // chunk is OK + } + else if (pc->Is(CT_ASSIGN)) + { + // chunk is OK (default values) + break; + } + else if (pc->Is(CT_ANGLE_OPEN)) + { + LOG_FMT(LFPARAM, "%s(%d): <== template\n", + __func__, __LINE__); + + return(true); + } + else if (pc->Is(CT_ELLIPSIS)) + { + LOG_FMT(LFPARAM, "%s(%d): <== ellipsis\n", + __func__, __LINE__); + + return(true); + } + else if ( word_count == 0 + && pc->Is(CT_PAREN_OPEN)) + { + // Check for old-school func proto param '(type)' + Chunk *tmp1 = pc->GetClosingParen(E_Scope::PREPROC); + + if (tmp1->IsNullChunk()) + { + return(false); + } + Chunk *tmp2 = tmp1->GetNextNcNnl(E_Scope::PREPROC); + + if (tmp2->IsNullChunk()) + { + return(false); + } + + if ( tmp2->Is(CT_COMMA) + || tmp2->IsParenClose()) + { + do + { + pc = pc->GetNextNcNnl(E_Scope::PREPROC); + + if (pc->IsNullChunk()) + { + return(false); + } + LOG_FMT(LFPARAM, "%s(%d): pc->Text() is '%s', type is %s\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType())); + } while (pc != tmp1); + + // reset some vars to allow [] after parens + word_count = 1; + type_count = 1; + } + else + { + LOG_FMT(LFPARAM, "%s(%d): <== '%s' not fcn type!\n", + __func__, __LINE__, get_token_name(pc->GetType())); + return(false); + } + } + else if ( ( word_count == 1 + || (word_count == type_count)) + && pc->Is(CT_PAREN_OPEN)) + { + // Check for func proto param 'void (*name)' or 'void (*name)(params)' or 'void (^name)(params)' + // <name> can be optional + Chunk *tmp1 = pc->GetNextNcNnl(E_Scope::PREPROC); + + if (tmp1->IsNullChunk()) + { + return(false); + } + Chunk *tmp2 = tmp1->GetNextNcNnl(E_Scope::PREPROC); + + if (tmp2->Is(CT_QUALIFIER)) + { + // tmp2 is the "nullable" qualifier in this case: + // void (^nullable name)(params) + // skip the qualifier + tmp2 = tmp2->GetNextNcNnl(E_Scope::PREPROC); + } + + if (tmp2->IsNullChunk()) + { + return(false); + } + Chunk *tmp3 = (tmp2->IsString(")")) ? tmp2 : tmp2->GetNextNcNnl(E_Scope::PREPROC); + + if (tmp3->IsNullChunk()) + { + return(false); + } + + if ( !tmp3->IsString(")") + || !( tmp1->IsString("*") + || tmp1->IsString("^")) // Issue #2656 + || !( tmp2->GetType() == CT_WORD + || tmp2->IsString(")"))) + { + LOG_FMT(LFPARAM, "%s(%d): <== '%s' not fcn type!\n", + __func__, __LINE__, get_token_name(pc->GetType())); + return(false); + } + LOG_FMT(LFPARAM, "%s(%d): <skip fcn type>\n", + __func__, __LINE__); + + tmp1 = tmp3->GetNextNcNnl(E_Scope::PREPROC); + + if (tmp1->IsNullChunk()) + { + return(false); + } + + if (tmp1->IsString("(")) + { + tmp3 = tmp1->GetClosingParen(E_Scope::PREPROC); + } + pc = tmp3; + LOG_FMT(LFPARAM, "%s(%d): pc->Text() is '%s', type is %s\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType())); + + // reset some vars to allow [] after parens + word_count = 1; + type_count = 1; + } + else if (pc->Is(CT_TSQUARE)) + { + // ignore it + } + else if ( word_count == 1 + && pc->Is(CT_SQUARE_OPEN)) + { + // skip over any array stuff + pc = pc->GetClosingParen(E_Scope::PREPROC); + LOG_FMT(LFPARAM, "%s(%d): pc->Text() is '%s', type is %s\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType())); + } + else if ( word_count == 2 + && pc->Is(CT_SQUARE_OPEN)) + { + // Bug #671: is it such as: bool foo[FOO_MAX] + pc = pc->GetClosingParen(E_Scope::PREPROC); + LOG_FMT(LFPARAM, "%s(%d): pc->Text() is '%s', type is %s\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType())); + } + else if ( word_count == 1 + && language_is_set(LANG_CPP) + && pc->IsString("&&")) + { + // ignore possible 'move' operator + } + else + { + LOG_FMT(LFPARAM, "%s(%d): <== type is %s, no way!, type count is %d, word count is %d\n", + __func__, __LINE__, get_token_name(pc->GetType()), type_count, word_count); + return(false); + } + LOG_FMT(LFPARAM, "%s(%d): pc->Text() is '%s', type is %s\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType())); + } + + Chunk *last = pc->GetPrevNcNnlNi(); // Issue #2279 + + LOG_FMT(LFPARAM, "%s(%d): last->Text() is '%s', type is %s\n", + __func__, __LINE__, last->Text(), get_token_name(last->GetType())); + + if (last->IsPointerOperator()) + { + LOG_FMT(LFPARAM, "%s(%d): <== type is %s, sure!\n", + __func__, __LINE__, get_token_name(last->GetType())); + return(true); + } + + if ( word_count < 2 + && type_count < 1 + && start->GetBraceLevel() > 0) + { + LOG_FMT(LFPARAM, "%s(%d): !MVP!\n", + __func__, __LINE__); + // Oh, joy, we are in Most Vexing Parse territory + Chunk *brace = + start->GetPrevType(CT_BRACE_OPEN, start->GetBraceLevel() - 1); + + if (brace->IsNotNullChunk()) + { + LOG_FMT(LFPARAM, "%s(%d): (matching %s brace at orig line %zu, orig col is %zu)", + __func__, __LINE__, + get_token_name(brace->GetParentType()), brace->GetOrigLine(), brace->GetOrigCol()); + } + + if ( brace->IsNotNullChunk() + && ( brace->GetParentType() == CT_CLASS + || brace->GetParentType() == CT_STRUCT)) + { + // A Most Vexing Parse variable declaration cannot occur in the body + // of a struct/class, so we probably have a function prototype + LOG_FMT(LFPARAM, "%s(%d): <== type is %s, Likely!\n", + __func__, __LINE__, (pc == nullptr ? "nullptr" : get_token_name(pc->GetType()))); + return(true); + } + } + LOG_FMT(LFPARAM, "%s(%d): pc->Text() is '%s', word_count is %d, type_count is %d\n", + __func__, __LINE__, pc->Text(), word_count, type_count); + + if ( first_word != nullptr + && first_word->IsNotNullChunk()) + { + LOG_FMT(LFPARAM, "%s(%d): first_word->Text() is '%s'\n", + __func__, __LINE__, first_word->Text()); + } + bool ret = ( word_count >= 2 + || ( word_count == 1 + && type_count == 1)); + + LOG_FMT(LFPARAM, "%s(%d): ret is %s\n", + __func__, __LINE__, ret ? "TRUE" : "FALSE"); + + LOG_FMT(LFPARAM, "%s(%d): pc->Text() is '%s', ", + __func__, __LINE__, pc->Text()); + LOG_FMT(LFPARAM, "<== type is %s, ", + (pc == nullptr ? "nullptr" : get_token_name(pc->GetType()))); + + if (ret) + { + LOG_FMT(LFPARAM, "Yup!\n"); + } + else + { + LOG_FMT(LFPARAM, "Unlikely!\n"); + } + return(ret); +} // can_be_full_param + + +bool chunk_ends_type(Chunk *start) +{ + LOG_FUNC_ENTRY(); + Chunk *pc = start; + bool ret = false; + size_t cnt = 0; + bool last_expr = false; + bool last_lval = false; + + bool a = pc->TestFlags(PCF_IN_FCN_CTOR); + + if (a) + { + return(false); + } + + for ( ; pc->IsNotNullChunk(); pc = pc->GetPrevNcNnlNi()) // Issue #2279 + { + LOG_FMT(LFTYPE, "%s(%d): type is %s, Text() '%s', orig line %zu, orig col %zu\n ", + __func__, __LINE__, get_token_name(pc->GetType()), pc->Text(), + pc->GetOrigLine(), pc->GetOrigCol()); + log_pcf_flags(LFTYPE, pc->GetFlags()); + + if ( pc->Is(CT_WORD) + || pc->Is(CT_TYPE) + || pc->Is(CT_PTR_TYPE) + || pc->Is(CT_STAR) + || pc->Is(CT_STRUCT) + || pc->Is(CT_DC_MEMBER) + || pc->Is(CT_PP) + || pc->Is(CT_QUALIFIER) + || ( language_is_set(LANG_CPP | LANG_OC) // Issue #2727 + && pc->GetParentType() == CT_TEMPLATE + && ( pc->Is(CT_ANGLE_OPEN) + || pc->Is(CT_ANGLE_CLOSE))) + || ( language_is_set(LANG_CS | LANG_VALA) + && (pc->Is(CT_MEMBER)))) + { + cnt++; + last_expr = pc->TestFlags(PCF_EXPR_START) + && !pc->TestFlags(PCF_IN_FCN_CALL); + last_lval = pc->TestFlags(PCF_LVALUE); + continue; + } + /* If a comma is encountered within a template, it must be + * considered within the context of its immediate parent + * template (i.e. argument list nest level) + */ + + if ( ( pc->IsSemicolon() + && !pc->TestFlags(PCF_IN_FOR)) + || pc->Is(CT_TYPEDEF) + || pc->Is(CT_BRACE_OPEN) + || pc->IsBraceClose() + || pc->Is(CT_FPAREN_CLOSE) + || pc->IsOCForinOpenParen() + || pc->Is(CT_MACRO) + || pc->Is(CT_PP_IF) + || pc->Is(CT_PP_ELSE) + || pc->Is(CT_PP_ENDIF) + || pc->GetParentType() == CT_PP_INCLUDE // Issue #3233 + || ( ( pc->Is(CT_COMMA) + && !pc->TestFlags(PCF_IN_FCN_CALL) + && get_cpp_template_angle_nest_level(start) == + get_cpp_template_angle_nest_level(pc)) + && last_expr) + || ( pc->Is(CT_SPAREN_OPEN) + && last_lval)) + { + ret = cnt > 0; + } + break; + } + + if (pc->IsNullChunk()) + { + // first token + ret = true; + } + LOG_FMT(LFTYPE, "%s(%d): first token verdict: %s\n", + __func__, __LINE__, ret ? "yes" : "no"); + + return(ret); +} // chunk_ends_type + + +bool chunkstack_match(ChunkStack &cs, Chunk *pc) +{ + for (size_t idx = 0; idx < cs.Len(); idx++) + { + Chunk *tmp = cs.GetChunk(idx); + + if (pc->GetStr().equals(tmp->GetStr())) + { + return(true); + } + } + + return(false); +} // chunkstack_match + + +void flag_series(Chunk *start, Chunk *end, T_PcfFlags set_flags, T_PcfFlags clr_flags, E_Scope nav) +{ + LOG_FUNC_ENTRY(); + + while ( start != nullptr + && start->IsNotNullChunk() + && start != end) + { + start->UpdateFlagBits(clr_flags, set_flags); + log_pcf_flags(LGUY, start->GetFlags()); + + start = start->GetNext(nav); + + if (start->IsNullChunk()) + { + return; + } + } + + if ( end != nullptr + && end->IsNotNullChunk()) + { + end->UpdateFlagBits(clr_flags, set_flags); + log_pcf_flags(LGUY, end->GetFlags()); + } +} // flag_series + + +size_t get_cpp_template_angle_nest_level(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + int nestLevel = 0; + + if (pc == nullptr) + { + pc = Chunk::NullChunkPtr; + } + + while ( pc->IsNotNullChunk() + && pc->TestFlags(PCF_IN_TEMPLATE)) + { + if ( pc->Is(CT_ANGLE_CLOSE) + && pc->GetParentType() == CT_TEMPLATE) + { + --nestLevel; + } + else if ( pc->Is(CT_ANGLE_OPEN) + && pc->GetParentType() == CT_TEMPLATE) + { + ++nestLevel; + } + pc = pc->GetPrevNcNnlNi(); + } + return(nestLevel <= 0 ? 0 : size_t(nestLevel)); +} + + +Chunk *get_d_template_types(ChunkStack &cs, Chunk *open_paren) +{ + LOG_FUNC_ENTRY(); + Chunk *tmp = open_paren->GetNextNcNnl(); + bool maybe_type = true; + + while ( tmp->IsNullChunk() + && tmp->GetLevel() > open_paren->GetLevel()) + { + if ( tmp->Is(CT_TYPE) + || tmp->Is(CT_WORD)) + { + if (maybe_type) + { + make_type(tmp); + cs.Push_Back(tmp); + } + maybe_type = false; + } + else if (tmp->Is(CT_COMMA)) + { + maybe_type = true; + } + tmp = tmp->GetNextNcNnl(); + } + return(tmp); +} // get_d_template_types + + +bool go_on(Chunk *pc, Chunk *start) +{ + if ( pc == nullptr + || pc->IsNullChunk() + || pc->GetLevel() != start->GetLevel()) + { + return(false); + } + + if (pc->TestFlags(PCF_IN_FOR)) + { + return( (!pc->IsSemicolon()) + && (!(pc->Is(CT_COLON)))); + } + return(!pc->IsSemicolon()); +} // go_on + + +bool is_ucase_str(const char *str, size_t len) +{ + while (len-- > 0) + { + if (unc_toupper(*str) != *str) + { + return(false); + } + str++; + } + return(true); +} // is_ucase_str + + +void make_type(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + if ( pc != nullptr + && pc->IsNotNullChunk()) + { + if (pc->Is(CT_WORD)) + { + pc->SetType(CT_TYPE); + } + else if ( ( pc->IsStar() + || pc->IsMsRef() + || pc->IsNullable()) + && pc->GetPrev()->IsTypeDefinition()) // Issue # 2640 + { + pc->SetType(CT_PTR_TYPE); + } + else if ( pc->IsAddress() + && pc->GetPrev()->IsNot(CT_SQUARE_OPEN)) // Issue # 2166 + { + pc->SetType(CT_BYREF); + } + } +} // make_type + + +Chunk *set_paren_parent(Chunk *start, E_Token parent_type) +{ + LOG_FUNC_ENTRY(); + Chunk *end; + + end = start->GetClosingParen(E_Scope::PREPROC); + + if (end->IsNotNullChunk()) + { + LOG_FMT(LFLPAREN, "%s(%d): %zu:%zu '%s' and %zu:%zu '%s' type is %s, parent type is %s", + __func__, __LINE__, start->GetOrigLine(), start->GetOrigCol(), start->Text(), + end->GetOrigLine(), end->GetOrigCol(), end->Text(), + get_token_name(start->GetType()), get_token_name(parent_type)); + log_func_stack_inline(LFLPAREN); + start->SetParentType(parent_type); + end->SetParentType(parent_type); + LOG_FMT(LFLPAREN, "%s(%d):\n", __func__, __LINE__); + return(end->GetNextNcNnl(E_Scope::PREPROC)); + } + LOG_FMT(LFLPAREN, "%s(%d):\n", __func__, __LINE__); + return(nullptr); +} // set_paren_parent diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_tools.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_tools.h new file mode 100644 index 00000000..e18fe92a --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine_tools.h @@ -0,0 +1,85 @@ +/** + * @file combine_tools.h + * + * @author Guy Maurel + * @license GPL v2+ + * extract from combine.cpp + */ + +#ifndef COMBINE_TOOLS_H_INCLUDED +#define COMBINE_TOOLS_H_INCLUDED + +#include "chunk.h" +#include "ChunkStack.h" + +/** + * Checks to see if a series of chunks could be a C++ parameter + * FOO foo(5, &val); + * + * WORD means CT_WORD or CT_TYPE + * + * "WORD WORD" ==> true + * "QUALIFIER ??" ==> true + * "TYPE" ==> true + * "WORD" ==> true + * "WORD.WORD" ==> true + * "WORD::WORD" ==> true + * "WORD * WORD" ==> true + * "WORD & WORD" ==> true + * "NUMBER" ==> false + * "STRING" ==> false + * "OPEN PAREN" ==> false + * + * @param start the first chunk to look at + * @param end the chunk after the last one to look at + */ +bool can_be_full_param(Chunk *start, Chunk *end); + + +//! Scan backwards to see if we might be on a type declaration +bool chunk_ends_type(Chunk *start); + + +bool chunkstack_match(ChunkStack &cs, Chunk *pc); + + +///** +// * Simply change any STAR to PTR_TYPE and WORD to TYPE +// * +// * @param start points to the open paren +// */ +void fix_fcn_def_params(Chunk *pc); + + +void flag_series(Chunk *start, Chunk *end, T_PcfFlags set_flags, T_PcfFlags clr_flags = {}, E_Scope nav = E_Scope::ALL); + + +/* + * Checks whether or not a given chunk has a parent cpp template, + * and if so returns the associated angle bracket nest level + * with respect to the root parent template; returns 0 if + * the chunk is not part of a template parameter list + */ +size_t get_cpp_template_angle_nest_level(Chunk *pc); + + +/** + * Parse off the types in the D template args, adds to cs + * returns the close_paren + */ +Chunk *get_d_template_types(ChunkStack &cs, Chunk *open_paren); + + +//! help function for mark_variable_definition... +bool go_on(Chunk *pc, Chunk *start); + + +bool is_ucase_str(const char *str, size_t len); + + +void make_type(Chunk *pc); + +Chunk *set_paren_parent(Chunk *start, E_Token parent); + + +#endif /* COMBINE_TOOLS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/compat.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/compat.h new file mode 100644 index 00000000..32fce459 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/compat.h @@ -0,0 +1,26 @@ +/** + * @file compat.h + * prototypes for compat_xxx.c + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef COMPAT_H_INCLUDED +#define COMPAT_H_INCLUDED + +#include "uncrustify_types.h" + + +bool unc_getenv(const char *name, std::string &str); + + +bool unc_homedir(std::string &home); + + +/* + * even if we prefer the format %zu, we have to change to %lu + * to be runable under Windows + */ +void convert_log_zu2lu(char *buf); + +#endif /* COMPAT_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/compat_posix.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/compat_posix.cpp new file mode 100644 index 00000000..c77c7a89 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/compat_posix.cpp @@ -0,0 +1,39 @@ +/** + * @file compat_posix.cpp + * Compatibility functions for POSIX + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef WIN32 + +#include "uncrustify_types.h" + + +bool unc_getenv(const char *name, std::string &str) +{ + const char *val = getenv(name); + + if (val != nullptr) + { + str = val; + return(true); + } + return(false); +} + + +bool unc_homedir(std::string &home) +{ + return(unc_getenv("HOME", home)); +} + + +void convert_log_zu2lu(char *fmt) +{ + UNUSED(fmt); + // nothing to do +} + +#endif /* ifndef WIN32 */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/compat_win32.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/compat_win32.cpp new file mode 100644 index 00000000..e1617876 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/compat_win32.cpp @@ -0,0 +1,82 @@ +/** + * @file compat_win32.cpp + * Compatibility functions for win32 + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#if defined (_WIN32) \ + && !defined (__CYGWIN__) + +#include "windows_compat.h" + +#include <cstdio> +#include <string> + + +bool unc_getenv(const char *name, std::string &str) +{ + DWORD len = GetEnvironmentVariableA(name, NULL, 0); + char *buf; + + if (len == 0) + { + if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) + { + return(false); + } + } + buf = (char *)malloc(len); + + if (buf) + { + len = GetEnvironmentVariableA(name, buf, len); + } + buf[len] = 0; + + str = buf; + //printf("%s: name=%s len=%zu value=%s\n", __func__, name, len, str.c_str()); + free(buf); + + return(true); +} + + +bool unc_homedir(std::string &home) +{ + if (unc_getenv("HOME", home)) + { + return(true); + } + + if (unc_getenv("USERPROFILE", home)) + { + return(true); + } + std::string hd, hp; + + if ( unc_getenv("HOMEDRIVE", hd) + && unc_getenv("HOMEPATH", hp)) + { + home = hd + hp; + return(true); + } + return(false); +} + + +void convert_log_zu2lu(char *fmt) +{ + for (size_t i = 0; i < strlen(fmt); i++) + { + if ( (fmt[i] == '%') + && (fmt[i + 1] == 'z') + && (fmt[i + 2] == 'u')) + { + fmt[i + 1] = 'l'; + } + } +} + +#endif /* if defined(_WIN32) && !defined(__CYGWIN__) */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/config.h.in b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/config.h.in new file mode 100644 index 00000000..420de635 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/config.h.in @@ -0,0 +1,97 @@ +// Used by CMake to generate config.h. + +// Define to 1 if you have the <inttypes.h> header file. +#cmakedefine HAVE_INTTYPES_H 1 + +// Define to 1 if you have the <memory.h> header file. +#cmakedefine HAVE_MEMORY_H 1 + +// Define to 1 if you have the `memset' function. +#cmakedefine HAVE_MEMSET 1 + +// Define to 1 if stdbool.h conforms to C99. +#cmakedefine HAVE_STDBOOL_H 1 + +// Define to 1 if you have the <stdint.h> header file. +#cmakedefine HAVE_STDINT_H 1 + +// Define to 1 if you have the <stdlib.h> header file. +#cmakedefine HAVE_STDLIB_H 1 + +// Define to 1 if you have the `strcasecmp' function. +#cmakedefine HAVE_STRCASECMP 1 + +// Define to 1 if you have the `strchr' function. +#cmakedefine HAVE_STRCHR 1 + +// Define to 1 if you have the `strdup' function. +#cmakedefine HAVE_STRDUP 1 + +// Define to 1 if you have the `strerror' function. +#cmakedefine HAVE_STRERROR 1 + +// Define to 1 if you have the <strings.h> header file. +#cmakedefine HAVE_STRINGS_H 1 + +// Define to 1 if you have the <string.h> header file. +#cmakedefine HAVE_STRING_H 1 + +// Define to 1 if you have the `strtol' function. +#cmakedefine HAVE_STRTOL 1 + +// Define to 1 if you have the `strtoul' function. +#cmakedefine HAVE_STRTOUL 1 + +// Define to 1 if you have the <sys/stat.h> header file. +#cmakedefine HAVE_SYS_STAT_H 1 + +// Define to 1 if you have the <sys/types.h> header file. +#cmakedefine HAVE_SYS_TYPES_H 1 + +// Define to 1 if you have the <unistd.h> header file. +#cmakedefine HAVE_UNISTD_H 1 + +// Define to 1 if you have the <utime.h> header file. +#cmakedefine HAVE_UTIME_H 1 + +// Define to 1 if the system has the type `_Bool'. +#cmakedefine HAVE__BOOL 1 + +// Name of package +#cmakedefine PACKAGE "@PACKAGE@" + +// Define to the address where bug reports for this package should be sent. +#cmakedefine PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" + +// Define to the full name of this package. +#cmakedefine PACKAGE_NAME "@PACKAGE_NAME@" + +// Define to the full name and version of this package. +#cmakedefine PACKAGE_STRING "@PACKAGE_STRING@" + +// Define to the one symbol short name of this package. +#cmakedefine PACKAGE_TARNAME "@PACKAGE_TARNAME@" + +// Define to the home page for this package. +#cmakedefine PACKAGE_URL "@PACKAGE_URL@" + +// Define to the version of this package. +#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" + +// Define to 1 if you have the ANSI C header files. +#cmakedefine STDC_HEADERS 1 + +// Version number of package +#cmakedefine VERSION "@VERSION@" + +/* Define to appropriate substitute if compiler doesn't have __func__ */ +/* #undef __func__ */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + * calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/cs_top_is_question.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/cs_top_is_question.cpp new file mode 100644 index 00000000..b9b5b958 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/cs_top_is_question.cpp @@ -0,0 +1,20 @@ +/** + * @file cs_top_is_question.cpp + * + * @author Guy Maurel + * @license GPL v2+ + * extract from combine.cpp + */ + +#include "cs_top_is_question.h" + +#include "chunk.h" + + +bool cs_top_is_question(ChunkStack &cs, size_t level) +{ + Chunk *pc = cs.Empty() ? Chunk::NullChunkPtr : cs.Top()->m_pc; + + return( pc->Is(CT_QUESTION) + && pc->GetLevel() == level); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/cs_top_is_question.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/cs_top_is_question.h new file mode 100644 index 00000000..de6ace3e --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/cs_top_is_question.h @@ -0,0 +1,18 @@ +/** + * @file cs_top_is_question.h + * + * @author Guy Maurel + * @license GPL v2+ + * extract from combine.cpp + */ + +#ifndef CS_TOP_IS_QUESTION_H_INCLUDED +#define CS_TOP_IS_QUESTION_H_INCLUDED + +#include "ChunkStack.h" + + +bool cs_top_is_question(ChunkStack &cs, size_t level); + + +#endif /* CS_TOP_IS_QUESTION_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/detect.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/detect.cpp new file mode 100644 index 00000000..ec718e81 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/detect.cpp @@ -0,0 +1,439 @@ +/** + * @file detect.cpp + * Scans the parsed file and tries to determine options. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "detect.h" + +#include "prototypes.h" + + +using namespace uncrustify; + + +//! Detect spacing options +static void detect_space_options(); + + +class sp_votes +{ +protected: + size_t m_add = 0; + size_t m_remove = 0; + size_t m_force = 0; + Option<iarf_e> &m_option; + +public: + sp_votes(Option<iarf_e> &opt) + : m_option(opt) + {} + + //! Figure out the result of the vote and maybe update *m_av + ~sp_votes(); + + void vote(Chunk *first, Chunk *second); +}; + + +void sp_votes::vote(Chunk *first, Chunk *second) +{ + if ( first == nullptr + || first->IsNewline() + || second == nullptr + || second->IsNewline()) + { + return; + } + int col_dif = second->GetColumn() - (first->GetColumn() + first->Len()); + + if (col_dif == 0) + { + m_remove++; + } + else if (col_dif == 1) + { + m_force++; + } + else + { + m_add++; + } +} + + +//! Figure out the result of the vote and maybe update *m_av +sp_votes::~sp_votes() +{ + // no change if no items were added + if ( m_remove == 0 + && m_add == 0 + && m_force == 0) + { + return; + } + + if (m_remove == 0) + { + m_option = (m_force > m_add) ? IARF_FORCE : IARF_ADD; + } + else if ( m_force == 0 + && m_add == 0) + { + m_option = IARF_REMOVE; + } + else + { + // nothing conclusive. do not alter. + } +} + + +// generates "vote_sp_xxx" variable name from uncrustify option name "UO_xxx" +#define SP_VOTE_VAR(x) sp_votes vote_ ## x(options::x) + + +static void detect_space_options() +{ + SP_VOTE_VAR(sp_arith); + SP_VOTE_VAR(sp_before_assign); + SP_VOTE_VAR(sp_after_assign); + SP_VOTE_VAR(sp_enum_before_assign); + SP_VOTE_VAR(sp_enum_after_assign); + SP_VOTE_VAR(sp_bool); + SP_VOTE_VAR(sp_compare); + SP_VOTE_VAR(sp_inside_paren); + SP_VOTE_VAR(sp_paren_paren); + SP_VOTE_VAR(sp_paren_brace); + SP_VOTE_VAR(sp_before_ptr_star); + SP_VOTE_VAR(sp_before_unnamed_ptr_star); + SP_VOTE_VAR(sp_between_ptr_star); + SP_VOTE_VAR(sp_after_ptr_star); + SP_VOTE_VAR(sp_after_byref); + SP_VOTE_VAR(sp_before_byref); + SP_VOTE_VAR(sp_before_unnamed_byref); + SP_VOTE_VAR(sp_after_type); + SP_VOTE_VAR(sp_template_angle); + SP_VOTE_VAR(sp_before_angle); + SP_VOTE_VAR(sp_inside_angle); + SP_VOTE_VAR(sp_after_angle); + SP_VOTE_VAR(sp_angle_paren); + SP_VOTE_VAR(sp_angle_word); + SP_VOTE_VAR(sp_before_square); + SP_VOTE_VAR(sp_before_squares); + SP_VOTE_VAR(sp_inside_square); + SP_VOTE_VAR(sp_before_sparen); + SP_VOTE_VAR(sp_inside_sparen); + SP_VOTE_VAR(sp_after_sparen); + SP_VOTE_VAR(sp_sparen_brace); + SP_VOTE_VAR(sp_special_semi); + SP_VOTE_VAR(sp_before_semi); + SP_VOTE_VAR(sp_before_semi_for); + SP_VOTE_VAR(sp_before_semi_for_empty); + SP_VOTE_VAR(sp_after_semi_for_empty); + SP_VOTE_VAR(sp_after_comma); + SP_VOTE_VAR(sp_before_comma); + SP_VOTE_VAR(sp_after_class_colon); + SP_VOTE_VAR(sp_before_class_colon); + SP_VOTE_VAR(sp_inside_braces); + SP_VOTE_VAR(sp_inside_braces_empty); + SP_VOTE_VAR(sp_else_brace); + SP_VOTE_VAR(sp_brace_else); + SP_VOTE_VAR(sp_catch_brace); + SP_VOTE_VAR(sp_brace_catch); + SP_VOTE_VAR(sp_finally_brace); + SP_VOTE_VAR(sp_brace_finally); + SP_VOTE_VAR(sp_try_brace); + SP_VOTE_VAR(sp_getset_brace); + + Chunk *prev = Chunk::GetHead(); + Chunk *pc = prev->GetNext(); + Chunk *next; + + while (pc->IsNotNullChunk()) + { + next = pc->GetNext(); + + if (next->IsNullChunk()) + { + break; + } + + if ( pc->Is(CT_ARITH) + || pc->Is(CT_SHIFT)) + { + vote_sp_arith.vote(pc, next); + vote_sp_arith.vote(prev, pc); + } + + if (pc->Is(CT_ASSIGN)) + { + if (!pc->TestFlags(PCF_IN_ENUM)) + { + vote_sp_before_assign.vote(prev, pc); + vote_sp_after_assign.vote(pc, next); + } + else + { + vote_sp_enum_before_assign.vote(prev, pc); + vote_sp_enum_after_assign.vote(pc, next); + } + } + + if (pc->Is(CT_SQUARE_OPEN)) + { + vote_sp_before_square.vote(prev, pc); + vote_sp_inside_square.vote(pc, next); + } + + if (pc->Is(CT_SQUARE_CLOSE)) + { + vote_sp_inside_square.vote(prev, pc); + } + + if (pc->Is(CT_TSQUARE)) + { + vote_sp_before_squares.vote(prev, pc); + } + + if (pc->Is(CT_BOOL)) + { + vote_sp_bool.vote(prev, pc); + vote_sp_bool.vote(pc, next); + } + + if (pc->Is(CT_COMPARE)) + { + vote_sp_compare.vote(prev, pc); + vote_sp_compare.vote(pc, next); + } + + if (pc->Is(CT_PAREN_CLOSE)) + { + vote_sp_inside_paren.vote(prev, pc); + } + + if (pc->Is(CT_PAREN_OPEN)) + { + vote_sp_inside_paren.vote(pc, next); + } + + if ( ( pc->IsParenOpen() + && next->IsParenOpen()) + || ( pc->IsParenClose() + && next->IsParenClose())) + { + vote_sp_paren_paren.vote(pc, next); + } + + if ( pc->IsParenClose() + && next->Is(CT_BRACE_OPEN)) + { + vote_sp_paren_brace.vote(pc, next); + } + + if (pc->Is(CT_PTR_TYPE)) + { + if (prev->Is(CT_PTR_TYPE)) + { + vote_sp_between_ptr_star.vote(prev, pc); + } + else if (next->IsNot(CT_WORD)) + { + vote_sp_before_unnamed_ptr_star.vote(prev, pc); + } + else + { + vote_sp_before_ptr_star.vote(prev, pc); + } + + if (CharTable::IsKw1(next->GetStr()[0])) + { + vote_sp_after_ptr_star.vote(pc, next); + } + } + + if (pc->Is(CT_BYREF)) + { + if (next->IsNot(CT_WORD)) + { + vote_sp_before_unnamed_byref.vote(prev, pc); + } + else + { + vote_sp_before_byref.vote(prev, pc); + } + vote_sp_after_byref.vote(pc, next); + } + + if ( pc->IsNot(CT_PTR_TYPE) + && ( prev->Is(CT_QUALIFIER) + || prev->Is(CT_TYPE))) + { + vote_sp_after_type.vote(prev, pc); + } + + if (pc->Is(CT_ANGLE_OPEN)) + { + vote_sp_inside_angle.vote(pc, next); + + if (prev->Is(CT_TEMPLATE)) + { + vote_sp_template_angle.vote(prev, pc); + } + else + { + vote_sp_before_angle.vote(prev, pc); + } + } + + if (pc->Is(CT_ANGLE_CLOSE)) + { + vote_sp_inside_angle.vote(prev, pc); + + if (next->IsParenOpen()) + { + vote_sp_angle_paren.vote(prev, pc); + } + else if ( next->Is(CT_WORD) + || CharTable::IsKw1(next->GetStr()[0])) + { + vote_sp_angle_word.vote(prev, pc); + } + else + { + vote_sp_after_angle.vote(pc, next); + } + } + + if (pc->Is(CT_SPAREN_OPEN)) + { + vote_sp_before_sparen.vote(prev, pc); + vote_sp_inside_sparen.vote(pc, next); + } + + if (pc->Is(CT_SPAREN_CLOSE)) + { + vote_sp_inside_sparen.vote(prev, pc); + + if (next->Is(CT_BRACE_OPEN)) + { + vote_sp_sparen_brace.vote(pc, next); + } + else + { + vote_sp_after_sparen.vote(pc, next); + } + } + + if (pc->Is(CT_SEMICOLON)) + { + if (pc->GetParentType() == CT_FOR) + { + if (prev->Is(CT_SPAREN_OPEN)) + { + // empty, ie for (;;) + // ^ is prev + // ^ is pc + vote_sp_before_semi_for_empty.vote(prev, pc); + } + else if (next->Is(CT_SPAREN_CLOSE)) + { + // empty, ie for (;;) + // ^ is pc + // ^ is next + vote_sp_after_semi_for_empty.vote(pc, next); + } + else if (prev->IsNot(CT_SEMICOLON)) + { + // empty, ie for (; i < 8;) + // ^ is pc + // or + // ^ is prev + vote_sp_before_semi_for.vote(prev, pc); + } + } + else if (prev->Is(CT_VBRACE_OPEN)) + { + vote_sp_special_semi.vote(prev->GetPrev(), pc); + } + else + { + vote_sp_before_semi.vote(prev, pc); + } + } + + if (pc->Is(CT_COMMA)) + { + vote_sp_before_comma.vote(prev, pc); + vote_sp_after_comma.vote(pc, next); + } + + if (pc->Is(CT_CLASS_COLON)) + { + vote_sp_before_class_colon.vote(prev, pc); + vote_sp_after_class_colon.vote(pc, next); + } + + if (pc->Is(CT_BRACE_OPEN)) + { + if (prev->Is(CT_ELSE)) + { + vote_sp_else_brace.vote(prev, pc); + } + else if (prev->Is(CT_CATCH)) + { + vote_sp_catch_brace.vote(prev, pc); + } + else if (prev->Is(CT_FINALLY)) + { + vote_sp_catch_brace.vote(prev, pc); + } + else if (prev->Is(CT_TRY)) + { + vote_sp_catch_brace.vote(prev, pc); + } + else if (prev->Is(CT_GETSET)) + { + vote_sp_catch_brace.vote(prev, pc); + } + + if (next->Is(CT_BRACE_CLOSE)) + { + vote_sp_inside_braces_empty.vote(pc, next); + } + else + { + vote_sp_inside_braces.vote(pc, next); + } + } + + if (pc->Is(CT_BRACE_CLOSE)) + { + vote_sp_inside_braces.vote(prev, pc); + + if (next->Is(CT_ELSE)) + { + vote_sp_brace_else.vote(pc, next); + } + else if (next->Is(CT_CATCH)) + { + vote_sp_brace_catch.vote(pc, next); + } + else if (next->Is(CT_FINALLY)) + { + vote_sp_brace_finally.vote(pc, next); + } + } + prev = pc; + pc = next; + } +} // detect_space_options + + +void detect_options() +{ + detect_space_options(); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/detect.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/detect.h new file mode 100644 index 00000000..77169322 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/detect.h @@ -0,0 +1,16 @@ +/** + * @file detect.h + * prototypes for detect.c + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef DETECT_H_INCLUDED +#define DETECT_H_INCLUDED + + +//! Call all the detect_xxxx() functions +void detect_options(); + + +#endif /* DETECT_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/enum_cleanup.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/enum_cleanup.cpp new file mode 100644 index 00000000..d44d5799 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/enum_cleanup.cpp @@ -0,0 +1,96 @@ +/** + * @file enum_cleanup.cpp + * works on the last comma within enum + * + * @author Guy Maurel Juli 2018 + * @license GPL v2+ + */ + +#include "enum_cleanup.h" + +#include "log_rules.h" + +constexpr static auto LCURRENT = LTOK; + +using namespace uncrustify; + + +void enum_cleanup() +{ + LOG_FUNC_ENTRY(); + + log_rule_B("mod_enum_last_comma"); + + if (options::mod_enum_last_comma() == IARF_IGNORE) + { + // nothing to do + return; + } + Chunk *pc = Chunk::GetHead(); // Issue #858 + + while (pc->IsNotNullChunk()) + { + if ( pc->GetParentType() == CT_ENUM + && pc->Is(CT_BRACE_CLOSE)) + { + LOG_FMT(LTOK, "%s(%d): orig line is %zu, type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), get_token_name(pc->GetType())); + Chunk *prev = pc->GetPrevNcNnl(); // Issue #3604 + + if ( prev != nullptr + && prev->IsNotNullChunk()) + { + if (prev->Is(CT_COMMA)) + { + log_rule_B("mod_enum_last_comma"); + + if (options::mod_enum_last_comma() == IARF_REMOVE) + { + Chunk::Delete(prev); + } + } + else + { + if (prev->Is(CT_BRACE_OPEN)) // Issue #2902 + { + // nothing between CT_BRACE_OPEN and CT_BRACE_CLOSE + } + else + { + log_rule_B("mod_enum_last_comma"); + + if ( options::mod_enum_last_comma() == IARF_ADD + || options::mod_enum_last_comma() == IARF_FORCE) + { + // create a comma + Chunk comma; + comma.SetType(CT_COMMA); + comma.SetOrigLine(prev->GetOrigLine()); + comma.SetOrigCol(prev->GetOrigCol() + 1); + comma.SetNlCount(0); + comma.SetPpLevel(0); + comma.SetFlags(PCF_NONE); + comma.Str() = ","; + + if (prev->Is(CT_PP_ENDIF)) // Issue #3604 + { + prev = prev->GetPrevNcNnlNpp(); + } + + if (prev->Is(CT_COMMA)) // Issue #3604 + { + // nothing to do + } + else + { + comma.CopyAndAddAfter(prev); + } + pc = pc->GetNext(); + } + } + } + } + } + pc = pc->GetNext(); + } +} // enum_cleanup diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/enum_cleanup.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/enum_cleanup.h new file mode 100644 index 00000000..f9c46dc2 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/enum_cleanup.h @@ -0,0 +1,16 @@ +/** + * @file enum_cleanup.h + * + * @author Guy Maurel Juli 2018 + * @license GPL v2+ + */ +#ifndef ENUM_CLEANUP_H_INCLUDED +#define ENUM_CLEANUP_H_INCLUDED + +/** + * Scans through the whole list and does stuff. + * works on the last comma within enum + */ +void enum_cleanup(); + +#endif /* ENUM_CLEANUP_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/enum_flags.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/enum_flags.h new file mode 100644 index 00000000..4f4e33c5 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/enum_flags.h @@ -0,0 +1,120 @@ +/** + * @file enum_flags.h + * Operators for working with bit-flag enumerators. + * + * @author Matthew Woehlke (but mostly "borrowed" from Qt) + * @license GPL v2+ + */ + +#ifndef ENUM_FLAGS_H_INCLUDED +#define ENUM_FLAGS_H_INCLUDED + +#include <type_traits> + +#if __GNUC__ == 4 && !defined (__clang__) +#pragma GCC diagnostic push +#if __GNUC_MINOR__ < 9 || __GNUC_PATCHLEVEL__ < 2 +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59624 +#pragma GCC diagnostic ignored "-Wunused-but-set-parameter" +#endif +#endif + +#define UNC_DECLARE_FLAGS(flag_type, enum_type) \ + using flag_type = ::uncrustify::flags<enum_type> + +#define UNC_DECLARE_OPERATORS_FOR_FLAGS(flag_type) \ + inline flag_type operator&(flag_type::enum_t f1, flag_type::enum_t f2) \ + { return(flag_type{ f1 } &f2); } \ + inline flag_type operator|(flag_type::enum_t f1, flag_type::enum_t f2) \ + { return(flag_type{ f1 } | f2); } \ + inline flag_type operator|(flag_type::enum_t f1, flag_type f2) \ + { return(f2 | f1); } \ + inline void operator|(flag_type::enum_t f1, int f2) = delete + +namespace uncrustify +{ + +//----------------------------------------------------------------------------- +template<typename Enum> +class flags +{ +public: + using enum_t = Enum; + using int_t = typename std::underlying_type<enum_t>::type; + + template<typename T> using integral = + typename std::enable_if<std::is_integral<T>::value, bool>::type; + + inline flags() = default; + inline flags(Enum flag) + : m_i{static_cast<int_t>(flag)} + {} + + inline bool operator==(Enum const &other) + { return(m_i == static_cast<int_t>(other)); } + inline bool operator==(flags const &other) + { return(m_i == other.m_i); } + inline bool operator!=(Enum const &other) + { return(m_i != static_cast<int_t>(other)); } + inline bool operator!=(flags const &other) + { return(m_i != other.m_i); } + + template<typename T, integral<T> = true> + inline flags &operator&=(T mask) + { m_i &= static_cast<int_t>(mask); return(*this); } + + inline flags &operator|=(flags f) + { m_i |= f.m_i; return(*this); } + inline flags &operator|=(Enum f) + { m_i |= f; return(*this); } + + inline flags &operator^=(flags f) + { m_i ^= f.m_i; return(*this); } + inline flags &operator^=(Enum f) + { m_i ^= f; return(*this); } + + inline operator int_t() const { return(m_i); } + inline operator enum_t() const { return(static_cast<enum_t>(m_i)); } + + inline flags operator&(Enum f) const + { flags g; g.m_i = m_i & static_cast<int_t>(f); return(g); } + inline flags operator&(flags f) const + { flags g; g.m_i = m_i & static_cast<int_t>(f); return(g); } + + template<typename T, integral<T> = true> + inline flags operator&(T mask) const + { flags g; g.m_i = m_i & static_cast<int_t>(mask); return(g); } + + inline flags operator|(flags f) const + { flags g; g.m_i = m_i | f.m_i; return(g); } + inline flags operator|(Enum f) const + { flags g; g.m_i = m_i | static_cast<int_t>(f); return(g); } + + inline flags operator^(flags f) const + { flags g; g.m_i = m_i ^ f.m_i; return(g); } + inline flags operator^(Enum f) const + { flags g; g.m_i = m_i ^ static_cast<int_t>(f); return(g); } + + inline int_t operator~() const + { return(~m_i); } + + inline operator bool() const { return(!!m_i); } + inline bool operator!() const { return(!m_i); } + + inline bool test(flags f) const { return((*this & f) == f); } + inline bool test(Enum f) const { return((*this & f) == f); } + + inline bool test_any() const { return(m_i != 0); } + inline bool test_any(flags f) const { return((*this & f).test_any()); } + +protected: + int_t m_i = 0; +}; + +} // namespace uncrustify + +#if __GNUC__ == 4 && !defined (__clang__) +#pragma GCC diagnostic pop +#endif + +#endif diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/error_types.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/error_types.h new file mode 100644 index 00000000..4b162768 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/error_types.h @@ -0,0 +1,53 @@ +/** + * @file error_types.h + * + * Defines the error codes that are used throughout uncrustify + * + * @license GPL v2+ + */ +#ifndef ERROR_TYPES_H_INCLUDED +#define ERROR_TYPES_H_INCLUDED + +#if 1 +#include <stdlib.h> // provides EXIT_SUCCESS and EXIT FAILURE + +// TODO: if we decided to only use EX_OK and EX_xxx we can avoid including stdlib.h here + +#else +// TODO: I left this to show my modifications remove it after the PR was reviewed + +// the good old SUCCESS/FAILURE +#define SUCCESS 0 //! same as EX_OK */ +#define FAILURE -1 //! incompatible to EXIT_FAILURE +#endif + + +#if defined (WIN32) || defined (__QNXNTO__) +// Windows does not know sysexists.h. Thus define the error codes + +#define EX_OK 0 //! successful termination +#define EX__BASE 64 //! base value for error messages +#define EX_USAGE 64 //! command line usage error +#define EX_DATAERR 65 //! data format error +#define EX_NOINPUT 66 //! cannot open input +#define EX_NOUSER 67 //! addressee unknown +#define EX_NOHOST 68 //! host name unknown +#define EX_UNAVAILABLE 69 //! service unavailable +#define EX_SOFTWARE 70 //! internal software error +#define EX_OSERR 71 //! system error (e.g., can't fork) +#define EX_OSFILE 72 //! critical OS file missing +#define EX_CANTCREAT 73 //! can't create (user) output file +#define EX_IOERR 74 //! input/output error +#define EX_TEMPFAIL 75 //! temp failure; user is invited to retry +#define EX_PROTOCOL 76 //! remote error in protocol +#define EX_NOPERM 77 //! permission denied +#define EX_CONFIG 78 //! configuration error +#define EX__MAX 78 //! maximum listed value + +#else // not WIN32 or not __QNXNTO__ +// TODO: do all non windows systems know sysexits.h? +// Linux knows: /usr/include/sysexits.h +#include "sysexits.h" // comes from BSD +#endif + +#endif /* ERROR_TYPES_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_braced_init_list.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_braced_init_list.cpp new file mode 100644 index 00000000..66c128fa --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_braced_init_list.cpp @@ -0,0 +1,112 @@ +/** + * @file flag_braced_init_list.cpp + * + * @license GPL v2+ + */ + +#include "chunk.h" + +#include "flag_braced_init_list.h" + +#include "uncrustify.h" + + +bool detect_cpp_braced_init_list(Chunk *pc, Chunk *next) +{ + LOG_FUNC_ENTRY(); + // Issue #2332 + bool we_have_a_case_before = false; + + if (pc->Is(CT_COLON)) + { + // check if we have a case before + Chunk *switch_before = pc->GetPrevType(CT_CASE, pc->GetLevel()); + + if (switch_before->IsNotNullChunk()) + { + LOG_FMT(LFCNR, "%s(%d): switch_before orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, switch_before->GetOrigLine(), switch_before->GetOrigCol(), + switch_before->Text(), get_token_name(switch_before->GetType())); + we_have_a_case_before = true; + } + } + + // Detect a braced-init-list + if ( pc->Is(CT_WORD) + || pc->Is(CT_TYPE) + || pc->Is(CT_ASSIGN) + || pc->Is(CT_RETURN) + || pc->Is(CT_COMMA) + || pc->Is(CT_ANGLE_CLOSE) + || pc->Is(CT_SQUARE_CLOSE) + || pc->Is(CT_TSQUARE) + || pc->Is(CT_FPAREN_OPEN) + || pc->Is(CT_QUESTION) + || ( pc->Is(CT_COLON) + && !we_have_a_case_before) + || ( pc->Is(CT_BRACE_OPEN) + && ( pc->GetParentType() == CT_NONE + || pc->GetParentType() == CT_BRACED_INIT_LIST))) + { + LOG_FMT(LFCNR, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n ", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + log_pcf_flags(LFCNR, pc->GetFlags()); + auto brace_open = pc->GetNextNcNnl(); + + if ( brace_open->Is(CT_BRACE_OPEN) + && ( brace_open->GetParentType() == CT_NONE + || brace_open->GetParentType() == CT_ASSIGN + || brace_open->GetParentType() == CT_RETURN + || brace_open->GetParentType() == CT_BRACED_INIT_LIST)) + { + log_pcf_flags(LFCNR, brace_open->GetFlags()); + auto brace_close = next->GetClosingParen(); + + if (brace_close->Is(CT_BRACE_CLOSE)) + { + return(true); + } + } + } + return(false); +} // detect_cpp_braced_init_list + + +void flag_cpp_braced_init_list(Chunk *pc, Chunk *next) +{ + Chunk *brace_open = pc->GetNextNcNnl(); + Chunk *brace_close = next->GetClosingParen(); + + brace_open->SetParentType(CT_BRACED_INIT_LIST); + brace_close->SetParentType(CT_BRACED_INIT_LIST); + + Chunk *tmp = brace_close->GetNextNcNnl(); + + if (tmp->IsNotNullChunk()) + { + tmp->ResetFlagBits(PCF_EXPR_START | PCF_STMT_START); + + // Flag call operator + if (tmp->Is(CT_PAREN_OPEN)) + { + Chunk *c = tmp->GetClosingParen(); + + if (c->IsNotNullChunk()) + { + tmp->SetType(CT_FPAREN_OPEN); + tmp->SetParentType(CT_FUNC_CALL); + c->SetType(CT_FPAREN_CLOSE); + c->SetParentType(CT_FUNC_CALL); + } + } + } + // TODO: Change pc->GetType() CT_WORD -> CT_TYPE + // for the case CT_ASSIGN (and others). + + // TODO: Move this block to the fix_fcn_call_args function. + if ( pc->Is(CT_WORD) + && pc->TestFlags(PCF_IN_FCN_CALL)) + { + pc->SetType(CT_TYPE); + } +} // flag_cpp_braced_init_list diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_braced_init_list.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_braced_init_list.h new file mode 100644 index 00000000..75d19a79 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_braced_init_list.h @@ -0,0 +1,27 @@ +/** + * @file flag_braced_init_list.h + * + * @license GPL v2+ + */ + +#ifndef FLAG_BRACED_INIT_LIST_INCLUDED +#define FLAG_BRACED_INIT_LIST_INCLUDED + +#include "chunk.h" + + +/** + * Detect a cpp braced init list + */ +bool detect_cpp_braced_init_list(Chunk *pc, Chunk *next); + + +/** + * Flags the opening and closing braces of an expression deemed to be + * a cpp braced initializer list; a call to detect_cpp_braced_init_list() + * should first be made prior to calling this function + */ +void flag_cpp_braced_init_list(Chunk *pc, Chunk *next); + + +#endif diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_decltype.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_decltype.cpp new file mode 100644 index 00000000..6950bc10 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_decltype.cpp @@ -0,0 +1,46 @@ +/** + * @file flag_decltype.cpp + * + * @license GPL v2+ + */ + +#include "chunk.h" + + +bool flag_cpp_decltype(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + if (pc->Is(CT_DECLTYPE)) + { + auto paren_open = pc->GetNextNcNnl(); + + if (paren_open->Is(CT_PAREN_OPEN)) + { + // We would like to simply call Chunk::SkipToMatch(), but it finds + // a match based on level, and the level is 0 for all chunks in some + // cases, like the following example. + // + // template <typename T> + // decltype(std::declval<T &>().put(foo), std::true_type()) + // has_something(Tag<2>); + // + // This means that IN_DECLTYPE is only set for tokens through the + // closing parenthesis right before ".put" in the above example. + // + // So, we will manually look for the matching closing parenthesis. + paren_open->SetFlagBits(PCF_IN_DECLTYPE); + pc = paren_open->GetNextNcNnl(); + + for (int level = 1; pc->IsNotNullChunk() && level > 0; pc = pc->GetNextNcNnl()) + { + level += pc->Is(CT_PAREN_OPEN); + level -= pc->Is(CT_PAREN_CLOSE); + pc->SetFlagBits(PCF_IN_DECLTYPE); + } + + return(pc->IsNotNullChunk()); + } + } + return(false); +} // mark_cpp_decltype diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_decltype.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_decltype.h new file mode 100644 index 00000000..293fcd02 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_decltype.h @@ -0,0 +1,21 @@ +/** + * @file flag_decltype.h + * + * @license GPL v2+ + */ + +#ifndef FLAG_DECLTYPE_INCLUDED +#define FLAG_DECLTYPE_INCLUDED + +#include "chunk.h" + +/** + * Flags all chunks within a cpp decltype expression from the opening + * brace to the closing brace + * + * @return Returns true if expression is a valid decltype expression + */ +bool flag_cpp_decltype(Chunk *pc); + + +#endif diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_parens.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_parens.cpp new file mode 100644 index 00000000..c435710a --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_parens.cpp @@ -0,0 +1,71 @@ +/** + * @file flag_parens.cpp + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#include "flag_parens.h" + +#include "uncrustify.h" + + +Chunk *flag_parens(Chunk *po, T_PcfFlags flags, E_Token opentype, E_Token parent_type, bool parent_all) +{ + LOG_FUNC_ENTRY(); + Chunk *paren_close; + + paren_close = po->GetClosingParen(E_Scope::PREPROC); + + if (paren_close->IsNullChunk()) + { + LOG_FMT(LERR, "%s(%d): no match for '%s' at [%zu:%zu]", + __func__, __LINE__, po->Text(), po->GetOrigLine(), po->GetOrigCol()); + log_func_stack_inline(LERR); + exit(EX_SOFTWARE); + } + LOG_FMT(LFLPAREN, "%s(%d): between po is '%s', orig line is %zu, orig col is %zu, and\n", + __func__, __LINE__, po->Text(), po->GetOrigLine(), po->GetOrigCol()); + LOG_FMT(LFLPAREN, "%s(%d): paren_close is '%s', orig line is %zu, orig col is %zu, type is %s, parent type is %s\n", + __func__, __LINE__, paren_close->Text(), paren_close->GetOrigLine(), paren_close->GetOrigCol(), + get_token_name(opentype), get_token_name(parent_type)); + log_func_stack_inline(LFLPAREN); + + // the last chunk must be also modified. Issue #2149 + Chunk *after_paren_close = paren_close->GetNext(); + + if (po != paren_close) + { + if ( flags != PCF_NONE + || ( parent_all + && parent_type != CT_NONE)) + { + Chunk *pc; + + for (pc = po->GetNext(E_Scope::PREPROC); + pc != nullptr && pc->IsNotNullChunk() && pc != after_paren_close; + pc = pc->GetNext(E_Scope::PREPROC)) + { + pc->SetFlagBits(flags); + + if (parent_all) + { + pc->SetParentType(parent_type); + } + } + } + + if (opentype != CT_NONE) + { + po->SetType(opentype); + paren_close->SetType((E_Token)(opentype + 1)); + } + + if (parent_type != CT_NONE) + { + po->SetParentType(parent_type); + paren_close->SetParentType(parent_type); + } + } + return(paren_close->GetNextNcNnl(E_Scope::PREPROC)); +} // flag_parens diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_parens.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_parens.h new file mode 100644 index 00000000..220eb127 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/flag_parens.h @@ -0,0 +1,28 @@ +/** + * @file flag_parens.h + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#ifndef FLAG_PARENS_H_INCLUDED +#define FLAG_PARENS_H_INCLUDED + +#include "chunk.h" + + +/** + * Flags everything from the open paren to the close paren. + * + * @param po Pointer to the open parenthesis + * @param flags flags to add + * @param opentype + * @param parenttype + * @param parent_all + * + * @return The token after the close paren + */ +Chunk *flag_parens(Chunk *po, T_PcfFlags flags, E_Token opentype, E_Token parenttype, bool parent_all); + + +#endif /* FLAG_PARENS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/frame_list.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/frame_list.cpp new file mode 100644 index 00000000..da94ba2f --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/frame_list.cpp @@ -0,0 +1,345 @@ +/** + * @file frame_list.cpp + * mainly used to handle preprocessor stuff + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "frame_list.h" + +#include "prototypes.h" + + +namespace +{ + +void fl_log_frms(log_sev_t logsev, const char *txt, const ParseFrame &frm, const std::vector<ParseFrame> &frames); + + +//! Logs the entire parse frame stack +void fl_log_all(log_sev_t logsev, const std::vector<ParseFrame> &frames); + + +/** + * Copy the top element of the frame list into the ParseFrame. + * + * If the frame list is empty nothing happens. + * + * This is called on #else and #elif. + */ +void fl_copy_tos(ParseFrame &pf, const std::vector<ParseFrame> &frames); + + +/** + * Copy the 2nd top element off the list into the ParseFrame. + * This is called on #else and #elif. + * The stack contains [...] [base] [if] at this point. + * We want to copy [base]. + */ +void fl_copy_2nd_tos(ParseFrame &pf, const std::vector<ParseFrame> &frames); + + +//! Deletes the top element from the list. +void fl_trash_tos(std::vector<ParseFrame> &frames); + + +//! Logs one parse frame +void fl_log(log_sev_t logsev, const ParseFrame &frm) +{ + LOG_FMT(logsev, "[%s] BrLevel=%zu Level=%zu PseTos=%zu\n", + get_token_name(frm.in_ifdef), frm.brace_level, frm.level, frm.size() - 1); + + LOG_FMT(logsev, " *"); + + for (size_t idx = 1; idx < frm.size(); idx++) + { + LOG_FMT(logsev, " [%s-%s]", get_token_name(frm.at(idx).type), + get_brace_stage_name(frm.at(idx).stage)); + } + + LOG_FMT(logsev, "\n"); +} + + +void fl_log_frms(log_sev_t logsev, + const char *txt, + const ParseFrame &frm, + const std::vector<ParseFrame> &frames) +{ + LOG_FMT(logsev, "%s Parse Frames(%zu):", txt, frames.size()); + + for (const auto &frame : frames) + { + LOG_FMT(logsev, " [%s-%zu]", get_token_name(frame.in_ifdef), + frame.ref_no); + } + + LOG_FMT(logsev, "-[%s-%zu]\n", get_token_name(frm.in_ifdef), frm.ref_no); +} + + +void fl_log_all(log_sev_t logsev, const std::vector<ParseFrame> &frames) +{ + LOG_FMT(logsev, "##=- Parse Frame : %zu entries\n", frames.size()); + + for (size_t idx = 0; idx < frames.size(); idx++) + { + LOG_FMT(logsev, "## idx is %zu, ", idx); + + fl_log(logsev, frames.at(idx)); + } + + LOG_FMT(logsev, "##=-\n"); +} + + +void fl_copy_tos(ParseFrame &pf, const std::vector<ParseFrame> &frames) +{ + if (!frames.empty()) + { + pf = *std::prev(std::end(frames)); + } + LOG_FMT(LPF, "%s(%d): frame_count is %zu\n", __func__, __LINE__, frames.size()); +} + + +void fl_copy_2nd_tos(ParseFrame &pf, const std::vector<ParseFrame> &frames) +{ + if (frames.size() > 1) + { + pf = *std::prev(std::end(frames), 2); + } + LOG_FMT(LPF, "%s(%d): frame_count is %zu\n", __func__, __LINE__, frames.size()); +} + + +void fl_trash_tos(std::vector<ParseFrame> &frames) +{ + if (!frames.empty()) + { + frames.pop_back(); + } + LOG_FMT(LPF, "%s(%d): frame_count is %zu\n", __func__, __LINE__, frames.size()); +} + +} // namespace + + +void fl_push(std::vector<ParseFrame> &frames, ParseFrame &frm) +{ + static int ref_no = 1; + + frames.push_back(frm); + frm.ref_no = ref_no++; + + LOG_FMT(LPF, "%s(%d): frame_count is %zu\n", __func__, __LINE__, frames.size()); +} + + +void fl_pop(std::vector<ParseFrame> &frames, ParseFrame &pf) +{ + if (frames.empty()) + { + return; + } + fl_copy_tos(pf, frames); + fl_trash_tos(frames); +} + + +int fl_check(std::vector<ParseFrame> &frames, ParseFrame &frm, int &pp_level, Chunk *pc) +{ + if (pc->IsNot(CT_PREPROC)) + { + return(pp_level); + } + Chunk *next = pc->GetNext(); + + if (next->IsNullChunk()) + { + return(pp_level); + } + + if (pc->GetParentType() != next->GetType()) + { + LOG_FMT(LNOTE, "%s(%d): Preproc parent not set correctly on orig line %zu: got %s expected %s\n", + __func__, __LINE__, pc->GetOrigLine(), get_token_name(pc->GetParentType()), + get_token_name(next->GetType())); + pc->SetParentType(next->GetType()); + } + LOG_FMT(LPFCHK, "%s(%d): orig line is %zu, %s\n", + __func__, __LINE__, pc->GetOrigLine(), get_token_name(pc->GetParentType())); + fl_log_frms(LPFCHK, "TOP", frm, frames); + + + int out_pp_level = pp_level; + const E_Token in_ifdef = frm.in_ifdef; + const size_t b4_cnt = frames.size(); + + const char *txt = nullptr; + + if (pc->TestFlags(PCF_IN_PREPROC)) + { + LOG_FMT(LPF, " <In> "); + fl_log(LPF, frm); + + if (pc->GetParentType() == CT_PP_IF) + { + // An #if pushes a copy of the current frame on the stack + pp_level++; + fl_push(frames, frm); + frm.in_ifdef = CT_PP_IF; + txt = "if-push"; + } + else if (pc->GetParentType() == CT_PP_ELSE) + { + if (out_pp_level == 0) + { + fprintf(stderr, "%s(%d): pp level is ZERO, cannot be decremented, at line %zu, column %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + out_pp_level--; + + /* + * For #else of #elif, we want to keep the #if part and throw out the + * else parts. + * We check to see what the top type is to see if we just push or + * pop and then push. + * We need to use the copy right before the if. + */ + bool if_block = false; + + if (frm.in_ifdef == CT_PP_IF) + { + // we have [...] [base]-[if], so push an [else] + fl_push(frames, frm); + frm.in_ifdef = CT_PP_ELSE; + if_block = true; + } + size_t brace_level = frm.brace_level; + // we have [...] [base] [if]-[else], copy [base] over [else] + fl_copy_2nd_tos(frm, frames); + frm.in_ifdef = CT_PP_ELSE; + + if (if_block) + { + // check if #if block was unbalanced + size_t base_brace_level = frames[frames.size() - 2].brace_level; + + if ( options::pp_warn_unbalanced_if() + && brace_level != base_brace_level) + { + LOG_FMT(LWARN, "%s(%d): orig line is %zu, unbalanced #if block braces (1), in-level is %zu, out-level is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), base_brace_level, brace_level); + } + } + else + { + // check if previous #else block has a different indentation than the corresponding #if block + size_t if_brace_level = frames[frames.size() - 1].brace_level; + + if ( options::pp_warn_unbalanced_if() + && brace_level != if_brace_level) + { + LOG_FMT(LWARN, "%s(%d): orig line is %zu, unbalanced #if-#else block braces (1), #else out-level is %zu, #if out-level is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), brace_level, if_brace_level); + } + } + txt = "else-push"; + } + else if (pc->GetParentType() == CT_PP_ENDIF) + { + /* + * we may have [...] [base] [if]-[else] or [...] [base]-[if]. + * Throw out the [else]. + */ + if (pp_level == 0) + { + // cpd.pp_level is ZERO, cannot be decremented. + fprintf(stderr, "%s(%d): #endif found, at line %zu, column %zu, without corresponding #if\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + pp_level--; + + if (out_pp_level == 0) + { + fprintf(stderr, "%s(%d): pp level is ZERO, cannot be decremented, at line %zu, column %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + out_pp_level--; + + if (frm.in_ifdef == CT_PP_ELSE) + { + size_t brace_level = frm.brace_level; // brace level or current #else block + /* + * We have: [...] [base] [if]-[else] + * We want: [...]-[if] + */ + fl_copy_tos(frm, frames); // [...] [base] [if]-[if] + + if ( options::pp_warn_unbalanced_if() + && brace_level != frm.brace_level) + { + LOG_FMT(LWARN, "%s(%d): orig line is %zu, unbalanced #if-#else block braces (2), #else out-level is %zu, #if out-level is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), brace_level, frm.brace_level); + } + + if (frames.size() < 2) + { + fprintf(stderr, "Number of 'frame' is too small.\n"); + fprintf(stderr, "Please make a report.\n"); + log_flush(true); + exit(EX_SOFTWARE); + } + frm.in_ifdef = frames[frames.size() - 2].in_ifdef; + fl_trash_tos(frames); // [...] [base]-[if] + fl_trash_tos(frames); // [...]-[if] + + txt = "endif-trash/pop"; + } + else if (frm.in_ifdef == CT_PP_IF) + { + /* + * We have: [...] [base] [if] + * We want: [...] [base] + */ + // check if #if block was unbalanced + size_t brace_level = frm.brace_level; + fl_pop(frames, frm); + + if ( options::pp_warn_unbalanced_if() + && brace_level != frm.brace_level) + { + LOG_FMT(LWARN, "%s(%d): orig line is %zu, unbalanced #if block braces (2), in-level is %zu, out-level is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), frm.brace_level, brace_level); + } + txt = "endif-pop"; + } + else + { + txt = "???"; + } + } + } + + if (txt != nullptr) + { + LOG_FMT(LPF, "%s(%d): orig line is %zu, type is %s: %s in_ifdef is %s/%s, counts is %zu, frame_count is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), + get_token_name(pc->GetParentType()), txt, get_token_name(in_ifdef), + get_token_name(frm.in_ifdef), b4_cnt, frames.size()); + fl_log_all(LPF, frames); + LOG_FMT(LPF, " <Out>"); + fl_log(LPF, frm); + } + fl_log_frms(LPFCHK, "END", frm, frames); + + return(out_pp_level); +} // fl_check diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/frame_list.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/frame_list.h new file mode 100644 index 00000000..5fd09a52 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/frame_list.h @@ -0,0 +1,40 @@ +/** + * @file frame_list.h + * mainly used to handle preprocessor stuff + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef PARSE_FRAME_H_INCLUDED +#define PARSE_FRAME_H_INCLUDED + +#include "ParseFrame.h" +#include "uncrustify_types.h" + + +/** + * Push a copy of a ParseFrame onto the frames list. + * This is called on #if and #ifdef. + */ +void fl_push(std::vector<ParseFrame> &frames, ParseFrame &frm); + + +/** + * Pop the top element off the frame list and copy it into the ParseFrame. + * + * Does nothing if the frame list is empty. + * + * This is called on #endif + */ +void fl_pop(std::vector<ParseFrame> &frames, ParseFrame &pf); + + +// TODO: this name is dumb: +// - what is it checking? +// - why does is much more than simple checks, it allters kinds of stuff +//! Returns the pp_indent to use for this line +int fl_check(std::vector<ParseFrame> &frames, ParseFrame &frm, int &pp_level, Chunk *pc); + + +#endif /* PARSE_FRAME_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/indent.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/indent.cpp new file mode 100644 index 00000000..b9f515ad --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/indent.cpp @@ -0,0 +1,4741 @@ +/** + * @file indent.cpp + * Does all the indenting stuff. + * + * @author Ben Gardner + * @author Guy Maurel October 2015- 2021 + * @license GPL v2+ + */ + +#include "indent.h" + +#include "align.h" +#include "frame_list.h" +#include "options.h" +#include "options_for_QT.h" +#include "prototypes.h" +#include "quick_align_again.h" +#include "space.h" + +#ifdef WIN32 +#include <algorithm> // to get max +#endif // ifdef WIN32 + +#ifdef IGNORE // WinBase.h +#undef IGNORE +#endif + + +constexpr static auto LCURRENT = LINDENT; + +using namespace std; +using namespace uncrustify; + + +/** + * General indenting approach: + * Indenting levels are put into a stack. + * + * The stack entries contain: + * - opening type + * - brace column + * - continuation column + * + * Items that start a new stack item: + * - preprocessor (new parse frame) + * - Brace Open (Virtual brace also) + * - Paren, Square, Angle open + * - Assignments + * - C++ '<<' operator (ie, cout << "blah") + * - case + * - class colon + * - return + * - types + * - any other continued statement + * + * Note that the column of items marked 'PCF_WAS_ALIGNED' is not changed. + * + * For an open brace: + * - indent increases by indent_columns + * - if part of if/else/do/while/switch/etc, an extra indent may be applied + * - if in a paren, then cont-col is set to column + 1, ie "({ some code })" + * + * Open paren/square/angle: + * cont-col is set to the column of the item after the open paren, unless + * followed by a newline, then it is set to (brace-col + indent_columns). + * Examples: + * a_really_long_function_name( + * param1, param2); + * a_really_long_function_name(param1, + * param2); + * + * Assignments: + * Assignments are continued aligned with the first item after the assignment, + * unless the assign is followed by a newline. + * Examples: + * some.variable = asdf + asdf + + * asdf; + * some.variable = + * asdf + asdf + asdf; + * + * C++ << operator: + * Handled the same as assignment. + * Examples: + * cout << "this is test number: " + * << test_number; + * + * case: + * Started with case or default. + * Terminated with close brace at level or another case or default. + * Special indenting according to various rules. + * - indent of case label + * - indent of case body + * - how to handle optional braces + * Examples: + * { + * case x: { + * a++; + * break; + * } + * case y: + * b--; + * break; + * default: + * c++; + * break; + * } + * + * Class colon: + * Indent continuation by indent_columns: + * class my_class : + * baseclass1, + * baseclass2 + * { + * + * Return: same as assignments + * If the return statement is not fully paren'd, then the indent continues at + * the column of the item after the return. If it is paren'd, then the paren + * rules apply. + * return somevalue + + * othervalue; + * + * Type: pretty much the same as assignments + * Examples: + * int foo, + * bar, + * baz; + * + * Any other continued item: + * There shouldn't be anything not covered by the above cases, but any other + * continued item is indented by indent_columns: + * Example: + * somereallycrazylongname.with[lotsoflongstuff]. + * thatreallyannoysme.whenIhavetomaintain[thecode] = 3; + */ + +/** + * REVISIT: This needs to be re-checked, maybe cleaned up + * + * Indents comments in a (hopefully) smart manner. + * + * There are two type of comments that get indented: + * - stand alone (ie, no tokens on the line before the comment) + * - trailing comments (last token on the line apart from a linefeed) + * + note that a stand-alone comment is a special case of a trailing + * + * The stand alone comments will get indented in one of three ways: + * - column 1: + * + There is an empty line before the comment AND the indent level is 0 + * + The comment was originally in column 1 + * + * - Same column as trailing comment on previous line (ie, aligned) + * + if originally within TBD (3) columns of the previous comment + * + * - syntax indent level + * + doesn't fit in the previous categories + * + * Options modify this behavior: + * - keep original column (don't move the comment, if possible) + * - keep relative column (move out the same amount as first item on line) + * - fix trailing comment in column TBD + * + * @param pc The comment, which is the first item on a line + * @param col The column if this is to be put at indent level + */ +static void indent_comment(Chunk *pc, size_t col); + + +static size_t token_indent(E_Token type); + + +static size_t calc_indent_continue(const ParseFrame &frm, size_t pse_tos); + +/** + * Get candidate chunk first on line to which OC blocks can be indented against. + */ +static Chunk *candidate_chunk_first_on_line(Chunk *pc); + +/** + * We are on a '{' that has parent = OC_BLOCK_EXPR + * find the column of the param tag + */ +static Chunk *oc_msg_block_indent(Chunk *pc, bool from_brace, bool from_caret, bool from_colon, bool from_keyword); + + +/** + * returns true if forward or reverse scan reveals only single newlines or comments + * stops when hits code + * false if next thing hit is a closing brace, also if 2 newlines in a row + */ +static bool single_line_comment_indent_rule_applies(Chunk *start, bool forward); + +/** + * returns true if semicolon on the same level ends any assign operations + * false if next thing hit is not the end of an assign operation + */ +static bool is_end_of_assignment(Chunk *pc, const ParseFrame &frm); + + +void indent_to_column(Chunk *pc, size_t column) +{ + LOG_FUNC_ENTRY(); + + if (column < pc->GetColumn()) + { + column = pc->GetColumn(); + } + reindent_line(pc, column); +} + + +enum class align_mode_e : unsigned int +{ + SHIFT, //! shift relative to the current column + KEEP_ABS, //! try to keep the original absolute column + KEEP_REL, //! try to keep the original gap +}; + + +enum class indent_mode_e : int +{ + INDENT = 0, //! indent by one level + ALIGN = 1, //! align under the open brace/parenthesis + IGNORE = -1, //! preserve original indentation +}; + + +void align_to_column(Chunk *pc, size_t column) +{ + LOG_FUNC_ENTRY(); + + if ( pc == nullptr + || column == pc->GetColumn()) + { + return; + } + LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s => column is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetColumn(), pc->Text(), + get_token_name(pc->GetType()), column); + + const int col_delta = column - pc->GetColumn(); + size_t min_col = column; + + pc->SetColumn(column); + + do + { + auto *next = pc->GetNext(); + + if (next->IsNullChunk()) + { + break; + } + const size_t min_delta = space_col_align(pc, next); + min_col += min_delta; + + const auto *prev = pc; + pc = next; + + auto almod = align_mode_e::SHIFT; + + if ( pc->IsComment() + && pc->GetParentType() != CT_COMMENT_EMBED) + { + log_rule_B("indent_relative_single_line_comments"); + almod = ( pc->IsSingleLineComment() + && options::indent_relative_single_line_comments()) + ? align_mode_e::KEEP_REL : align_mode_e::KEEP_ABS; + } + + if (almod == align_mode_e::KEEP_ABS) + { + // Keep same absolute column + pc->SetColumn(max(pc->GetOrigCol(), min_col)); + } + else if (almod == align_mode_e::KEEP_REL) + { + // Keep same relative column + size_t orig_delta = pc->GetOrigPrevSp() + prev->Len(); + orig_delta = max<size_t>(orig_delta, min_delta); // keeps orig_delta positive + + pc->SetColumn(prev->GetColumn() + orig_delta); + } + else // SHIFT + { + // Shift by the same amount, keep above negative values + pc->SetColumn(( col_delta >= 0 + || (size_t)(abs(col_delta)) < pc->GetColumn()) + ? pc->GetColumn() + col_delta : 0); + pc->SetColumn(max(pc->GetColumn(), min_col)); + } + LOG_FMT(LINDLINED, "%s(%d): %s set column of '%s', type is %s, orig line is %zu, to col %zu (orig col was %zu)\n", + __func__, __LINE__, + (almod == align_mode_e::KEEP_ABS) ? "abs" : + (almod == align_mode_e::KEEP_REL) ? "rel" : "sft", + pc->Text(), get_token_name(pc->GetType()), pc->GetOrigLine(), pc->GetColumn(), pc->GetOrigCol()); + } while ( pc->IsNotNullChunk() + && pc->GetNlCount() == 0); +} // align_to_column + + +void reindent_line(Chunk *pc, size_t column) +{ + LOG_FUNC_ENTRY(); + char copy[1000]; + + LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, orig col is %zu, on '%s' [%s/%s] => %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->ElidedText(copy), + get_token_name(pc->GetType()), get_token_name(pc->GetParentType()), + column); + log_func_stack_inline(LINDLINE); + + if (column == pc->GetColumn()) + { + return; + } + int col_delta = column - pc->GetColumn(); + size_t min_col = column; + + pc->SetColumn(column); + + do + { + if (QT_SIGNAL_SLOT_found) + { + // fix the bug #654 + // connect(&mapper, SIGNAL(mapped(QString &)), this, SLOT(onSomeEvent(QString &))); + // look for end of SIGNAL/SLOT block + if (!pc->TestFlags(PCF_IN_QT_MACRO)) + { + LOG_FMT(LINDLINE, "FLAGS is NOT set: PCF_IN_QT_MACRO\n"); + restore_options_for_QT(); + } + } + else + { + // look for begin of SIGNAL/SLOT block + if (pc->TestFlags(PCF_IN_QT_MACRO)) + { + LOG_FMT(LINDLINE, "FLAGS is set: PCF_IN_QT_MACRO\n"); + save_set_options_for_QT(pc->GetLevel()); + } + } + Chunk *next = pc->GetNext(); + + if (next->IsNullChunk()) + { + break; + } + + if (pc->GetNlCount()) + { + min_col = 0; + col_delta = 0; + } + min_col += space_col_align(pc, next); + pc = next; + + const bool is_comment = pc->IsComment(); + log_rule_B("indent_relative_single_line_comments"); + const bool keep = ( is_comment + && pc->IsSingleLineComment() + && options::indent_relative_single_line_comments()); + + if ( is_comment + && pc->GetParentType() != CT_COMMENT_EMBED + && !keep) + { + pc->SetColumn(max(pc->GetOrigCol(), min_col)); + LOG_FMT(LINDLINE, "%s(%d): set comment on line %zu to col %zu (orig %zu)\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetColumn(), pc->GetOrigCol()); + } + else + { + pc->SetColumn(max(pc->GetColumn() + col_delta, min_col)); + + LOG_FMT(LINDLINED, "%s(%d): set column of ", __func__, __LINE__); + + if (pc->Is(CT_NEWLINE)) + { + LOG_FMT(LINDLINED, "<Newline>"); + } + else + { + LOG_FMT(LINDLINED, "'%s'", pc->Text()); + } + LOG_FMT(LINDLINED, " to %zu (orig %zu)\n", pc->GetColumn(), pc->GetOrigCol()); + } + } while ( pc->IsNotNullChunk() + && pc->GetNlCount() == 0); +} // reindent_line + + +static size_t token_indent(E_Token type) +{ + switch (type) + { + case CT_IF: + case CT_DO: + return(3); + + case CT_FOR: + case CT_ELSE: // wacky, but that's what is wanted + return(4); + + case CT_WHILE: + case CT_USING_STMT: + return(6); + + case CT_SWITCH: + return(7); + + case CT_ELSEIF: + return(8); + + case CT_SYNCHRONIZED: + return(13); + + default: + return(0); + } +} + + +#define indent_column_set(X) \ + do { \ + LOG_FMT(LINDENT2, "%s(%d): orig line is %zu, indent_column changed from %zu to %zu\n", \ + __func__, __LINE__, pc->GetOrigLine(), indent_column, (size_t)X); \ + indent_column = (X); \ + } while (false) + + +static size_t get_indent_first_continue(Chunk *pc) +{ + log_rule_B("indent_ignore_first_continue"); + Chunk *continuation = pc->GetNextType(CT_NEWLINE, pc->GetLevel()); + + if (continuation->IsNotNullChunk()) + { + continuation = continuation->GetNext(); + + if (continuation->IsNotNullChunk()) + { + return(continuation->GetOrigCol()); + } + } + return(0); +} + + +static size_t calc_indent_continue(const ParseFrame &frm, size_t pse_tos) +{ + log_rule_B("indent_continue"); + const int ic = options::indent_continue(); + + if ( ic < 0 + && frm.at(pse_tos).indent_cont) + { + return(frm.at(pse_tos).indent); + } + return(frm.at(pse_tos).indent + abs(ic)); +} + + +static size_t calc_indent_continue(const ParseFrame &frm) +{ + return(calc_indent_continue(frm, frm.size() - 1)); +} + + +static Chunk *candidate_chunk_first_on_line(Chunk *pc) +{ + Chunk *first = pc->GetFirstChunkOnLine(); + + log_rule_B("indent_inside_ternary_operator"); + + if ( options::indent_inside_ternary_operator() + && ( first->Is(CT_QUESTION) + || first->Is(CT_COND_COLON))) + { + return(first->GetNextNcNnl()); + } + else + { + return(first); + } +} + + +static Chunk *oc_msg_block_indent(Chunk *pc, bool from_brace, + bool from_caret, bool from_colon, + bool from_keyword) +{ + LOG_FUNC_ENTRY(); + Chunk *tmp = Chunk::NullChunkPtr; + + if (pc != nullptr) + { + tmp = pc->GetPrevNc(); + } + + if (from_brace) + { + return(pc); + } + + // Skip to open paren in ':^TYPE *(ARGS) {' + if (tmp->IsParenClose()) + { + tmp = tmp->GetOpeningParen()->GetPrevNc(); + } + + // // Check for star in ':^TYPE *(ARGS) {'. Issue 2477 + if (tmp->Is(CT_PTR_TYPE)) + { + tmp = tmp->GetPrevNc(); + } + + // Check for type in ':^TYPE *(ARGS) {'. Issue 2482 + if (tmp->Is(CT_TYPE)) + { + tmp = tmp->GetPrevNc(); + } + // Check for caret in ':^TYPE *(ARGS) {' + // Store the caret position + Chunk *caret_tmp = Chunk::NullChunkPtr; + + if ( tmp->IsNotNullChunk() + && tmp->GetType() == CT_OC_BLOCK_CARET) + { + caret_tmp = tmp; + } + else + { + caret_tmp = tmp->GetPrevType(CT_OC_BLOCK_CARET); + tmp = caret_tmp; + } + + // If we still cannot find caret then return first chunk on the line + if ( tmp->IsNullChunk() + || tmp->IsNot(CT_OC_BLOCK_CARET)) + { + return(candidate_chunk_first_on_line(pc)); + } + + if (from_caret) + { + return(tmp); + } + tmp = tmp->GetPrevNc(); + + // Check for colon in ':^TYPE *(ARGS) {' + if (from_colon) + { + if ( tmp->IsNullChunk() + || tmp->IsNot(CT_OC_COLON)) + { + return(candidate_chunk_first_on_line(pc)); + } + else + { + return(tmp); + } + } + tmp = tmp->GetPrevNc(); + + if (from_keyword) + { + if ( tmp->IsNullChunk() + || ( tmp->IsNot(CT_OC_MSG_NAME) + && tmp->IsNot(CT_OC_MSG_FUNC))) + { + return(candidate_chunk_first_on_line(pc)); + } + else + { + return(tmp); + } + } + // In almost all the cases, its better to return the first chunk on the line than not indenting at all. + tmp = candidate_chunk_first_on_line(pc); + return(tmp); +} // oc_msg_block_indent + + +#define log_indent() \ + do { _log_indent(__func__, __LINE__, frm); \ + } while (false) + + +static void _log_indent(const char *func, const uint32_t line, const ParseFrame &frm) +{ + LOG_FMT(LINDLINE, "%s(%d): frm.pse_tos is %zu, ...indent is %zu\n", + func, line, frm.size() - 1, frm.top().indent); +} + + +#define log_prev_indent() \ + do { _log_prev_indent(__func__, __LINE__, frm); \ + } while (false) + + +static void _log_prev_indent(const char *func, const uint32_t line, const ParseFrame &frm) +{ + LOG_FMT(LINDLINE, "%s(%d): frm.pse_tos is %zu, prev....indent is %zu\n", + func, line, frm.size() - 1, frm.prev().indent); +} + + +#define log_indent_tmp() \ + do { _log_indent_tmp(__func__, __LINE__, frm); \ + } while (false) + + +static void _log_indent_tmp(const char *func, const uint32_t line, const ParseFrame &frm) +{ + LOG_FMT(LINDLINE, "%s(%d): frm.pse_tos is %zu, ...indent_tmp is %zu\n", + func, line, frm.size() - 1, frm.top().indent_tmp); +} + + +static void quick_indent_again() +{ + LOG_FUNC_ENTRY(); + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if (pc->GetIndentData().ref == nullptr) + { + continue; + } + Chunk *tmp = pc->GetPrev(); + + if (!tmp->IsNewline()) + { + continue; + } + const size_t col = pc->GetIndentData().ref->GetColumn() + pc->GetIndentData().delta; + indent_to_column(pc, col); + + LOG_FMT(LINDENTAG, "%s(%d): [%zu] indent [%s] to %zu based on [%s] @ %zu:%zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->Text(), col, + pc->GetIndentData().ref->Text(), pc->GetIndentData().ref->GetOrigLine(), + pc->GetIndentData().ref->GetColumn()); + } +} + + +void indent_text() +{ + LOG_FUNC_ENTRY(); + bool did_newline = true; + size_t vardefcol = 0; + + log_rule_B("indent_columns"); + const size_t indent_size = options::indent_columns(); + size_t indent_column = 0; + int xml_indent = 0; + size_t sql_col = 0; + size_t sql_orig_col = 0; + bool in_func_def = false; + + + std::vector<ParseFrame> frames; + ParseFrame frm{}; + + + Chunk *pc = Chunk::GetHead(); + bool classFound = false; // Issue #672 + + while ( pc != nullptr + && pc->IsNotNullChunk()) + { + LOG_CHUNK(LINDLINE, pc); + // forces string literal to column-1 [Fix for 1246] + log_rule_B("indent_col1_multi_string_literal"); + + if ( (pc->GetType() == CT_STRING_MULTI) + && !(cpd.lang_flags & LANG_OC) // Issue #1795 + && options::indent_col1_multi_string_literal()) + { + string str = pc->Text(); + + if ( (str[0] == '@') + && (pc->GetPrev()->GetType() == CT_NEWLINE)) + { + indent_column_set(1); + reindent_line(pc, indent_column); + pc = pc->GetNext(); + did_newline = false; + } + } + + if (pc->Is(CT_NEWLINE)) + { + LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, <Newline>\n", + __func__, __LINE__, pc->GetOrigLine()); + } + else if (pc->Is(CT_NL_CONT)) + { + LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, CT_NL_CONT\n", + __func__, __LINE__, pc->GetOrigLine()); + } + else + { + char copy[1000]; + LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, orig col is %zu, column is %zu, for '%s'\n ", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->GetColumn(), pc->ElidedText(copy)); + log_pcf_flags(LINDLINE, pc->GetFlags()); + } + log_rule_B("use_options_overriding_for_qt_macros"); + + if ( options::use_options_overriding_for_qt_macros() + && ( strcmp(pc->Text(), "SIGNAL") == 0 + || strcmp(pc->Text(), "SLOT") == 0)) + { + LOG_FMT(LINDLINE, "%s(%d): orig line=%zu: type %s SIGNAL/SLOT found\n", + __func__, __LINE__, pc->GetOrigLine(), get_token_name(pc->GetType())); + } + // Handle preprocessor transitions + log_rule_B("indent_brace_parent"); + const size_t parent_token_indent = (options::indent_brace_parent()) + ? token_indent(pc->GetParentType()) : 0; + + // Handle "force indentation of function definition to start in column 1" + log_rule_B("indent_func_def_force_col1"); + + if (options::indent_func_def_force_col1()) + { + if (!in_func_def) + { + Chunk *next = pc->GetNextNcNnl(); + + if ( pc->GetParentType() == CT_FUNC_DEF + || ( pc->Is(CT_COMMENT) + && next->IsNotNullChunk() + && next->GetParentType() == CT_FUNC_DEF)) + { + in_func_def = true; + frm.push(pc, __func__, __LINE__); + frm.top().indent_tmp = 1; + frm.top().indent = 1; + frm.top().indent_tab = 1; + } + } + else + { + Chunk *prev = pc->GetPrev(); + + if ( prev->Is(CT_BRACE_CLOSE) + && prev->GetParentType() == CT_FUNC_DEF) + { + in_func_def = false; + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + } + } + // Clean up after a #define, etc + const bool in_preproc = pc->TestFlags(PCF_IN_PREPROC); + + if (!in_preproc) + { + while ( !frm.empty() + && frm.top().in_preproc) + { + const E_Token type = frm.top().type; + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + + /* + * If we just removed an #endregion, then check to see if a + * PP_REGION_INDENT entry is right below it + */ + if ( type == CT_PP_ENDREGION + && frm.top().type == CT_PP_REGION_INDENT) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + } + } + else if (pc->Is(CT_PREPROC)) // # + { + // Close out PP_IF_INDENT before playing with the parse frames + if ( frm.top().type == CT_PP_IF_INDENT + && ( pc->GetParentType() == CT_PP_ENDIF + || pc->GetParentType() == CT_PP_ELSE)) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + ParseFrame frmbkup = frm; + fl_check(frames, frm, cpd.pp_level, pc); + + // Indent the body of a #region here + log_rule_B("pp_region_indent_code"); + + if ( options::pp_region_indent_code() + && pc->GetParentType() == CT_PP_REGION) + { + Chunk *next = pc->GetNext(); + + if (next->IsNullChunk()) + { + break; + } + // Hack to get the logs to look right + next->SetType(CT_PP_REGION_INDENT); + frm.push(next, __func__, __LINE__); + next->SetType(CT_PP_REGION); + + // Indent one level + frm.top().indent = frm.prev().indent + indent_size; + log_indent(); + + frm.top().indent_tab = frm.prev().indent_tab + indent_size; + frm.top().indent_tmp = frm.top().indent; + frm.top().in_preproc = false; + log_indent_tmp(); + } + // If option set, remove indent inside switch statement + log_rule_B("indent_switch_pp"); + + if ( frm.top().type == CT_CASE + && !options::indent_switch_pp()) + { + frm.push(pc, __func__, __LINE__); + LOG_FMT(LINDPC, "%s(%d): frm.top().indent is %zu, indent_size is %zu\n", + __func__, __LINE__, frm.top().indent, indent_size); + + if (frm.top().indent >= indent_size) + { + frm.prev().indent = frm.top().indent - indent_size; + } + log_prev_indent(); + } + // Indent the body of a #if here + log_rule_B("pp_if_indent_code"); + + if ( options::pp_if_indent_code() + && ( pc->GetParentType() == CT_PP_IF + || pc->GetParentType() == CT_PP_ELSE)) + { + Chunk *next = pc->GetNext(); + + if (next->IsNullChunk()) + { + break; + } + int should_indent_preproc = true; + int should_ignore_preproc = false; + Chunk *preproc_next = pc->GetNextNl(); + preproc_next = preproc_next->GetNextNcNnlNet(); + + /* Look ahead at what's on the line after the #if */ + log_rule_B("pp_indent_brace"); + log_rule_B("pp_indent_func_def"); + log_rule_B("pp_indent_case"); + log_rule_B("pp_indent_extern"); + + while ( preproc_next->IsNotNullChunk() + && preproc_next->IsNot(CT_NEWLINE)) + { + if ( (preproc_next->Is(CT_BRACE_OPEN)) + || (preproc_next->Is(CT_BRACE_CLOSE))) + { + if (options::pp_indent_brace() == 0) + { + should_indent_preproc = false; + break; + } + else if (options::pp_indent_brace() == -1) + { + should_ignore_preproc = true; + break; + } + } + else if ( ( preproc_next->Is(CT_FUNC_DEF) + && !options::pp_indent_func_def()) + || ( preproc_next->Is(CT_CASE) + && !options::pp_indent_case()) + || ( preproc_next->Is(CT_EXTERN) + && !options::pp_indent_extern())) + { + should_indent_preproc = false; + break; + } + preproc_next = preproc_next->GetNext(); + } + + if (should_indent_preproc) + { + // Hack to get the logs to look right + + const E_Token memtype = next->GetType(); + next->SetType(CT_PP_IF_INDENT); + frm.push(next, __func__, __LINE__); + next->SetType(memtype); + + if (should_ignore_preproc) + { + // Preserve original indentation + frm.top().indent = pc->GetNextNl()->GetNext()->GetOrigCol(); + log_indent(); + } + else + { + // Indent one level except if the #if is a #include guard + size_t extra = ( pc->GetPpLevel() == 0 + && ifdef_over_whole_file()) + ? 0 : indent_size; + + frm.top().indent = frm.prev().indent + extra; + log_indent(); + + frm.top().indent_tab = frm.prev().indent_tab + extra; + } + frm.top().indent_tmp = frm.top().indent; + frm.top().in_preproc = false; + log_indent_tmp(); + } + } + log_rule_B("indent_member_single"); + + if (options::indent_member_single()) + { + if (pc->GetParentType() == CT_PP_IF) + { + // do nothing + } + else if (pc->GetParentType() == CT_PP_ELSE) + { + if ( frm.top().type == CT_MEMBER + && frm.top().pop_pc->IsNotNullChunk() + && frm.top().pc != frmbkup.top().pc) + { + Chunk *tmp = pc->GetNextNcNnlNpp(); + + if (tmp->IsNotNullChunk()) + { + if ( tmp->Is(CT_WORD) + || tmp->Is(CT_TYPE)) + { + tmp = pc->GetNextNcNnlNpp(); + } + else if ( tmp->Is(CT_FUNC_CALL) + || tmp->Is(CT_FPAREN_OPEN)) + { + tmp = tmp->GetNextType(CT_FPAREN_CLOSE, tmp->GetLevel()); + + if (tmp->IsNotNullChunk()) + { + tmp = pc->GetNextNcNnlNpp(); + } + } + + if (tmp->IsNotNullChunk()) + { + frm.top().pop_pc = tmp; + } + } + } + } + else if (pc->GetParentType() == CT_PP_ENDIF) + { + if ( frmbkup.top().type == CT_MEMBER + && frm.top().type == CT_MEMBER) + { + frm.top().pop_pc = frmbkup.top().pop_pc; + } + } + } + // Transition into a preproc by creating a dummy indent + Chunk *pp_next = pc->GetNext(); + + if (pp_next->IsNullChunk()) + { + return; + } + frm.push(pp_next, __func__, __LINE__); + + if ( pc->GetParentType() == CT_PP_DEFINE + || pc->GetParentType() == CT_PP_UNDEF) + { + log_rule_B("pp_define_at_level"); + frm.top().indent_tmp = options::pp_define_at_level() + ? frm.prev().indent_tmp : 1; + + log_rule_B("pp_multiline_define_body_indent"); + + if (options::pp_multiline_define_body_indent() < 0) + { + frm.top().indent = -options::pp_multiline_define_body_indent(); + } + else + { + frm.top().indent = pc->GetColumn() + options::pp_multiline_define_body_indent(); + } + log_indent(); + + frm.top().indent_tab = frm.top().indent; + log_indent_tmp(); + } + else if ( ( pc->GetParentType() == CT_PP_PRAGMA + || pc->GetParentType() == CT_PP_OTHER) + && options::pp_define_at_level()) + { + log_rule_B("pp_define_at_level"); + frm.top().indent_tmp = frm.prev().indent_tmp; + frm.top().indent = frm.top().indent_tmp + indent_size; + log_indent(); + + frm.top().indent_tab = frm.top().indent; + log_indent_tmp(); + } + else if ( pc->GetParentType() == CT_PP_INCLUDE + && options::pp_include_at_level()) + { + log_rule_B("pp_include_at_level"); + frm.top().indent_tmp = frm.prev().indent_tmp; + frm.top().indent = frm.top().indent_tmp + indent_size; + log_indent(); + + frm.top().indent_tab = frm.top().indent; + log_indent_tmp(); + } + else + { + if ( (frm.prev().type == CT_PP_REGION_INDENT) + || ( (frm.prev().type == CT_PP_IF_INDENT) + && (frm.top().type != CT_PP_ENDIF))) + { + frm.top().indent = frm.prev(2).indent; + log_indent(); + } + else + { + frm.top().indent = frm.prev().indent; + log_indent(); + } + log_indent(); + + + int val = 0; + + if ( pc->GetParentType() == CT_PP_REGION + || pc->GetParentType() == CT_PP_ENDREGION) + { + log_rule_B("pp_indent_region"); + val = options::pp_indent_region(); + log_indent(); + } + else if ( pc->GetParentType() == CT_PP_IF + || pc->GetParentType() == CT_PP_ELSE + || pc->GetParentType() == CT_PP_ENDIF) + { + log_rule_B("pp_indent_if"); + val = options::pp_indent_if(); + log_indent(); + } + + if (val != 0) + { + size_t &indent = frm.top().indent; + + indent = (val > 0) ? val // reassign if positive val, + : ((size_t)(abs(val)) < indent) // else if no underflow + ? (indent + val) : 0; // reduce, else 0 + } + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + } + } + // Check for close XML tags "</..." + log_rule_B("indent_xml_string"); + + if (options::indent_xml_string() > 0) + { + if (pc->Is(CT_STRING)) + { + if ( pc->Len() > 4 + && xml_indent > 0 + && pc->GetStr()[1] == '<' + && pc->GetStr()[2] == '/') + { + log_rule_B("indent_xml_string"); + xml_indent -= options::indent_xml_string(); + } + } + else if (!pc->IsCommentOrNewline()) + { + xml_indent = 0; + } + } + // Handle non-brace closures + log_indent_tmp(); + + bool token_used = false; + size_t old_frm_size; + + do + { + old_frm_size = frm.size(); + + // End anything that drops a level + if ( !pc->IsCommentOrNewline() + && frm.top().level > pc->GetLevel()) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + + if (frm.top().level >= pc->GetLevel()) + { + // process virtual braces closes (no text output) + if ( pc->Is(CT_VBRACE_CLOSE) + && frm.top().type == CT_VBRACE_OPEN) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + pc = pc->GetNext(); + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + + if (pc->IsNullChunk()) + { + // need to break out of both the do and while loops + goto null_pc; + } + } + + if ( pc->Is(CT_BRACE_CLOSE) + && pc->GetParentType() == CT_ENUM) + { + Chunk *prev_ncnl = pc->GetPrevNcNnl(); + LOG_FMT(LINDLINE, "%s(%d): prev_ncnl is '%s', orig line is %zu, orig col is %zu\n", + __func__, __LINE__, prev_ncnl->Text(), prev_ncnl->GetOrigLine(), prev_ncnl->GetOrigCol()); + + if (prev_ncnl->Is(CT_COMMA)) + { + LOG_FMT(LINDLINE, "%s(%d): prev_ncnl is comma\n", __func__, __LINE__); + } + else + { + LOG_FMT(LINDLINE, "%s(%d): prev_ncnl is NOT comma\n", __func__, __LINE__); + } + } + + // End any assign operations with a semicolon on the same level + if (is_end_of_assignment(pc, frm)) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + // Pop Colon from stack in ternary operator + // a + // ? b + // : e/*top*/;/*pc*/ + log_rule_B("indent_inside_ternary_operator"); + + if ( options::indent_inside_ternary_operator() + && (frm.top().type == CT_COND_COLON) + && ( pc->IsSemicolon() + || pc->Is(CT_COMMA) + || pc->Is(CT_OC_MSG_NAME) + || pc->Is(CT_SPAREN_CLOSE))) // Issue #1130, #1715 + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + + // End any assign operations with a semicolon on the same level + if ( pc->IsSemicolon() + && ( (frm.top().type == CT_IMPORT) + || (frm.top().type == CT_USING))) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + + // End any custom macro-based open/closes + if ( !token_used + && (frm.top().type == CT_MACRO_OPEN) + && pc->Is(CT_MACRO_CLOSE)) + { + token_used = true; + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + + // End any CPP/ObjC class colon stuff + if ( ( (frm.top().type == CT_CLASS_COLON) + || (frm.top().type == CT_CONSTR_COLON)) + && ( pc->Is(CT_BRACE_OPEN) + || pc->Is(CT_OC_END) + || pc->Is(CT_OC_SCOPE) + || pc->Is(CT_OC_PROPERTY) + || pc->Is(CT_TYPEDEF) // Issue #2675 + || pc->Is(CT_MACRO_OPEN) + || pc->Is(CT_MACRO_CLOSE) + || ( language_is_set(LANG_OC) + && pc->IsComment() + && pc->GetParentType() == CT_COMMENT_WHOLE) // Issue #2675 + || pc->IsSemicolon())) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + + // End ObjC class colon stuff inside of generic definition (like Test<T1: id<T3>>) + if ( (frm.top().type == CT_CLASS_COLON) + && pc->Is(CT_ANGLE_CLOSE) + && pc->GetParentType() == CT_OC_GENERIC_SPEC) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + + // End Objc nested message and boxed array + // TODO: ideally formatting would know which opens occurred on a line and group closes in the same manor + if ( language_is_set(LANG_OC) + && pc->Is(CT_SQUARE_CLOSE) + && pc->GetParentType() == CT_OC_AT + && frm.top().level >= pc->GetLevel()) + { + size_t count = 1; + Chunk *next = pc->GetNextNc(); + + while ( next->IsNotNullChunk() + && ( ( next->Is(CT_BRACE_CLOSE) + && next->GetParentType() == CT_OC_AT) + || ( next->Is(CT_SQUARE_CLOSE) + && next->GetParentType() == CT_OC_AT) + || ( next->Is(CT_SQUARE_CLOSE) + && next->GetParentType() == CT_OC_MSG))) + { + count++; + next = next->GetNextNc(); + } + count = std::min(count, frm.size()); + + if (count > 0) + { + while (count-- > 0) + { + if (frm.top().type == CT_SQUARE_OPEN) + { + if (frm.paren_count == 0) + { + fprintf(stderr, "%s(%d): frm.paren_count is ZERO, cannot be decremented, at line %zu, column %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + frm.paren_count--; + } + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + + if (next) + { + // End any assign operations with a semicolon on the same level + if (is_end_of_assignment(next, frm)) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + } + // Indent the brace to match outer most brace/square + indent_column_set(frm.top().indent_tmp); + continue; + } + } + + // a case is ended with another case or a close brace + if ( (frm.top().type == CT_CASE) + && ( pc->Is(CT_BRACE_CLOSE) + || pc->Is(CT_CASE))) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + + if (frm.top().pop_pc->IsNotNullChunk()) + { + LOG_FMT(LINDLINE, "%s(%d): pop_pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, frm.top().pop_pc->GetOrigLine(), frm.top().pop_pc->GetOrigCol(), + frm.top().pop_pc->Text(), get_token_name(frm.top().pop_pc->GetType())); + } + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + + if ( (frm.top().type == CT_MEMBER) + && frm.top().pop_pc == pc) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + + if ( (frm.top().type == CT_LAMBDA) + && ( pc->Is(CT_SEMICOLON) + || pc->Is(CT_COMMA) + || pc->Is(CT_BRACE_OPEN))) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + // a class scope is ended with another class scope or a close brace + log_rule_B("indent_access_spec_body"); + + if ( options::indent_access_spec_body() + && (frm.top().type == CT_ACCESS) + && ( pc->Is(CT_BRACE_CLOSE) + || pc->Is(CT_ACCESS))) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + + // return & throw are ended with a semicolon + if ( pc->IsSemicolon() + && ( (frm.top().type == CT_RETURN) + || (frm.top().type == CT_THROW))) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + + // an OC SCOPE ('-' or '+') ends with a semicolon or brace open + if ( (frm.top().type == CT_OC_SCOPE) + && ( pc->IsSemicolon() + || pc->Is(CT_BRACE_OPEN))) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + + /* + * a typedef and an OC SCOPE ('-' or '+') ends with a semicolon or + * brace open + */ + if ( (frm.top().type == CT_TYPEDEF) + && ( pc->IsSemicolon() + || pc->IsParenOpen() + || pc->Is(CT_BRACE_OPEN))) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + + // an SQL EXEC is ended with a semicolon + if ( (frm.top().type == CT_SQL_EXEC) + && pc->IsSemicolon()) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + + // an CLASS is ended with a semicolon or brace open + if ( (frm.top().type == CT_CLASS) + && ( pc->Is(CT_CLASS_COLON) + || pc->Is(CT_BRACE_OPEN) + || pc->IsSemicolon())) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + log_rule_B("indent_oc_inside_msg_sel"); + + // Pop OC msg selector stack + if ( options::indent_oc_inside_msg_sel() + && (frm.top().type != CT_SQUARE_OPEN) + && frm.top().level >= pc->GetLevel() + && ( pc->Is(CT_OC_MSG_FUNC) + || pc->Is(CT_OC_MSG_NAME))) // Issue #2658 + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + + // Close out parenthesis and squares + if ( (frm.top().type == (pc->GetType() - 1)) + && ( pc->Is(CT_PAREN_CLOSE) + || pc->Is(CT_LPAREN_CLOSE) // Issue #3054 + || pc->Is(CT_SPAREN_CLOSE) + || pc->Is(CT_FPAREN_CLOSE) + || pc->Is(CT_SQUARE_CLOSE) + || pc->Is(CT_ANGLE_CLOSE))) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + + if (frm.paren_count == 0) + { + fprintf(stderr, "%s(%d): frm.paren_count is ZERO, cannot be decremented, at line %zu, column %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + frm.paren_count--; + } + } + } while (old_frm_size > frm.size()); + + // Grab a copy of the current indent + indent_column_set(frm.top().indent_tmp); // Issue #3294 + log_indent_tmp(); + + log_rule_B("indent_single_newlines"); + + if ( pc->Is(CT_NEWLINE) + && options::indent_single_newlines()) + { + pc->SetNlColumn(indent_column); + } + + if ( !pc->IsCommentOrNewline() + && log_sev_on(LINDPC)) + { + LOG_FMT(LINDPC, "%s(%d):\n", __func__, __LINE__); + LOG_FMT(LINDPC, " -=[ pc orig line is %zu, orig col is %zu, Text() is '%s' ]=-, frm.size() is %zu\n", + pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), frm.size()); + + for (size_t ttidx = frm.size() - 1; ttidx > 0; ttidx--) + { + LOG_FMT(LINDPC, " [%zu %zu:%zu '%s' %s/%s tmp=%zu indent=%zu brace_indent=%zu indent_tab=%zu indent_cont=%d level=%zu pc brace level=%zu]\n", + ttidx, + frm.at(ttidx).pc->GetOrigLine(), + frm.at(ttidx).pc->GetOrigCol(), + frm.at(ttidx).pc->Text(), + get_token_name(frm.at(ttidx).type), + get_token_name(frm.at(ttidx).pc->GetParentType()), + frm.at(ttidx).indent_tmp, + frm.at(ttidx).indent, + frm.at(ttidx).brace_indent, + frm.at(ttidx).indent_tab, + frm.at(ttidx).indent_cont, + frm.at(ttidx).level, + frm.at(ttidx).pc->GetBraceLevel()); + } + } + char copy[1000]; + LOG_FMT(LINDENT2, "%s(%d): orig line is %zu, orig col is %zu, column is %zu, Text() is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->GetColumn(), pc->ElidedText(copy)); + + // Issue #672 + if ( pc->Is(CT_BRACE_OPEN) + && classFound) + { + LOG_FMT(LINDENT, "%s(%d): CT_BRACE_OPEN found, CLOSE IT\n", + __func__, __LINE__); + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + classFound = false; + } + /* + * Handle stuff that can affect the current indent: + * - brace close + * - vbrace open + * - brace open + * - case (immediate) + * - labels (immediate) + * - class colons (immediate) + * + * And some stuff that can't + * - open paren + * - open square + * - assignment + * - return + */ + log_rule_B("indent_braces"); + log_rule_B("indent_braces_no_func"); + log_rule_B("indent_braces_no_class"); + log_rule_B("indent_braces_no_struct"); + const bool brace_indent = ( ( pc->Is(CT_BRACE_CLOSE) + || pc->Is(CT_BRACE_OPEN)) + && options::indent_braces() + && ( !options::indent_braces_no_func() + || pc->GetParentType() != CT_FUNC_DEF) + && ( !options::indent_braces_no_func() + || pc->GetParentType() != CT_FUNC_CLASS_DEF) + && ( !options::indent_braces_no_class() + || pc->GetParentType() != CT_CLASS) + && ( !options::indent_braces_no_struct() + || pc->GetParentType() != CT_STRUCT)); + LOG_FMT(LINDENT, "%s(%d): brace_indent is %s\n", + __func__, __LINE__, brace_indent ? "true" : "false"); + + if (pc->Is(CT_BRACE_CLOSE)) + { + if (language_is_set(LANG_OC)) + { + if ( frm.top().type == CT_BRACE_OPEN + && frm.top().level >= pc->GetLevel()) + { + size_t count = 1; + Chunk *next = pc->GetNextNc(); + + while ( next->IsNotNullChunk() + && ( ( next->Is(CT_BRACE_CLOSE) + && next->GetParentType() == CT_OC_AT) + || ( next->Is(CT_SQUARE_CLOSE) + && next->GetParentType() == CT_OC_AT))) + { + count++; + next = next->GetNextNc(); + } + count = std::min(count, frm.size()); + + // End Objc nested boxed dictionary + // TODO: ideally formatting would know which opens occurred on a line and group closes in the same manor + if ( count > 0 + && pc->Is(CT_BRACE_CLOSE) + && pc->GetParentType() == CT_OC_AT) + { + if (frm.top().ip.ref) + { + pc->IndentData().ref = frm.top().ip.ref; + pc->IndentData().delta = 0; + } + + while (count-- > 0) + { + LOG_CHUNK(LINDLINE, pc); + frm.pop(__func__, __LINE__, pc); + } + + if (next) + { + // End any assign operations with a semicolon on the same level + if (is_end_of_assignment(next, frm)) + { + LOG_CHUNK(LINDLINE, pc); + frm.pop(__func__, __LINE__, pc); + } + } + + // Indent the brace to match outer most brace/square + if (frm.top().indent_cont) + { + indent_column_set(frm.top().indent_tmp - indent_size); + } + else + { + indent_column_set(frm.top().indent_tmp); + } + } + else + { + // Indent the brace to match the open brace + indent_column_set(frm.top().brace_indent); + + if (frm.top().ip.ref) + { + pc->IndentData().ref = frm.top().ip.ref; + pc->IndentData().delta = 0; + } + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + } + } + else if (frm.top().brace_indent) // Issue #3421 + { + // Indent the brace to match the open brace + indent_column_set(frm.top().brace_indent); + + if (frm.top().ip.ref) + { + pc->IndentData().ref = frm.top().ip.ref; + pc->IndentData().delta = 0; + } + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + } + else if (pc->Is(CT_VBRACE_OPEN)) + { + frm.push(pc, __func__, __LINE__); + + log_rule_B("indent_min_vbrace_open"); + size_t iMinIndent = options::indent_min_vbrace_open(); + + if (indent_size > iMinIndent) + { + iMinIndent = indent_size; + } + size_t iNewIndent = frm.prev().indent + iMinIndent; + + log_rule_B("indent_vbrace_open_on_tabstop"); + + if (options::indent_vbrace_open_on_tabstop()) + { + iNewIndent = next_tab_column(iNewIndent); + } + frm.top().indent = iNewIndent; + log_indent(); + frm.top().indent_tmp = frm.top().indent; + frm.top().indent_tab = frm.top().indent; + log_indent_tmp(); + + // Always indent on virtual braces + indent_column_set(frm.top().indent_tmp); + } + else if ( pc->Is(CT_BRACE_OPEN) + && pc->GetNext()->IsNot(CT_NAMESPACE)) + { + LOG_FMT(LINDENT2, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + frm.push(pc, __func__, __LINE__); + + log_rule_B("indent_macro_brace"); + + if ( !options::indent_macro_brace() + && frm.prev().type == CT_PP_DEFINE + && frm.prev().open_line == frm.top().open_line) + { + LOG_FMT(LINDENT2, "%s(%d): indent_macro_brace\n", __func__, __LINE__); + } + else if ( options::indent_cpp_lambda_body() + && pc->GetParentType() == CT_CPP_LAMBDA) + { + log_rule_B("indent_cpp_lambda_body"); + frm.top().brace_indent = frm.prev().indent; + + Chunk *head = frm.top().pc->GetPrevNcNnlNpp(); + Chunk *tail = Chunk::NullChunkPtr; + Chunk *frm_prev = frm.prev().pc; + bool enclosure = ( frm_prev->GetParentType() != CT_FUNC_DEF // Issue #3407 + && frm_prev != frm_prev->GetClosingParen()); + bool linematch = true; + + for (auto it = frm.rbegin(); it != frm.rend() && tail->IsNullChunk(); ++it) + { + if (it->pc && it->pc != frm.top().pc) + { + linematch &= it->pc->IsOnSameLine(head); + } + Chunk *match = it->pc->GetClosingParen(); + + if (match->IsNullChunk()) + { + continue; + } + Chunk *target = match->GetNextNcNnlNpp(); + + while ( tail->IsNullChunk() + && target->IsNotNullChunk()) + { + if ( target->IsSemicolon() + && target->GetLevel() == match->GetLevel()) + { + tail = target; + } + else if (target->GetLevel() < match->GetLevel()) + { + break; + } + else + { + target = target->GetNextNcNnlNpp(); + } + } + } + + bool toplevel = true; + + for (auto it = frm.rbegin(); it != frm.rend() && tail->IsNotNullChunk(); ++it) + { + if (!it->pc->Is(CT_FPAREN_OPEN)) + { + continue; + } + + if (it->pc->GetLevel() < tail->GetLevel()) + { + toplevel = false; + break; + } + } + + // A few things to check: + // 1. The matching brace is on the same line as the ending semicolon + // 2a. If it's an assignment, check that both sides of the assignment operator are on the same line + // 2b. If it's inside some closure, check that all the frames are on the same line, + // and it is in the top level closure, and indent_continue is non-zero + bool sameLine = frm.top().pc->GetClosingParen()->IsOnSameLine(tail); + + bool isAssignSameLine = + !enclosure + && options::align_assign_span() == 0 + && !options::indent_align_assign() + && frm.prev().pc->GetPrevNcNnlNpp()->IsOnSameLine(frm.prev().pc) + && frm.prev().pc->IsOnSameLine(frm.prev().pc->GetNextNcNnlNpp()); + + bool closureSameLineTopLevel = + (options::indent_continue() > 0) + && enclosure + && linematch + && toplevel + && frm.top().pc->GetClosingParen()->IsOnSameLine(frm.top().pc); + + if (sameLine && ((isAssignSameLine) || (closureSameLineTopLevel))) + { + if (indent_size > frm.top().brace_indent) // if options::indent_indent_columns() is too big + { + frm.top().brace_indent = 1; + } + else + { + frm.top().brace_indent -= indent_size; + } + } + indent_column_set(frm.top().brace_indent); + frm.top().indent = indent_column + indent_size; + log_indent(); + + frm.top().indent_tab = frm.top().indent; + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + + frm.prev().indent_tmp = frm.top().indent_tmp; + log_indent_tmp(); + } + else if ( language_is_set(LANG_CPP) + && options::indent_cpp_lambda_only_once() + && (pc->GetParentType() == CT_CPP_LAMBDA)) + { + // test example cpp:30756 + log_rule_B("indent_cpp_lambda_only_once"); + + size_t namespace_indent_to_ignore = 0; // Issue #1813 + log_rule_B("indent_namespace"); + + if (!options::indent_namespace()) + { + for (auto i = frm.rbegin(); i != frm.rend(); ++i) + { + if (i->ns_cnt) + { + namespace_indent_to_ignore = i->ns_cnt; + break; + } + } + } + // Issue # 1296 + frm.top().brace_indent = 1 + ((pc->GetBraceLevel() - namespace_indent_to_ignore) * indent_size); + indent_column_set(frm.top().brace_indent); + frm.top().indent = indent_column + indent_size; + log_indent(); + frm.top().indent_tab = frm.top().indent; + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + + frm.prev().indent_tmp = frm.top().indent_tmp; + log_indent_tmp(); + } + else if ( language_is_set(LANG_CS | LANG_JAVA) + && options::indent_cs_delegate_brace() + && ( pc->GetParentType() == CT_LAMBDA + || pc->GetParentType() == CT_DELEGATE)) + { + log_rule_B("indent_cs_delegate_brace"); + frm.top().brace_indent = 1 + ((pc->GetBraceLevel() + 1) * indent_size); + indent_column_set(frm.top().brace_indent); + frm.top().indent = indent_column + indent_size; + log_indent(); + frm.top().indent_tab = frm.top().indent; + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + + frm.prev().indent_tmp = frm.top().indent_tmp; + log_indent_tmp(); + } + else if ( language_is_set(LANG_CS | LANG_JAVA) + && !options::indent_cs_delegate_brace() + && !options::indent_align_paren() + && ( pc->GetParentType() == CT_LAMBDA + || pc->GetParentType() == CT_DELEGATE)) + { + log_rule_B("indent_cs_delegate_brace"); + log_rule_B("indent_align_paren"); + frm.top().brace_indent = frm.prev().indent; + + // Issue # 1620, UNI-24090.cs + if (frm.prev().pc->IsOnSameLine(frm.top().pc->GetPrevNcNnlNpp())) + { + frm.top().brace_indent -= indent_size; + } + indent_column_set(frm.top().brace_indent); + frm.top().indent = indent_column + indent_size; + log_indent(); + frm.top().indent_tab = frm.top().indent; + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + frm.prev().indent_tmp = frm.top().indent_tmp; + log_indent_tmp(); + } + else if ( !options::indent_paren_open_brace() + && !language_is_set(LANG_CS) + && pc->GetParentType() == CT_CPP_LAMBDA + && ( pc->TestFlags(PCF_IN_FCN_DEF) + || pc->TestFlags(PCF_IN_FCN_CTOR)) // Issue #2152 + && pc->GetNextNc()->IsNewline()) + { + log_rule_B("indent_paren_open_brace"); + // Issue #1165 + LOG_FMT(LINDENT2, "%s(%d): orig line is %zu, brace level is %zu, for '%s', pc->GetLevel() is %zu, pc(-1)->GetLevel() is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetBraceLevel(), pc->Text(), pc->GetLevel(), frm.prev().pc->GetLevel()); + frm.top().brace_indent = 1 + ((pc->GetBraceLevel() + 1) * indent_size); + indent_column_set(frm.top().brace_indent); + frm.top().indent = frm.prev().indent_tmp; + log_indent(); + + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + } + // any '{' that is inside of a '(' overrides the '(' indent + // only to help the vim command } + else if ( !options::indent_paren_open_brace() + && frm.prev().pc->IsParenOpen() + && pc->GetNextNc()->IsNewline()) + { + log_rule_B("indent_paren_open_brace"); + LOG_FMT(LINDENT2, "%s(%d): orig line is %zu, brace level is %zu, for '%s', pc->GetLevel() is %zu, pc(-1)->GetLevel() is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetBraceLevel(), pc->Text(), pc->GetLevel(), frm.prev().pc->GetLevel()); + // FIXME: I don't know how much of this is necessary, but it seems to work + frm.top().brace_indent = 1 + (pc->GetBraceLevel() * indent_size); + indent_column_set(frm.top().brace_indent); + frm.top().indent = indent_column + indent_size; + log_indent(); + + if ( (pc->GetParentType() == CT_OC_BLOCK_EXPR) + && pc->TestFlags(PCF_IN_OC_MSG)) + { + frm.top().indent = frm.prev().indent_tmp + indent_size; + log_indent(); + frm.top().brace_indent = frm.prev().indent_tmp; + indent_column_set(frm.top().brace_indent); + } + frm.top().indent_tab = frm.top().indent; + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + + frm.prev().indent_tmp = frm.top().indent_tmp; + } + else if ( frm.paren_count != 0 + && !pc->TestFlags(PCF_IN_LAMBDA)) // Issue #3761 + { + if (frm.top().pc->GetParentType() == CT_OC_BLOCK_EXPR) + { + log_rule_B("indent_oc_block_msg"); + + if ( pc->TestFlags(PCF_IN_OC_MSG) + && options::indent_oc_block_msg()) + { + frm.top().ip.ref = oc_msg_block_indent(pc, false, false, false, true); + log_rule_B("indent_oc_block_msg"); + frm.top().ip.delta = options::indent_oc_block_msg(); + } + log_rule_B("indent_oc_block"); + log_rule_B("indent_oc_block_msg_xcode_style"); + + if ( options::indent_oc_block() + || options::indent_oc_block_msg_xcode_style()) + { + bool in_oc_msg = pc->TestFlags(PCF_IN_OC_MSG); + log_rule_B("indent_oc_block_msg_from_keyword"); + bool indent_from_keyword = options::indent_oc_block_msg_from_keyword() + && in_oc_msg; + log_rule_B("indent_oc_block_msg_from_colon"); + bool indent_from_colon = options::indent_oc_block_msg_from_colon() + && in_oc_msg; + log_rule_B("indent_oc_block_msg_from_caret"); + bool indent_from_caret = options::indent_oc_block_msg_from_caret() + && in_oc_msg; + log_rule_B("indent_oc_block_msg_from_brace"); + bool indent_from_brace = options::indent_oc_block_msg_from_brace() + && in_oc_msg; + + /* + * In "Xcode indent mode", we want to indent: + * - if the colon is aligned (namely, if a newline has been + * added before it), indent_from_brace + * - otherwise, indent from previous block (the "else" statement here) + */ + log_rule_B("indent_oc_block_msg_xcode_style"); + + if (options::indent_oc_block_msg_xcode_style()) + { + Chunk *bbc = pc->GetClosingParen(); // block brace close '}' + Chunk *bbc_next_ncnl = bbc->GetNextNcNnl(); + + if ( bbc_next_ncnl->GetType() == CT_OC_MSG_NAME + || bbc_next_ncnl->GetType() == CT_OC_MSG_FUNC) + { + indent_from_brace = false; + indent_from_colon = false; + indent_from_caret = false; + indent_from_keyword = true; + } + else + { + indent_from_brace = false; + indent_from_colon = false; + indent_from_caret = false; + indent_from_keyword = false; + } + } + Chunk *ref = oc_msg_block_indent(pc, indent_from_brace, + indent_from_caret, + indent_from_colon, + indent_from_keyword); + + if (ref) + { + frm.top().indent = indent_size + ref->GetColumn(); + } + else + { + frm.top().indent = 1 + ((pc->GetBraceLevel() + 1) * indent_size); + } + log_indent(); + indent_column_set(frm.top().indent - indent_size); + } + else + { + frm.top().indent = frm.prev().indent_tmp + indent_size; + log_indent(); + } + } + else if ( frm.top().pc->GetType() == CT_BRACE_OPEN + && frm.top().pc->GetParentType() == CT_OC_AT) + { + // We are inside @{ ... } -- indent one tab from the paren + if (frm.prev().indent_cont) + { + frm.top().indent = frm.prev().indent_tmp; + } + else + { + frm.top().indent = frm.prev().indent_tmp + indent_size; + } + log_indent(); + } + // Issue # 1620, UNI-24090.cs + else if ( frm.prev().pc->IsOnSameLine(frm.top().pc) + && !options::indent_align_paren() + && frm.prev().pc->IsParenOpen() + && !pc->TestFlags(PCF_ONE_LINER)) + { + log_rule_B("indent_align_paren"); + // We are inside ({ ... }) -- where { and ( are on the same line, avoiding double indentations. + // only to help the vim command } + frm.top().brace_indent = frm.prev().indent - indent_size; + indent_column_set(frm.top().brace_indent); + frm.top().indent = frm.prev().indent_tmp; + log_indent(); + } + else if ( frm.prev().pc->IsOnSameLine(frm.top().pc->GetPrevNcNnlNpp()) + && !options::indent_align_paren() + && frm.prev().pc->IsParenOpen() + && !pc->TestFlags(PCF_ONE_LINER)) + { + log_rule_B("indent_align_paren"); + // We are inside ({ ... }) -- where { and ( are on adjacent lines, avoiding indentation of brace. + // only to help the vim command } + frm.top().brace_indent = frm.prev().indent - indent_size; + indent_column_set(frm.top().brace_indent); + frm.top().indent = frm.prev().indent_tmp; + log_indent(); + } + else if ( options::indent_oc_inside_msg_sel() + && ( frm.prev().type == CT_OC_MSG_FUNC + || frm.prev().type == CT_OC_MSG_NAME)) // Issue #2658 + { + log_rule_B("indent_oc_inside_msg_sel"); + // [Class Message:{<here> + frm.top().indent = frm.prev().pc->GetColumn() + indent_size; + log_indent(); + indent_column_set(frm.prev().pc->GetColumn()); + } + // Issue #3813 + else if (pc->TestFlags(PCF_OC_IN_BLOCK) && pc->GetParentType() == CT_SWITCH) + { + frm.top().indent = frm.prev().indent_tmp; + } + else + { + // We are inside ({ ... }) -- indent one tab from the paren + frm.top().indent = frm.prev().indent_tmp + indent_size; + + if (!frm.prev().pc->IsParenOpen()) + { + frm.top().indent_tab = frm.top().indent; + } + log_indent(); + } + } + else if ( frm.top().pc->GetType() == CT_BRACE_OPEN + && frm.top().pc->GetParentType() == CT_OC_AT) + { + // We are inside @{ ... } -- indent one tab from the paren + if (frm.prev().indent_cont) + { + frm.top().indent = frm.prev().indent_tmp; + } + else + { + frm.top().indent = frm.prev().indent_tmp + indent_size; + frm.top().indent_tab = frm.top().indent; + } + log_indent(); + } + else if ( ( pc->GetParentType() == CT_BRACED_INIT_LIST + || ( !options::indent_compound_literal_return() + && pc->GetParentType() == CT_C_CAST)) + && frm.prev().type == CT_RETURN) + { + log_rule_B("indent_compound_literal_return"); + + // we're returning either a c compound literal (CT_C_CAST) or a + // C++11 initialization list (CT_BRACED_INIT_LIST), use indent from the return. + if (frm.prev().indent_cont) + { + frm.top().indent = frm.prev().indent_tmp; + } + else + { + frm.top().indent = frm.prev().indent_tmp + indent_size; + } + log_indent(); + } + else + { + // Use the prev indent level + indent_size. + if (pc->GetParentType() == CT_SWITCH) + { + frm.top().indent = frm.prev().indent + options::indent_switch_body(); + } + else + { + frm.top().indent = frm.prev().indent + indent_size; + } + LOG_FMT(LINDLINE, "%s(%d): frm.pse_tos is %zu, ... indent is %zu\n", + __func__, __LINE__, frm.size() - 1, frm.top().indent); + LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s', parent type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), + get_token_name(pc->GetParentType())); + + // If this brace is part of a statement, bump it out by indent_brace + if ( pc->GetParentType() == CT_IF + || pc->GetParentType() == CT_ELSE + || pc->GetParentType() == CT_ELSEIF + || pc->GetParentType() == CT_TRY + || pc->GetParentType() == CT_CATCH + || pc->GetParentType() == CT_DO + || pc->GetParentType() == CT_WHILE + || pc->GetParentType() == CT_USING_STMT + || pc->GetParentType() == CT_SWITCH + || pc->GetParentType() == CT_SYNCHRONIZED + || pc->GetParentType() == CT_FOR) + { + if (parent_token_indent != 0) + { + frm.top().indent += parent_token_indent - indent_size; + log_indent(); + } + else + { + log_rule_B("indent_brace"); + frm.top().indent += options::indent_brace(); + log_indent(); + indent_column_set(indent_column + options::indent_brace()); + } + } + else if (pc->GetParentType() == CT_CASE) + { + if (options::indent_ignore_case_brace()) + { + log_rule_B("indent_ignore_case_brace"); + indent_column_set(pc->GetOrigCol()); + } + else + { + log_rule_B("indent_case_brace"); + const auto tmp_indent = static_cast<int>(frm.prev().indent) + - static_cast<int>(indent_size) + + options::indent_case_brace(); + /* + * An open brace with the parent of case does not indent by default + * UO_indent_case_brace can be used to indent the brace. + * So we need to take the CASE indent, subtract off the + * indent_size that was added above and then add indent_case_brace. + * may take negative value + */ + indent_column_set(max(tmp_indent, 0)); + } + // Stuff inside the brace still needs to be indented + frm.top().indent = indent_column + indent_size; + log_indent(); + + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + } + else if ( pc->GetParentType() == CT_CLASS + && !options::indent_class()) + { + log_rule_B("indent_class"); + LOG_FMT(LINDENT, "%s(%d): orig line is %zu, orig col is %zu, text is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + frm.top().indent -= indent_size; + log_indent(); + } + else if (pc->GetParentType() == CT_NAMESPACE) + { + frm.top().ns_cnt = frm.prev().ns_cnt + 1; + + log_rule_B("indent_namespace"); + log_rule_B("indent_namespace_single_indent"); + + if ( options::indent_namespace() + && options::indent_namespace_single_indent()) + { + if (frm.top().ns_cnt >= 2) + { + // undo indent on all except the first namespace + frm.top().indent -= indent_size; + log_indent(); + } + indent_column_set(frm.prev(frm.top().ns_cnt).indent); + } + else if ( options::indent_namespace() + && options::indent_namespace_inner_only()) + { + if (frm.top().ns_cnt == 1) + { + // undo indent on first namespace only + frm.top().indent -= indent_size; + log_indent(); + } + } + else if ( pc->TestFlags(PCF_LONG_BLOCK) + || !options::indent_namespace()) + { + log_rule_B("indent_namespace"); + // don't indent long blocks + frm.top().indent -= indent_size; + log_indent(); + } + else // indenting 'short' namespace + { + log_rule_B("indent_namespace_level"); + + if (options::indent_namespace_level() > 0) + { + frm.top().indent -= indent_size; + log_indent(); + + frm.top().indent += + options::indent_namespace_level(); + log_indent(); + } + } + } + else if ( pc->GetParentType() == CT_EXTERN + && !options::indent_extern()) + { + log_rule_B("indent_extern"); + frm.top().indent -= indent_size; + log_indent(); + } + frm.top().indent_tab = frm.top().indent; + } + + if (pc->TestFlags(PCF_DONT_INDENT)) + { + frm.top().indent = pc->GetColumn(); + log_indent(); + + indent_column_set(pc->GetColumn()); + } + else + { + /* + * If there isn't a newline between the open brace and the next + * item, just indent to wherever the next token is. + * This covers this sort of stuff: + * { a++; + * b--; }; + */ + Chunk *next = pc->GetNextNcNnl(); + + if (next->IsNullChunk()) + { + break; + } + Chunk *prev = pc->GetPrev(); + + if ( pc->GetParentType() == CT_BRACED_INIT_LIST + && prev->Is(CT_BRACE_OPEN) + && prev->GetParentType() == CT_BRACED_INIT_LIST) + { + indent_column = frm.prev().brace_indent; + frm.top().indent = frm.prev().indent; + log_indent(); + } + else if ( !pc->IsNewlineBetween(next) + && next->GetParentType() != CT_BRACED_INIT_LIST + && options::indent_token_after_brace() + && !pc->TestFlags(PCF_ONE_LINER)) // Issue #1108 + { + log_rule_B("indent_token_after_brace"); + frm.top().indent = next->GetColumn(); + log_indent(); + } + frm.top().indent_tmp = frm.top().indent; + frm.top().open_line = pc->GetOrigLine(); + log_indent_tmp(); + + log_rule_B("Update the indent_column"); + + // Update the indent_column if needed + if ( brace_indent + || parent_token_indent != 0) + { + indent_column_set(frm.top().indent_tmp); + log_indent_tmp(); + } + } + // Save the brace indent + frm.top().brace_indent = indent_column; + } + else if (pc->Is(CT_SQL_END)) + { + if (frm.top().type == CT_SQL_BEGIN) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + indent_column_set(frm.top().indent_tmp); + log_indent_tmp(); + } + } + else if ( pc->Is(CT_SQL_BEGIN) + || pc->Is(CT_MACRO_OPEN) + || ( pc->Is(CT_CLASS) + && language_is_set(LANG_CS))) // Issue #3536 + { + frm.push(pc, __func__, __LINE__); + + frm.top().indent = frm.prev().indent + indent_size; + log_indent(); + + frm.top().indent_tmp = frm.top().indent; + frm.top().indent_tab = frm.top().indent; + log_indent_tmp(); + } + else if (pc->Is(CT_SQL_EXEC)) + { + frm.push(pc, __func__, __LINE__); + + frm.top().indent = frm.prev().indent + indent_size; + log_indent(); + + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + } + else if (pc->Is(CT_MACRO_ELSE)) + { + if (frm.top().type == CT_MACRO_OPEN) + { + indent_column_set(frm.prev().indent); + } + } + else if (pc->Is(CT_CASE)) + { + // Start a case - indent UO_indent_switch_case from the switch level + log_rule_B("indent_switch_case"); + const size_t tmp = frm.top().indent + indent_size + - options::indent_switch_body() + + options::indent_switch_case(); + frm.push(pc, __func__, __LINE__); + + frm.top().indent = tmp; + log_indent(); + + log_rule_B("indent_case_shift"); + frm.top().indent_tmp = tmp - indent_size + options::indent_case_shift(); + frm.top().indent_tab = tmp; + log_indent_tmp(); + + // Always set on case statements + indent_column_set(frm.top().indent_tmp); + + if (options::indent_case_comment()) + { + // comments before 'case' need to be aligned with the 'case' + Chunk *pct = pc; + + while ( ((pct = pct->GetPrevNnl())->IsNotNullChunk()) + && pct->IsComment()) + { + Chunk *t2 = pct->GetPrev(); + + if (t2->IsNewline()) + { + pct->SetColumn(frm.top().indent_tmp); + pct->SetColumnIndent(pct->GetColumn()); + } + } + } + } + else if (pc->Is(CT_BREAK)) + { + Chunk *prev = pc->GetPrevNcNnl(); + + if ( prev->Is(CT_BRACE_CLOSE) + && prev->GetParentType() == CT_CASE) + { + // issue #663 + issue #1366 + Chunk *prev_prev_newline = pc->GetPrevNl()->GetPrevNl(); + + if (prev_prev_newline->IsNotNullChunk()) + { + // This only affects the 'break', so no need for a stack entry + indent_column_set(prev_prev_newline->GetNext()->GetColumn()); + } + } + } + else if (pc->Is(CT_LABEL)) + { + if (options::indent_ignore_label()) + { + log_rule_B("indent_ignore_label"); + indent_column_set(pc->GetOrigCol()); + } + else + { + log_rule_B("indent_label"); + const int val = options::indent_label(); + size_t pse_indent = frm.top().indent; + + // Labels get sent to the left or backed up + if (val > 0) + { + indent_column_set(val); + + Chunk *next = pc->GetNext()->GetNext(); // colon + possible statement + + if ( next->IsNotNullChunk() + && !next->IsNewline() + // label (+ 2, because there is colon and space after it) must fit into indent + && (val + pc->Len() + 2 <= pse_indent)) + { + reindent_line(next, pse_indent); + } + } + else + { + bool no_underflow = (size_t)(abs(val)) < pse_indent; + indent_column_set((no_underflow ? (pse_indent + val) : 0)); + } + } + } + else if (pc->Is(CT_ACCESS)) + { + log_rule_B("indent_access_spec_body"); + + if (options::indent_access_spec_body()) + { + const size_t tmp = frm.top().indent + indent_size; + frm.push(pc, __func__, __LINE__); + + frm.top().indent = tmp; + log_indent(); + + frm.top().indent_tmp = tmp - indent_size; + frm.top().indent_tab = tmp; + log_indent_tmp(); + + /* + * If we are indenting the body, then we must leave the access spec + * indented at brace level + */ + indent_column_set(frm.top().indent_tmp); + // Issues 1161 + 2704 + // comments before 'access specifier' need to be aligned with the 'access specifier' + // unless it is a Doxygen comment + Chunk *pct = pc; + + while ( ((pct = pct->GetPrevNnl())->IsNotNullChunk()) + && pct->IsComment() + && !pct->IsDoxygenComment()) + { + Chunk *t2 = pct->GetPrev(); + + if (t2->IsNewline()) + { + pct->SetColumn(frm.top().indent_tmp); + pct->SetColumnIndent(pct->GetColumn()); + } + } + } + else + { + // Access spec labels get sent to the left or backed up + log_rule_B("indent_access_spec"); + int val = options::indent_access_spec(); + + if (val > 0) + { + indent_column_set(val); + } + else + { + size_t pse_indent = frm.top().indent; + bool no_underflow = (size_t)(abs(val)) < pse_indent; + + indent_column_set(no_underflow ? (pse_indent + val) : 0); + } + } + } + else if ( pc->Is(CT_CLASS_COLON) + || pc->Is(CT_CONSTR_COLON)) + { + // just indent one level + frm.push(pc, __func__, __LINE__); + + frm.top().indent = frm.prev().indent_tmp + indent_size; + log_indent(); + + frm.top().indent_tmp = frm.top().indent; + frm.top().indent_tab = frm.top().indent; + log_indent_tmp(); + + if (pc->Is(CT_CLASS_COLON)) + { + if (options::indent_ignore_before_class_colon()) + { + log_rule_B("indent_ignore_before_class_colon"); + frm.top().indent_tmp = pc->GetOrigCol(); + log_indent_tmp(); + } + else if (options::indent_before_class_colon() != 0) + { + log_rule_B("indent_before_class_colon"); + frm.top().indent_tmp = std::max<ptrdiff_t>(frm.top().indent_tmp + options::indent_before_class_colon(), 0); + log_indent_tmp(); + } + } + indent_column_set(frm.top().indent_tmp); + + log_rule_B("indent_class_colon"); + + if ( options::indent_class_colon() + && pc->Is(CT_CLASS_COLON)) + { + log_rule_B("indent_class_on_colon"); + + if (options::indent_class_on_colon()) + { + frm.top().indent = pc->GetColumn(); + log_indent(); + } + else + { + Chunk *next = pc->GetNext(); + + if ( next->IsNotNullChunk() + && !next->IsNewline()) + { + frm.top().indent = next->GetColumn(); + log_indent(); + } + } + } + else if (pc->Is(CT_CONSTR_COLON)) + { + if (options::indent_ignore_before_constr_colon()) + { + log_rule_B("indent_ignore_before_constr_colon"); + frm.top().indent_tmp = pc->GetOrigCol(); + indent_column_set(frm.top().indent_tmp); + } + + if (options::indent_constr_colon()) + { + log_rule_B("indent_constr_colon"); + Chunk *prev = pc->GetPrev(); + + if (prev->IsNewline()) + { + log_rule_B("indent_ctor_init_following"); + frm.top().indent += options::indent_ctor_init_following(); + log_indent(); + } + // TODO: Create a dedicated indent_constr_on_colon? + log_rule_B("indent_class_on_colon"); + + if (options::indent_ctor_init() != 0) + { + log_rule_B("indent_ctor_init"); + /* + * If the std::max() calls were specialized with size_t (the type of the underlying variable), + * they would never actually do their job, because size_t is unsigned and therefore even + * a "negative" result would be always greater than zero. + * Using ptrdiff_t (a standard signed type of the same size as size_t) in order to avoid that. + */ + frm.top().indent = std::max<ptrdiff_t>(frm.top().indent + options::indent_ctor_init(), 0); + log_indent(); + frm.top().indent_tmp = std::max<ptrdiff_t>(frm.top().indent_tmp + options::indent_ctor_init(), 0); + frm.top().indent_tab = std::max<ptrdiff_t>(frm.top().indent_tab + options::indent_ctor_init(), 0); + log_indent_tmp(); + indent_column_set(frm.top().indent_tmp); + } + else if (options::indent_class_on_colon()) + { + frm.top().indent = pc->GetColumn(); + log_indent(); + } + else + { + Chunk *next = pc->GetNext(); + + if ( next->IsNotNullChunk() + && !next->IsNewline()) + { + frm.top().indent = next->GetColumn(); + log_indent(); + } + } + } + } + } + else if ( pc->Is(CT_PAREN_OPEN) + && ( pc->GetParentType() == CT_ASM + || ( pc->GetPrevNcNnl()->IsNotNullChunk() + && pc->GetPrevNcNnl()->GetType() == CT_ASM)) + && options::indent_ignore_asm_block()) + { + log_rule_B("indent_ignore_asm_block"); + Chunk *tmp = pc->GetClosingParen(); + + int move = 0; + + if ( pc->GetPrev()->IsNewline() + && pc->GetColumn() != indent_column) + { + move = indent_column - pc->GetColumn(); + } + else + { + move = pc->GetColumn() - pc->GetOrigCol(); + } + + do + { + if (!pc->TestFlags(PCF_IN_PREPROC)) + { + pc->SetColumn(pc->GetOrigCol() + move); + } + pc = pc->GetNext(); + } while (pc != tmp); + + reindent_line(pc, indent_column); + } + else if ( pc->Is(CT_PAREN_OPEN) + || pc->Is(CT_LPAREN_OPEN) // Issue #3054 + || pc->Is(CT_SPAREN_OPEN) + || pc->Is(CT_FPAREN_OPEN) + || pc->Is(CT_SQUARE_OPEN) + || pc->Is(CT_ANGLE_OPEN)) + { + /* + * Open parenthesis and squares - never update indent_column, + * unless right after a newline. + */ + frm.push(pc, __func__, __LINE__); + + if ( pc->GetPrev()->IsNewline() + && pc->GetColumn() != indent_column + && !pc->TestFlags(PCF_DONT_INDENT)) + { + LOG_FMT(LINDENT, "%s(%d): orig line is %zu, indent => %zu, text is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + reindent_line(pc, indent_column); + } + frm.top().indent = pc->GetColumn() + pc->Len(); + log_indent(); + + if ( pc->Is(CT_SQUARE_OPEN) + && language_is_set(LANG_D)) + { + frm.top().indent_tab = frm.top().indent; + } + bool skipped = false; + log_rule_B("indent_inside_ternary_operator"); + log_rule_B("indent_align_paren"); + + if ( options::indent_inside_ternary_operator() + && ( pc->Is(CT_FPAREN_OPEN) + || pc->Is(CT_PAREN_OPEN)) + && frm.size() > 2 + && ( frm.prev().type == CT_QUESTION + || frm.prev().type == CT_COND_COLON) + && !options::indent_align_paren()) + { + frm.top().indent = frm.prev().indent_tmp + indent_size; + log_indent(); + frm.top().indent_tab = frm.top().indent; + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + } + else if ( ( pc->Is(CT_FPAREN_OPEN) + || pc->Is(CT_ANGLE_OPEN)) + && ( ( options::indent_func_call_param() + && ( pc->GetParentType() == CT_FUNC_CALL + || pc->GetParentType() == CT_FUNC_CALL_USER)) + || ( options::indent_func_proto_param() + && pc->GetParentType() == CT_FUNC_PROTO) + || ( options::indent_func_class_param() + && ( pc->GetParentType() == CT_FUNC_CLASS_DEF + || pc->GetParentType() == CT_FUNC_CLASS_PROTO)) + || ( options::indent_template_param() + && pc->GetParentType() == CT_TEMPLATE) + || ( options::indent_func_ctor_var_param() + && pc->GetParentType() == CT_FUNC_CTOR_VAR) + || ( options::indent_func_def_param() + && pc->GetParentType() == CT_FUNC_DEF) + || ( !options::indent_func_def_param() // Issue #931 + && pc->GetParentType() == CT_FUNC_DEF + && options::indent_func_def_param_paren_pos_threshold() > 0 + && pc->GetOrigCol() > options::indent_func_def_param_paren_pos_threshold()))) + { + log_rule_B("indent_func_call_param"); + log_rule_B("indent_func_proto_param"); + log_rule_B("indent_func_class_param"); + log_rule_B("indent_template_param"); + log_rule_B("indent_func_ctor_var_param"); + log_rule_B("indent_func_def_param"); + log_rule_B("indent_func_def_param_paren_pos_threshold"); + // Skip any continuation indents + size_t idx = (!frm.empty()) ? frm.size() - 2 : 0; + + while ( ( ( idx > 0 + && frm.at(idx).type != CT_BRACE_OPEN + && frm.at(idx).type != CT_VBRACE_OPEN + && frm.at(idx).type != CT_PAREN_OPEN + && frm.at(idx).type != CT_FPAREN_OPEN + && frm.at(idx).type != CT_SPAREN_OPEN + && frm.at(idx).type != CT_SQUARE_OPEN + && frm.at(idx).type != CT_ANGLE_OPEN + && frm.at(idx).type != CT_CASE + && frm.at(idx).type != CT_MEMBER + && frm.at(idx).type != CT_QUESTION + && frm.at(idx).type != CT_COND_COLON + && frm.at(idx).type != CT_LAMBDA + && frm.at(idx).type != CT_ASSIGN_NL) + || frm.at(idx).pc->IsOnSameLine(frm.top().pc)) + && ( frm.at(idx).type != CT_CLASS_COLON + && frm.at(idx).type != CT_CONSTR_COLON + && !( frm.at(idx).type == CT_LAMBDA + && frm.at(idx).pc->GetPrevNc()->GetType() == CT_NEWLINE))) + { + if (idx == 0) + { + fprintf(stderr, "%s(%d): idx is ZERO, cannot be decremented, at line %zu, column %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + idx--; + skipped = true; + } + // PR#381 + log_rule_B("indent_param"); + + if (options::indent_param() != 0) + { + frm.top().indent = frm.at(idx).indent + options::indent_param(); + log_indent(); + } + else + { + frm.top().indent = frm.at(idx).indent + indent_size; + log_indent(); + } + log_rule_B("indent_func_param_double"); + + if (options::indent_func_param_double()) + { + // double is: Use both values of the options indent_columns and indent_param + frm.top().indent += indent_size; + log_indent(); + } + frm.top().indent_tab = frm.top().indent; + } + else if ( options::indent_oc_inside_msg_sel() + && pc->Is(CT_PAREN_OPEN) + && frm.size() > 2 + && ( frm.prev().type == CT_OC_MSG_FUNC + || frm.prev().type == CT_OC_MSG_NAME) + && !options::indent_align_paren()) // Issue #2658 + { + log_rule_B("indent_oc_inside_msg_sel"); + log_rule_B("indent_align_paren"); + // When parens are inside OC messages, push on the parse frame stack + // [Class Message:(<here> + frm.top().indent = frm.prev().pc->GetColumn() + indent_size; + log_indent(); + frm.top().indent_tab = frm.top().indent; + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + } + else if ( pc->Is(CT_PAREN_OPEN) + && !pc->GetNext()->IsNewline() + && !options::indent_align_paren() + && !pc->TestFlags(PCF_IN_SPAREN)) + { + log_rule_B("indent_align_paren"); + size_t idx = frm.size() - 2; + + while ( idx > 0 + && frm.at(idx).pc->IsOnSameLine(frm.top().pc)) + { + idx--; + skipped = true; + } + frm.top().indent = frm.at(idx).indent + indent_size; + log_indent(); + + frm.top().indent_tab = frm.top().indent; + skipped = true; + } + else if ( ( pc->IsString("(") + && !options::indent_paren_nl()) + || ( pc->IsString("<") + && !options::indent_paren_nl()) // TODO: add indent_angle_nl? + || ( pc->IsString("[") + && !options::indent_square_nl())) + { + log_rule_B("indent_paren_nl"); + log_rule_B("indent_square_nl"); + Chunk *next = pc->GetNextNc(); + + if (next->IsNullChunk()) + { + break; + } + log_rule_B("indent_paren_after_func_def"); + log_rule_B("indent_paren_after_func_decl"); + log_rule_B("indent_paren_after_func_call"); + + if ( next->IsNewline() + && !options::indent_paren_after_func_def() + && !options::indent_paren_after_func_decl() + && !options::indent_paren_after_func_call()) + { + size_t sub = 2; + + if ( (frm.prev().type == CT_ASSIGN) + || (frm.prev().type == CT_RETURN)) + { + sub = 3; + } + sub = frm.size() - sub; + + log_rule_B("indent_align_paren"); + + if (!options::indent_align_paren()) + { + sub = frm.size() - 2; + + while ( sub > 0 + && frm.at(sub).pc->IsOnSameLine(frm.top().pc)) + { + sub--; + skipped = true; + } + + if ( ( frm.at(sub + 1).type == CT_CLASS_COLON + || frm.at(sub + 1).type == CT_CONSTR_COLON) + && (frm.at(sub + 1).pc->GetPrev()->Is(CT_NEWLINE))) + { + sub = sub + 1; + } + } + frm.top().indent = frm.at(sub).indent + indent_size; + log_indent(); + + frm.top().indent_tab = frm.top().indent; + skipped = true; + } + else + { + if ( next->IsNotNullChunk() + && !next->IsComment()) + { + if (next->Is(CT_SPACE)) + { + next = next->GetNextNc(); + + if (next->IsNullChunk()) + { + break; + } + } + + if (next->GetPrev()->IsComment()) + { + // Issue #2099 + frm.top().indent = next->GetPrev()->GetColumn(); + } + else + { + frm.top().indent = next->GetColumn(); + } + log_indent(); + } + } + } + log_rule_B("use_indent_continue_only_once"); + log_rule_B("indent_paren_after_func_decl"); + log_rule_B("indent_paren_after_func_def"); + log_rule_B("indent_paren_after_func_call"); + + if ( ( ( !frm.top().indent_cont // Issue #3567 + && vardefcol == 0) + || ( !options::use_indent_continue_only_once() // Issue #1160 + && !options::indent_ignore_first_continue())) // Issue #3561 + && ( pc->Is(CT_FPAREN_OPEN) + && pc->GetPrev()->IsNewline()) + && ( ( ( pc->GetParentType() == CT_FUNC_PROTO + || pc->GetParentType() == CT_FUNC_CLASS_PROTO) + && options::indent_paren_after_func_decl()) + || ( ( pc->GetParentType() == CT_FUNC_DEF + || pc->GetParentType() == CT_FUNC_CLASS_DEF) + && options::indent_paren_after_func_def()) + || ( ( pc->GetParentType() == CT_FUNC_CALL + || pc->GetParentType() == CT_FUNC_CALL_USER) + && options::indent_paren_after_func_call()) + || !pc->GetNext()->IsNewline())) + { + frm.top().indent = frm.prev().indent + indent_size; + log_indent(); + + indent_column_set(frm.top().indent); + } + log_rule_B("indent_continue"); + + if ( pc->GetParentType() != CT_OC_AT + && ( options::indent_ignore_first_continue() + || options::indent_continue() != 0) + && !skipped) + { + if (options::indent_ignore_first_continue()) + { + frm.top().indent = get_indent_first_continue(pc->GetNext()); + } + else + { + frm.top().indent = frm.prev().indent; + } + log_indent(); + + if ( pc->GetLevel() == pc->GetBraceLevel() + && !options::indent_ignore_first_continue() + && ( pc->Is(CT_FPAREN_OPEN) + || pc->Is(CT_SPAREN_OPEN) + || ( pc->Is(CT_SQUARE_OPEN) + && pc->GetParentType() != CT_OC_MSG) + || pc->Is(CT_ANGLE_OPEN))) // Issue #1170 + { + //log_rule_B("indent_continue"); + //frm.top().indent += abs(options::indent_continue()); + // frm.top().indent = calc_indent_continue(frm); + // frm.top().indent_cont = true; + log_rule_B("use_indent_continue_only_once"); + + if ( (options::use_indent_continue_only_once()) + && (frm.top().indent_cont) + && vardefcol != 0) + { + /* + * The value of the indentation for a continuation line is calculate + * differently if the line is: + * a declaration :your case with QString fileName ... + * an assignment :your case with pSettings = new QSettings( ... + * At the second case the option value might be used twice: + * at the assignment + * at the function call (if present) + * If you want to prevent the double use of the option value + * you may use the new option : + * use_indent_continue_only_once + * with the value "true". + * use/don't use indent_continue once Guy 2016-05-16 + */ + + // if vardefcol isn't zero, use it + frm.top().indent = vardefcol; + log_indent(); + } + else + { + frm.top().indent = calc_indent_continue(frm); + log_indent(); + frm.top().indent_cont = true; + + log_rule_B("indent_sparen_extra"); + + if ( pc->Is(CT_SPAREN_OPEN) + && options::indent_sparen_extra() != 0) + { + frm.top().indent += options::indent_sparen_extra(); + log_indent(); + } + } + } + } + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + + frm.paren_count++; + } + else if ( options::indent_member_single() + && pc->Is(CT_MEMBER) + && (strcmp(pc->Text(), ".") == 0) + && language_is_set(LANG_CS | LANG_CPP)) + { + log_rule_B("indent_member_single"); + + if (frm.top().type != CT_MEMBER) + { + frm.push(pc, __func__, __LINE__); + Chunk *tmp = frm.top().pc->GetPrevNcNnlNpp(); + + if (frm.prev().pc->IsOnSameLine(tmp)) + { + frm.top().indent = frm.prev().indent; + } + else + { + frm.top().indent = frm.prev().indent + indent_size; + } + log_indent(); + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + } + + if (pc->GetPrev()->IsNewline()) + { + if ( pc->Is(CT_MEMBER) // Issue #2890 + && language_is_set(LANG_CPP)) + { + // will be done at another place + // look at the comment: XXXXXXXXXXXXXXXXXXXXXXXXXX + } + else + { + indent_column_set(frm.top().indent); + reindent_line(pc, indent_column); + did_newline = false; + } + } + //check for the series of CT_member chunks else pop it. + Chunk *tmp = pc->GetNextNcNnlNpp(); + + if (tmp->IsNotNullChunk()) + { + if (tmp->Is(CT_FUNC_CALL)) + { + tmp = tmp->GetNextType(CT_FPAREN_CLOSE, tmp->GetLevel()); + tmp = tmp->GetNextNcNnlNpp(); + } + else if ( tmp->Is(CT_WORD) + || tmp->Is(CT_TYPE)) + { + tmp = tmp->GetNextNcNnlNpp(); + } + } + + if ( tmp->IsNotNullChunk() + && ( (strcmp(tmp->Text(), ".") != 0) + || tmp->IsNot(CT_MEMBER))) + { + if (tmp->IsParenClose()) + { + tmp = tmp->GetPrevNcNnlNpp(); + } + Chunk *local_prev = tmp->GetPrev(); // Issue #3294 + + if (local_prev->IsComment()) + { + tmp = tmp->GetPrev(); // Issue #3294 + } + + if ( tmp->IsNotNullChunk() + && tmp->GetPrev()->IsNewline()) + { + tmp = tmp->GetPrevNcNnlNpp()->GetNextNl(); + } + + if (tmp->IsNotNullChunk()) + { + frm.top().pop_pc = tmp; + } + } + } + else if ( pc->Is(CT_ASSIGN) + || pc->Is(CT_IMPORT) + || ( pc->Is(CT_USING) + && language_is_set(LANG_CS))) + { + /* + * if there is a newline after the '=' or the line starts with a '=', + * just indent one level, + * otherwise align on the '='. + */ + if ( pc->Is(CT_ASSIGN) + && pc->GetPrev()->IsNewline()) + { + if (frm.top().type == CT_ASSIGN_NL) + { + frm.top().indent_tmp = frm.top().indent; + } + else + { + frm.top().indent_tmp = frm.top().indent + indent_size; + } + log_indent_tmp(); + + indent_column_set(frm.top().indent_tmp); + LOG_FMT(LINDENT, "%s(%d): %zu] assign => %zu [%s]\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + reindent_line(pc, frm.top().indent_tmp); + } + Chunk *next = pc->GetNext(); + + if (next->IsNotNullChunk()) + { + /* + * fixes 1260 , 1268 , 1277 (Extra indentation after line with multiple assignments) + * For multiple consecutive assignments in single line , the indent of all these + * assignments should be same and one more than this line's indent. + * so popping the previous assign and pushing the new one + */ + if ( frm.top().type == CT_ASSIGN + && pc->Is(CT_ASSIGN)) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } + frm.push(pc, __func__, __LINE__); + + if ( pc->Is(CT_ASSIGN) + && pc->GetPrev()->IsNewline()) + { + frm.top().type = CT_ASSIGN_NL; + } + log_rule_B("indent_continue"); + + if (options::indent_ignore_first_continue()) + { + frm.top().indent = get_indent_first_continue(pc); + log_indent(); + frm.top().indent_cont = true; // Issue #3567 + } + else if (options::indent_continue() != 0) + { + frm.top().indent = frm.prev().indent; + log_indent(); + + if ( pc->GetLevel() == pc->GetBraceLevel() + && ( pc->IsNot(CT_ASSIGN) + || ( pc->GetParentType() != CT_FUNC_PROTO + && pc->GetParentType() != CT_FUNC_DEF))) + { + log_rule_B("use_indent_continue_only_once"); + + if ( (options::use_indent_continue_only_once()) + && (frm.top().indent_cont) + && vardefcol != 0) + { + // if vardefcol isn't zero, use it + frm.top().indent = vardefcol; + log_indent(); + } + else + { + frm.top().indent = calc_indent_continue(frm); + log_indent(); + + vardefcol = frm.top().indent; // use the same variable for the next line + frm.top().indent_cont = true; + } + } + } + else if ( next->IsNewline() + || !options::indent_align_assign()) + { + log_rule_B("indent_align_assign"); + log_rule_B("indent_off_after_assign"); + + if (options::indent_off_after_assign()) // Issue #2591 + { + frm.top().indent = frm.prev().indent_tmp; + } + else + { + frm.top().indent = frm.prev().indent_tmp + indent_size; + } + log_indent(); + + if ( pc->Is(CT_ASSIGN) + && next->IsNewline()) + { + frm.top().type = CT_ASSIGN_NL; + frm.top().indent_tab = frm.top().indent; + } + } + else + { + frm.top().indent = pc->GetColumn() + pc->Len() + 1; + log_indent(); + } + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + } + } + else if ( pc->Is(CT_RETURN) + || ( pc->Is(CT_THROW) + && pc->GetParentType() == CT_NONE)) + { + // don't count returns inside a () or [] + if ( pc->GetLevel() == pc->GetBraceLevel() + || pc->TestFlags(PCF_IN_LAMBDA)) + { + Chunk *next = pc->GetNext(); + + // Avoid indentation on return token set by the option. + log_rule_B("indent_off_after_return"); + + // Avoid indentation on return token if the next token is a new token + // to properly indent object initializers returned by functions. + log_rule_B("indent_off_after_return_new"); + bool indent_after_return = ( next->IsNotNullChunk() + && next->GetType() == CT_NEW) + ? !options::indent_off_after_return_new() + : !options::indent_off_after_return(); + + if ( indent_after_return + || next->IsNullChunk()) + { + frm.push(pc, __func__, __LINE__); + + log_rule_B("indent_single_after_return"); + + if ( next->IsNewline() + || ( pc->Is(CT_RETURN) + && options::indent_single_after_return())) + { + // apply normal single indentation + frm.top().indent = frm.prev().indent + indent_size; + } + else + { + // indent after the return token + frm.top().indent = frm.prev().indent + pc->Len() + 1; + } + log_indent(); + frm.top().indent_tmp = frm.prev().indent; + log_indent_tmp(); + } + log_indent(); + } + } + else if ( pc->Is(CT_OC_SCOPE) + || pc->Is(CT_TYPEDEF)) + { + frm.push(pc, __func__, __LINE__); + // Issue #405 + frm.top().indent = frm.prev().indent; + log_indent(); + + frm.top().indent_tmp = frm.top().indent; + LOG_FMT(LINDLINE, "%s(%d): .indent is %zu, .indent_tmp is %zu\n", + __func__, __LINE__, frm.top().indent, frm.top().indent_tmp); + + log_rule_B("indent_continue"); + + if (options::indent_ignore_first_continue()) + { + frm.top().indent = get_indent_first_continue(pc); + log_indent(); + } + else if (options::indent_continue() != 0) + { + frm.top().indent = calc_indent_continue(frm, frm.size() - 2); + log_indent(); + + frm.top().indent_cont = true; + } + else + { + frm.top().indent = frm.prev().indent + indent_size; + log_indent(); + } + } + else if (pc->Is(CT_C99_MEMBER)) + { + // nothing to do + } + else if (pc->Is(CT_WHERE_SPEC)) + { + /* class indentation is ok already, just need to adjust func */ + /* TODO: make this configurable, obviously.. */ + if ( pc->GetParentType() == CT_FUNC_DEF + || pc->GetParentType() == CT_FUNC_PROTO + || ( pc->GetParentType() == CT_STRUCT + && frm.top().type != CT_CLASS_COLON)) + { + indent_column_set(frm.top().indent + 4); + } + } + else if ( options::indent_inside_ternary_operator() + && ( pc->Is(CT_QUESTION) + || pc->Is(CT_COND_COLON))) // Issue #1130, #1715 + { + log_rule_B("indent_inside_ternary_operator"); + + // Pop any colons before because they should already be processed + while ( pc->Is(CT_COND_COLON) + && frm.top().type == CT_COND_COLON) + { + frm.pop(__func__, __LINE__, pc); + } + log_rule_B("indent_inside_ternary_operator"); + + // Pop Question from stack in ternary operator + if ( options::indent_inside_ternary_operator() + && pc->Is(CT_COND_COLON) + && frm.top().type == CT_QUESTION) + { + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + indent_column_set(frm.top().indent_tmp); + } + frm.push(pc, __func__, __LINE__); + + frm.top().indent = frm.prev().indent + indent_size; + frm.top().indent_tab = frm.top().indent; + log_indent(); + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + } + else if ( pc->Is(CT_LAMBDA) + && (language_is_set(LANG_CS | LANG_JAVA)) + && pc->GetNextNcNnlNpp()->IsNot(CT_BRACE_OPEN) + && options::indent_cs_delegate_body()) + { + log_rule_B("indent_cs_delegate_body"); + frm.push(pc, __func__, __LINE__); + frm.top().indent = frm.prev().indent; + log_indent(); + + if ( pc->GetPrevNc()->IsNewline() + && !frm.prev().pc->IsOnSameLine(pc->GetPrevNcNnl())) + { + frm.top().indent = frm.prev().indent + indent_size; + log_indent(); + reindent_line(pc, (frm.prev().indent + indent_size)); + did_newline = false; + } + else if ( pc->GetNextNc()->IsNewline() + && !frm.prev().pc->IsOnSameLine(frm.top().pc)) + { + frm.top().indent = frm.prev().indent + indent_size; + } + log_indent(); + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + } + else if ( options::indent_oc_inside_msg_sel() + && ( pc->Is(CT_OC_MSG_FUNC) + || pc->Is(CT_OC_MSG_NAME)) + && pc->GetNextNcNnl()->Is(CT_OC_COLON)) // Issue #2658 + { + log_rule_B("indent_oc_inside_msg_sel"); + // Pop the OC msg name that is on the top of the stack + // [Class Message:<here> + frm.push(pc, __func__, __LINE__); + + frm.top().indent = frm.prev().indent; + frm.top().indent_tab = frm.prev().indent_tab; + log_indent(); + frm.top().indent_tmp = frm.prev().indent_tmp; + log_indent_tmp(); + } + else if (pc->IsComment()) + { + // Issue #3294 + Chunk *next = pc->GetNext(); + + if (next->Is(CT_COND_COLON)) + { + LOG_FMT(LINDLINE, "%s(%d): Comment and COND_COLON: pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + frm.pop(__func__, __LINE__, pc); + } +// uncomment the line below to get debug info +// #define ANYTHING_ELSE +#ifdef ANYTHING_ELSE + else + { + // anything else? + // Issue #3294 + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + LOG_FMT(LSPACE, "\n\n%s(%d): WARNING: unrecognize indent_text:\n", + __func__, __LINE__); + } +#endif /* ANYTHING_ELSE */ + } + else + { + // anything else? +#ifdef ANYTHING_ELSE + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + LOG_FMT(LSPACE, "\n\n%s(%d): WARNING: unrecognize indent_text:\n", + __func__, __LINE__); +#endif /* ANYTHING_ELSE */ + } + // Handle shift expression continuation indenting + size_t shiftcontcol = 0; + + log_rule_B("indent_shift"); + + if ( options::indent_shift() == 1 + && !pc->TestFlags(PCF_IN_ENUM) + && pc->GetParentType() != CT_OPERATOR + && !pc->IsComment() + && pc->IsNot(CT_BRACE_OPEN) + && pc->GetLevel() > 0 + && !pc->IsEmptyText()) + { + bool in_shift = false; + bool is_operator = false; + + // Are we in such an expression? Go both forwards and backwards. + Chunk *tmp = pc; + + do + { + if (tmp->Is(CT_SHIFT)) + { + in_shift = true; + LOG_FMT(LINDENT2, "%s(%d): in_shift set to TRUE\n", + __func__, __LINE__); + + tmp = tmp->GetPrevNcNnl(); + + if (tmp->Is(CT_OPERATOR)) + { + is_operator = true; + } + break; + } + tmp = tmp->GetPrevNcNnl(); + } while ( !in_shift + && tmp->IsNotNullChunk() + && tmp->IsNot(CT_SEMICOLON) + && tmp->IsNot(CT_BRACE_OPEN) + && tmp->IsNot(CT_BRACE_CLOSE) + && tmp->IsNot(CT_COMMA) + && tmp->IsNot(CT_SPAREN_OPEN) + && tmp->IsNot(CT_SPAREN_CLOSE)); + + tmp = pc; + + do + { + tmp = tmp->GetNextNcNnl(); + + if ( tmp->IsNotNullChunk() + && tmp->Is(CT_SHIFT)) + { + in_shift = true; + LOG_FMT(LINDENT2, "%s(%d): in_shift set to TRUE\n", + __func__, __LINE__); + + tmp = tmp->GetPrevNcNnl(); + + if (tmp->Is(CT_OPERATOR)) + { + is_operator = true; + } + break; + } + } while ( !in_shift + && tmp->IsNotNullChunk() + && tmp->IsNot(CT_SEMICOLON) + && tmp->IsNot(CT_BRACE_OPEN) + && tmp->IsNot(CT_BRACE_CLOSE) + && tmp->IsNot(CT_COMMA) + && tmp->IsNot(CT_SPAREN_OPEN) + && tmp->IsNot(CT_SPAREN_CLOSE)); + + LOG_FMT(LINDENT2, "%s(%d): in_shift is %s\n", + __func__, __LINE__, in_shift ? "TRUE" : "FALSE"); + Chunk *prev_nonl = pc->GetPrevNcNnl(); + Chunk *prev2 = pc->GetPrevNc(); + + if (( prev_nonl->IsSemicolon() + || prev_nonl->IsBraceOpen() + || prev_nonl->IsBraceClose() + || prev_nonl->Is(CT_CASE_COLON) + || ( prev_nonl->IsNotNullChunk() + && prev_nonl->TestFlags(PCF_IN_PREPROC)) != pc->TestFlags(PCF_IN_PREPROC) + || prev_nonl->Is(CT_COMMA) + || is_operator)) + { + in_shift = false; + } + LOG_FMT(LINDENT2, "%s(%d): in_shift is %s\n", + __func__, __LINE__, in_shift ? "TRUE" : "FALSE"); + + if ( prev2->Is(CT_NEWLINE) + && in_shift) + { + shiftcontcol = calc_indent_continue(frm); + // Setting frm.top().indent_cont = true in the top context when the indent is not also set + // just leads to complications when succeeding statements try to indent based on being + // embedded in a continuation. In other words setting frm.top().indent_cont = true + // should only be set if frm.top().indent is also set. + + // Work around the doubly increased indent in RETURNs and assignments + bool need_workaround = false; + size_t sub = 0; + + for (int i = frm.size() - 1; i >= 0; i--) + { + if ( frm.at(i).type == CT_RETURN + || frm.at(i).type == CT_ASSIGN) + { + need_workaround = true; + sub = frm.size() - i; + break; + } + } + + if (need_workaround) + { + shiftcontcol = calc_indent_continue(frm, frm.size() - 1 - sub); + } + } + } + + // Handle variable definition continuation indenting + if ( vardefcol == 0 + && ( pc->Is(CT_WORD) + || pc->Is(CT_FUNC_CTOR_VAR)) + && !pc->TestFlags(PCF_IN_FCN_DEF) + && pc->TestFlags(PCF_VAR_1ST_DEF)) + { + log_rule_B("indent_continue"); + + if (options::indent_ignore_first_continue()) + { + vardefcol = get_indent_first_continue(pc); + } + else if (options::indent_continue() != 0) + { + vardefcol = calc_indent_continue(frm); + // Setting frm.top().indent_cont = true in the top context when the indent is not also set + // just leads to complications when succeeding statements try to indent based on being + // embedded in a continuation. In other words setting frm.top().indent_cont = true + // should only be set if frm.top().indent is also set. + } + else if ( options::indent_var_def_cont() + || pc->GetPrev()->IsNewline()) + { + log_rule_B("indent_var_def_cont"); + vardefcol = frm.top().indent + indent_size; + } + else + { + // Issue #3010 + vardefcol = pc->GetColumn(); + // BUT, we need to skip backward over any '*' + Chunk *tmp = pc->GetPrevNc(); + + while (tmp->Is(CT_PTR_TYPE)) + { + vardefcol = tmp->GetColumn(); + tmp = tmp->GetPrevNc(); + } + // BUT, we need to skip backward over any '::' or TYPE + //tmp = pc->GetPrevNc(); + + //if (tmp->Is(CT_DC_MEMBER)) + //{ + // // look for a type + // Chunk *tmp2 = tmp->GetPrevNc(); + // if (tmp2->Is(CT_TYPE)) + // { + // // we have something like "SomeLongNamespaceName::Foo()" + // vardefcol = tmp2->GetColumn(); + // LOG_FMT(LINDENT, "%s(%d): orig line is %zu, vardefcol is %zu\n", + // __func__, __LINE__, pc->GetOrigLine(), vardefcol); + // } + //} + } + } + + if ( pc->IsSemicolon() + || ( pc->Is(CT_BRACE_OPEN) + && ( pc->GetParentType() == CT_FUNCTION + || pc->GetParentType() == CT_CLASS))) //Issue #3576 + { + vardefcol = 0; + } + + // Indent the line if needed + if ( did_newline + && !pc->IsNewline() + && (pc->Len() != 0)) + { + pc->SetColumnIndent(frm.top().indent_tab); + + if (frm.top().ip.ref) + { + pc->IndentData().ref = frm.top().ip.ref; + pc->IndentData().delta = frm.top().ip.delta; + } + LOG_FMT(LINDENT2, "%s(%d): orig line is %zu, pc->GetColumn() indent is %zu, indent_column is %zu, for '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetColumnIndent(), indent_column, pc->ElidedText(copy)); + + /* + * Check for special continuations. + * Note that some of these could be done as a stack item like + * everything else + */ + + Chunk *prev = pc->GetPrevNcNnl(); + Chunk *prevv = prev->GetPrevNcNnl(); + Chunk *next = pc->GetNextNcNnl(); + + bool do_vardefcol = false; + + if ( vardefcol > 0 + && pc->GetLevel() == pc->GetBraceLevel() + && ( prev->Is(CT_COMMA) + || prev->Is(CT_TYPE) + || prev->Is(CT_PTR_TYPE) + || prev->Is(CT_WORD))) + { + Chunk *tmp = pc; + + while (tmp->Is(CT_PTR_TYPE)) + { + tmp = tmp->GetNextNcNnl(); + } + LOG_FMT(LINDENT2, "%s(%d): orig line is %zu, for '%s'", + __func__, __LINE__, tmp->GetOrigLine(), tmp->Text()); + LOG_FMT(LINDENT2, " tmp->GetFlags(): "); + log_pcf_flags(LINDENT2, tmp->GetFlags()); // Issue #2332 + + if ( tmp->TestFlags(PCF_VAR_DEF) + && ( tmp->Is(CT_WORD) + || tmp->Is(CT_FUNC_CTOR_VAR))) + { + do_vardefcol = true; + } + } + //LOG_FMT(LINDENT2, "%s(%d): GUY 2:\n", __func__, __LINE__); + + if (pc->TestFlags(PCF_DONT_INDENT)) + { + // no change + } + else if ( pc->GetParentType() == CT_SQL_EXEC + && options::indent_preserve_sql()) + { + log_rule_B("indent_preserve_sql"); + reindent_line(pc, sql_col + (pc->GetOrigCol() - sql_orig_col)); + LOG_FMT(LINDENT, "Indent SQL: [%s] to %zu (%zu/%zu)\n", + pc->Text(), pc->GetColumn(), sql_col, sql_orig_col); + } + else if ( !options::indent_member_single() + && !pc->TestFlags(PCF_STMT_START) + && ( pc->Is(CT_MEMBER) + || ( pc->Is(CT_DC_MEMBER) + && prev->Is(CT_TYPE)) + || ( prev->Is(CT_MEMBER) + || ( prev->Is(CT_DC_MEMBER) + && prevv->Is(CT_TYPE))))) + { + log_rule_B("indent_member_single"); + log_rule_B("indent_member"); + size_t tmp = options::indent_member() + indent_column; + LOG_FMT(LINDENT, "%s(%d): orig line is %zu, member => %zu\n", + __func__, __LINE__, pc->GetOrigLine(), tmp); + reindent_line(pc, tmp); + } + else if (do_vardefcol) + { + LOG_FMT(LINDENT, "%s(%d): orig line is %zu, vardefcol is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), vardefcol); + reindent_line(pc, vardefcol); + } + else if (shiftcontcol > 0) + { + LOG_FMT(LINDENT, "%s(%d): orig line is %zu, shiftcontcol is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), shiftcontcol); + reindent_line(pc, shiftcontcol); + } + else if ( pc->Is(CT_NAMESPACE) + && options::indent_namespace() + && options::indent_namespace_single_indent() + && frm.top().ns_cnt) + { + log_rule_B("indent_namespace"); + log_rule_B("indent_namespace_single_indent"); + LOG_FMT(LINDENT, "%s(%d): orig line is %zu, Namespace => %zu\n", + __func__, __LINE__, pc->GetOrigLine(), frm.top().brace_indent); + reindent_line(pc, frm.top().brace_indent); + } + else if ( pc->Is(CT_STRING) + && prev->Is(CT_STRING) + && options::indent_align_string()) + { + log_rule_B("indent_align_string"); + const int tmp = (xml_indent != 0) ? xml_indent : prev->GetColumn(); + + LOG_FMT(LINDENT, "%s(%d): orig line is %zu, String => %d\n", + __func__, __LINE__, pc->GetOrigLine(), tmp); + reindent_line(pc, tmp); + } + else if (pc->IsComment()) + { + LOG_FMT(LINDENT, "%s(%d): orig line is %zu, comment => %zu\n", + __func__, __LINE__, pc->GetOrigLine(), frm.top().indent_tmp); + indent_comment(pc, frm.top().indent_tmp); + } + else if (pc->Is(CT_PREPROC)) + { + LOG_FMT(LINDENT, "%s(%d): orig line is %zu, pp-indent => %zu [%s]\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + reindent_line(pc, indent_column); + } + else if ( pc->IsParenClose() + || pc->Is(CT_ANGLE_CLOSE)) + { + /* + * This is a big hack. We assume that since we hit a paren close, + * that we just removed a paren open + */ + LOG_FMT(LINDLINE, "%s(%d): indent_column is %zu\n", + __func__, __LINE__, indent_column); + + if (frm.poped().type == E_Token(pc->GetType() - 1)) + { + // Issue # 405 + LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + Chunk *ck1 = frm.poped().pc; + LOG_FMT(LINDLINE, "%s(%d): ck1 orig line is %zu, orig col is %zu, Text() is '%s', GetType() is %s\n", + __func__, __LINE__, ck1->GetOrigLine(), ck1->GetOrigCol(), ck1->Text(), get_token_name(ck1->GetType())); + Chunk *ck2 = ck1->GetPrev(); + LOG_FMT(LINDLINE, "%s(%d): ck2 orig line is %zu, orig col is %zu, Text() is '%s', GetType() is %s\n", + __func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol(), ck2->Text(), get_token_name(ck2->GetType())); + + log_rule_B("indent_paren_close"); + + if (options::indent_paren_close() == -1) + { + LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_paren_close is -1\n", + __func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol()); + indent_column_set(pc->GetOrigCol()); + LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_column set to %zu\n", + __func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol(), indent_column); + } + else if ( ck2->IsNewline() + || (options::indent_paren_close() == 1)) + { + /* + * If the open parenthesis was the first thing on the line or we + * are doing mode 1, then put the close parenthesis in the same + * column + */ + LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_paren_close is 1\n", + __func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol()); + indent_column_set(ck1->GetColumn()); + LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_column set to %zu\n", + __func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol(), indent_column); + } + else + { + if (options::indent_paren_close() != 2) + { + // indent_paren_close is 0 or 1 + LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_paren_close is 0 or 1\n", + __func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol()); + indent_column_set(frm.poped().indent_tmp); + LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_column set to %zu\n", + __func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol(), indent_column); + pc->SetColumnIndent(frm.poped().indent_tab); + log_rule_B("indent_paren_close"); + + if (options::indent_paren_close() == 1) + { + LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_paren_close is 1\n", + __func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol()); + + if (indent_column == 0) + { + fprintf(stderr, "%s(%d): indent_column is ZERO, cannot be decremented, at line %zu, column %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + indent_column--; + LOG_FMT(LINDLINE, "%s(%d): [%zu:%zu] indent_column set to %zu\n", + __func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol(), indent_column); + } + } + else + { + // indent_paren_close is 2: Indent to the brace level + LOG_FMT(LINDLINE, "%s(%d): indent_paren_close is 2\n", + __func__, __LINE__); + LOG_FMT(LINDLINE, "%s(%d): ck2 orig line is %zu, orig col is %zu, ck2->Text() is '%s'\n", + __func__, __LINE__, ck2->GetOrigLine(), ck2->GetOrigCol(), ck2->Text()); + + if (pc->GetPrev()->GetType() == CT_NEWLINE) + { + LOG_FMT(LINDLINE, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + LOG_FMT(LINDLINE, "%s(%d): prev is <newline>\n", + __func__, __LINE__); + Chunk *search = pc; + + while (search->GetNext()->IsParenClose()) + { + search = search->GetNext(); + } + Chunk *searchNext = search->GetNext(); + + // Issue #3407 - Skip over a possible 'noexcept' keyword before going forward. + if (searchNext->GetType() == CT_NOEXCEPT) + { + searchNext = searchNext->GetNext(); + } + + if ( searchNext->GetType() == CT_SEMICOLON + || searchNext->GetType() == CT_MEMBER // Issue #2582 + || searchNext->GetType() == CT_NEWLINE) + { + LOG_FMT(LINDLINE, "%s(%d):\n", __func__, __LINE__); + search = search->GetOpeningParen(); + + if ( options::indent_oc_inside_msg_sel() + && search->GetPrevNcNnl()->Is(CT_OC_COLON) + && ( frm.top().type == CT_OC_MSG_FUNC + || frm.top().type == CT_OC_MSG_NAME)) // Issue #2658 + { + log_rule_B("indent_oc_inside_msg_sel"); + // [Class Message:(...)<here> + indent_column_set(frm.top().pc->GetColumn()); + } + else if ( options::indent_inside_ternary_operator() + && ( frm.top().type == CT_QUESTION + || frm.top().type == CT_COND_COLON)) // Issue #1130, #1715 + { + log_rule_B("indent_inside_ternary_operator"); + indent_column_set(frm.top().indent); + } + else + { + search = search->GetPrevNl()->GetNext(); + + if (search->IsNullChunk()) + { + search = Chunk::GetHead(); + } + indent_column_set(search->GetColumn()); + } + } + } + } + } + } + size_t indent_value = 0; + LOG_FMT(LINDENT, "%s(%d): orig line is %zu, closing parenthesis => %zu, text is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + LOG_FMT(LINDENT, "%s(%d): [%s/%s]\n", + __func__, __LINE__, + get_token_name(pc->GetType()), get_token_name(pc->GetParentType())); + Chunk *prev2 = pc->GetPrev(); // Issue #2930 + LOG_FMT(LINDENT, "%s(%d): prev2 is orig line is %zu, text is '%s'\n", + __func__, __LINE__, prev2->GetOrigLine(), prev2->Text()); + Chunk *next2 = pc->GetNext(); + LOG_FMT(LINDENT, "%s(%d): next2 is orig line is %zu, text is '%s'\n", + __func__, __LINE__, next2->GetOrigLine(), next2->Text()); + + if ( pc->GetParentType() == CT_FUNC_DEF + && prev2->IsNewline() + && next2->IsNewline()) + { + if (options::donot_indent_func_def_close_paren()) + { + indent_value = 1; + } + else + { + reindent_line(pc, indent_column); + indent_value = indent_column; + } + } + else + { + indent_value = indent_column; + } + reindent_line(pc, indent_value); + } + else if (pc->Is(CT_COMMA)) + { + bool indent_align = false; + bool indent_ignore = false; + + if (frm.top().pc->IsParenOpen()) + { + log_rule_B("indent_comma_paren"); + indent_align = options::indent_comma_paren() == (int)indent_mode_e::ALIGN; + indent_ignore = options::indent_comma_paren() == (int)indent_mode_e::IGNORE; + } + else if (frm.top().pc->IsBraceOpen()) + { + log_rule_B("indent_comma_brace"); + indent_align = options::indent_comma_brace() == (int)indent_mode_e::ALIGN; + indent_ignore = options::indent_comma_brace() == (int)indent_mode_e::IGNORE; + } + + if (indent_ignore) + { + indent_column_set(pc->GetOrigCol()); + } + else if (indent_align) + { + indent_column_set(frm.top().pc->GetColumn()); + } + LOG_FMT(LINDENT, "%s(%d): %zu] comma => %zu [%s]\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + reindent_line(pc, indent_column); + } + else if ( options::indent_func_const() + && pc->Is(CT_QUALIFIER) + && strncasecmp(pc->Text(), "const", pc->Len()) == 0 + && ( next == nullptr + || next->Is(CT_BRACED) + || next->IsBraceOpen() + || next->Is(CT_NEWLINE) + || next->Is(CT_SEMICOLON) + || next->Is(CT_THROW))) + { + // indent const - void GetFoo(void)\n const\n { return (m_Foo); } + log_rule_B("indent_func_const"); + indent_column_set(frm.top().indent + options::indent_func_const()); + LOG_FMT(LINDENT, "%s(%d): %zu] const => %zu [%s]\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + reindent_line(pc, indent_column); + } + else if ( options::indent_func_throw() + && pc->Is(CT_THROW) + && pc->GetParentType() != CT_NONE) + { + // indent throw - void GetFoo(void)\n throw()\n { return (m_Foo); } + log_rule_B("indent_func_throw"); + indent_column_set(options::indent_func_throw()); + LOG_FMT(LINDENT, "%s(%d): %zu] throw => %zu [%s]\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + reindent_line(pc, indent_column); + } + else if (pc->Is(CT_SEMICOLON)) + { + if ( pc->TestFlags(PCF_IN_FOR) + && options::indent_semicolon_for_paren()) + { + log_rule_B("indent_semicolon_for_paren"); + indent_column_set(frm.top().pc->GetColumn()); + + log_rule_B("indent_first_for_expr"); + + if (options::indent_first_for_expr()) + { + reindent_line(frm.top().pc->GetNext(), + indent_column + pc->Len() + 1); + } + LOG_FMT(LINDENT, "%s(%d): %zu] SEMICOLON => %zu [%s]\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + reindent_line(pc, indent_column); + } + else + { + log_rule_B("indent_ignore_semicolon"); + + if (options::indent_ignore_semicolon()) + { + indent_column_set(pc->GetOrigCol()); + } + LOG_FMT(LINDENT, "%s(%d): %zu] semicolon => %zu [%s]\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + reindent_line(pc, indent_column); + } + } + else if (pc->Is(CT_BOOL)) + { + if (frm.top().pc->IsParenOpen()) + { + log_rule_B("indent_bool_paren"); + + if (options::indent_bool_paren() == (int)indent_mode_e::IGNORE) + { + indent_column_set(pc->GetOrigCol()); + } + else if (options::indent_bool_paren() == (int)indent_mode_e::ALIGN) + { + indent_column_set(frm.top().pc->GetColumn()); + + log_rule_B("indent_first_bool_expr"); + + if (options::indent_first_bool_expr()) + { + reindent_line(frm.top().pc->GetNext(), + indent_column + pc->Len() + 1); + } + } + } + else + { + log_rule_B("indent_ignore_bool"); + + if (options::indent_ignore_bool()) + { + indent_column_set(pc->GetOrigCol()); + } + } + LOG_FMT(LINDENT, "%s(%d): %zu] bool => %zu [%s]\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + reindent_line(pc, indent_column); + } + else if ( pc->Is(CT_ARITH) + || pc->Is(CT_CARET)) + { + log_rule_B("indent_ignore_arith"); + + if (options::indent_ignore_arith()) + { + indent_column_set(pc->GetOrigCol()); + } + LOG_FMT(LINDENT, "%s(%d): %zu] arith => %zu [%s]\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + reindent_line(pc, indent_column); + } + else if (pc->Is(CT_SHIFT)) + { + log_rule_B("indent_shift"); + + if (options::indent_shift() == -1) + { + indent_column_set(pc->GetOrigCol()); + } + LOG_FMT(LINDENT, "%s(%d): %zu] shift => %zu [%s]\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + reindent_line(pc, indent_column); + } + else if (pc->Is(CT_ASSIGN)) + { + log_rule_B("indent_ignore_assign"); + + if (options::indent_ignore_assign()) + { + indent_column_set(pc->GetOrigCol()); + } + LOG_FMT(LINDENT, "%s(%d): %zu] assign => %zu [%s]\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + reindent_line(pc, indent_column); + } + else if ( options::indent_ternary_operator() == 1 + && prev->Is(CT_COND_COLON)) + { + log_rule_B("indent_ternary_operator"); + Chunk *tmp = prev->GetPrevType(CT_QUESTION); + + if (tmp->IsNotNullChunk()) + { + tmp = tmp->GetNextNcNnl(); + + if (tmp->IsNotNullChunk()) + { + LOG_FMT(LINDENT, "%s: %zu] ternarydefcol => %zu [%s]\n", + __func__, pc->GetOrigLine(), tmp->GetColumn(), pc->Text()); + reindent_line(pc, tmp->GetColumn()); + } + } + } + else if ( options::indent_ternary_operator() == 2 + && pc->Is(CT_COND_COLON)) + { + log_rule_B("indent_ternary_operator"); + Chunk *tmp = pc->GetPrevType(CT_QUESTION); + + if (tmp->IsNotNullChunk()) + { + LOG_FMT(LINDENT, "%s: %zu] ternarydefcol => %zu [%s]\n", + __func__, pc->GetOrigLine(), tmp->GetColumn(), pc->Text()); + reindent_line(pc, tmp->GetColumn()); + } + } + else if ( options::indent_oc_inside_msg_sel() + && ( pc->Is(CT_OC_MSG_FUNC) + || pc->Is(CT_OC_MSG_NAME))) // Issue #2658 + { + log_rule_B("indent_oc_inside_msg_sel"); + reindent_line(pc, frm.top().indent); + } + else + { + bool use_indent = true; + const size_t ttidx = frm.size() - 1; + + if (ttidx > 0) + { + LOG_FMT(LINDPC, "%s(%d): (frm.at(ttidx).pc)->GetParentType() is %s\n", + __func__, __LINE__, get_token_name((frm.at(ttidx).pc)->GetParentType())); + + if ((frm.at(ttidx).pc)->GetParentType() == CT_FUNC_CALL) + { + LOG_FMT(LINDPC, "FUNC_CALL OK [%d]\n", __LINE__); + + log_rule_B("use_indent_func_call_param"); + + if (options::use_indent_func_call_param()) + { + LOG_FMT(LINDPC, "use is true [%d]\n", __LINE__); + } + else + { + LOG_FMT(LINDPC, "use is false [%d]\n", __LINE__); + use_indent = false; + } + } + } + LOG_FMT(LINDENT, "%s(%d): pc->line is %zu, pc->GetColumn() is %zu, pc->Text() is '%s, indent_column is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetColumn(), pc->Text(), indent_column); + + if ( use_indent + && pc->IsNot(CT_PP_IGNORE)) // Leave indentation alone for PP_IGNORE tokens + { + log_rule_B("pos_conditional"); + + if ( ( pc->Is(CT_QUESTION) // Issue #2101 + || pc->Is(CT_COND_COLON)) // Issue #2101 + && options::pos_conditional() == TP_IGNORE) + { + // do not indent this line + LOG_FMT(LINDENT, "%s(%d): %zu] don't indent this line\n", + __func__, __LINE__, pc->GetOrigLine()); + } + else if (pc->Is(CT_BREAK)) + { + // Issue #1692 + log_rule_B("indent_switch_break_with_case"); + + // Issue #2281 + if ( options::indent_switch_break_with_case() + && pc->GetTypeOfParent() == CT_SWITCH) + { + // look for a case before Issue #2735 + Chunk *whereIsCase = pc->GetPrevType(CT_CASE, pc->GetLevel()); + + if (whereIsCase->IsNotNullChunk()) + { + LOG_FMT(LINDENT, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, whereIsCase->GetOrigLine(), whereIsCase->GetOrigCol(), whereIsCase->Text()); + LOG_FMT(LINDENT, "%s(%d): column is %zu\n", + __func__, __LINE__, whereIsCase->GetColumn()); + reindent_line(pc, whereIsCase->GetColumn()); + } + } + else + { + LOG_FMT(LINDENT, "%s(%d): orig line is %zu, indent_column set to %zu, for '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + reindent_line(pc, indent_column); + } + } + else if ( pc->Is(CT_MEMBER) // Issue #2890 + && language_is_set(LANG_CPP)) + { + // comment name: XXXXXXXXXXXXXXXXXXXXXXXXXX + LOG_FMT(LINDENT, "%s(%d): orig line is %zu, indent_column set to %zu, for '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + const size_t frm_size = frm.size(); + LOG_FMT(LINDPC, "%s(%d): frm_size is %zu\n", + __func__, __LINE__, frm_size); + // get pc + LOG_FMT(LINDPC, "%s(%d): Text() is '%s', (frm.at(frm_size - 1).pc)->GetType() is %s\n", + __func__, __LINE__, (frm.at(frm_size - 1).pc)->Text(), get_token_name((frm.at(frm_size - 1).pc)->GetType())); + // get the token before + const size_t temp_ttidx = frm_size - 2; + + if (temp_ttidx == 0) + { + indent_column = 1 + indent_size; + reindent_line(pc, indent_column); + } + else + { + Chunk *token_before = frm.at(temp_ttidx).pc; + LOG_FMT(LINDPC, "%s(%d): Text() is '%s', token_before->GetType() is %s\n", + __func__, __LINE__, token_before->Text(), get_token_name(token_before->GetType())); + + size_t vor_col = 0; + + if (token_before->Is(CT_ASSIGN)) + { + Chunk *before_Assign = frm.at(temp_ttidx - 1).pc; + + if (before_Assign->IsNullChunk()) + { + indent_column = 1 + indent_size; + } + else + { + vor_col = before_Assign->GetColumn(); + LOG_FMT(LINDPC, "%s(%d): Text() is '%s', before_Assign->GetType() is %s, column is %zu\n", + __func__, __LINE__, before_Assign->Text(), get_token_name(before_Assign->GetType()), vor_col); + indent_column = vor_col + 2 * indent_size; + } + } + else if (token_before->Is(CT_BRACE_OPEN)) + { + vor_col = token_before->GetColumn(); + LOG_FMT(LINDPC, "%s(%d): Text() is '%s', token_before->GetType() is %s, column is %zu\n", + __func__, __LINE__, token_before->Text(), get_token_name(token_before->GetType()), vor_col); + indent_column = vor_col + 2 * indent_size; + } + else if (token_before->Is(CT_RETURN)) + { + Chunk *before_Return = frm.at(temp_ttidx - 1).pc; + vor_col = before_Return->GetColumn(); + LOG_FMT(LINDPC, "%s(%d): Text() is '%s', before_Return->GetType() is %s, column is %zu\n", + __func__, __LINE__, before_Return->Text(), get_token_name(before_Return->GetType()), vor_col); + indent_column = vor_col + 2 * indent_size; + } + else + { + // TO DO + } + reindent_line(pc, indent_column); + } + reindent_line(pc, indent_column); + } + else + { + LOG_FMT(LINDENT, "%s(%d): orig line is %zu, indent_column set to %zu, for '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), indent_column, pc->Text()); + reindent_line(pc, indent_column); + } + } + else + { + // do not indent this line + LOG_FMT(LINDENT, "%s(%d): %zu] don't indent this line\n", + __func__, __LINE__, pc->GetOrigLine()); + } + } + did_newline = false; + + if ( pc->Is(CT_SQL_EXEC) + || pc->Is(CT_SQL_BEGIN) + || pc->Is(CT_SQL_END)) + { + sql_col = pc->GetColumn(); + sql_orig_col = pc->GetOrigCol(); + } + + // Handle indent for variable defs at the top of a block of code + if (pc->TestFlags(PCF_VAR_TYPE)) + { + if ( !frm.top().non_vardef + && (frm.top().type == CT_BRACE_OPEN)) + { + log_rule_B("indent_var_def_blk"); + int val = options::indent_var_def_blk(); + + if (val != 0) + { + size_t indent = indent_column; + indent = (val > 0) ? val // reassign if positive val, + : ((size_t)(abs(val)) < indent) // else if no underflow + ? (indent + val) : 0; // reduce, else 0 + + LOG_FMT(LINDENT, "%s(%d): %zu] var_type indent => %zu [%s]\n", + __func__, __LINE__, pc->GetOrigLine(), indent, pc->Text()); + reindent_line(pc, indent); + } + } + } + else if (pc != frm.top().pc) + { + frm.top().non_vardef = true; + } + } + + // if we hit a newline, reset indent_tmp + if ( pc->IsNewline() + || pc->Is(CT_COMMENT_MULTI) + || pc->Is(CT_COMMENT_CPP)) + { + log_indent(); + frm.top().indent_tmp = frm.top().indent; + log_indent_tmp(); + + /* + * Handle the case of a multi-line #define w/o anything on the + * first line (indent_tmp will be 1 or 0) + */ + if ( pc->Is(CT_NL_CONT) + && frm.top().indent_tmp <= indent_size + && frm.top().type != CT_PP_DEFINE) + { + frm.top().indent_tmp = indent_size + 1; + log_indent_tmp(); + } + // Get ready to indent the next item + did_newline = true; + } + // Check for open XML tags "</..." + log_rule_B("indent_xml_string"); + + if ( options::indent_xml_string() > 0 + && pc->Is(CT_STRING) + && pc->Len() > 4 + && pc->GetStr()[1] == '<' + && pc->GetStr()[2] != '/' + && pc->GetStr()[pc->Len() - 3] != '/') + { + if (xml_indent <= 0) + { + xml_indent = pc->GetColumn(); + } + log_rule_B("indent_xml_string"); + xml_indent += options::indent_xml_string(); + } + // Issue #672 + log_rule_B("indent_continue_class_head"); + + if ( pc->Is(CT_CLASS) + && language_is_set(LANG_CPP | LANG_JAVA) + && ( options::indent_ignore_first_continue() + || options::indent_continue_class_head() != 0) + && !classFound) + { + LOG_FMT(LINDENT, "%s(%d): orig line is %zu, CT_CLASS found, OPEN IT\n", + __func__, __LINE__, pc->GetOrigLine()); + frm.push(pc, __func__, __LINE__); + + if (options::indent_ignore_first_continue()) + { + frm.top().indent = get_indent_first_continue(pc); + } + else + { + frm.top().indent = frm.prev().indent + options::indent_continue_class_head(); + } + log_indent(); + + frm.top().indent_tmp = frm.top().indent; + frm.top().indent_tab = frm.top().indent; + log_indent_tmp(); + classFound = true; + } + pc = pc->GetNext(); + + if (pc->Is(CT_SPACE)) // Issue #3710 + { + pc = pc->GetNext(); + } + LOG_FMT(LINDLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + } +null_pc: + + // Throw out any stuff inside a preprocessor - no need to warn + while ( !frm.empty() + && frm.top().in_preproc) + { + frm.pop(__func__, __LINE__, pc); + } + + // Throw out any VBRACE_OPEN at the end - implied with the end of file + while ( !frm.empty() + && frm.top().type == CT_VBRACE_OPEN) + { + frm.pop(__func__, __LINE__, pc); + } + + for (size_t idx_temp = 1; idx_temp < frm.size(); idx_temp++) + { + LOG_FMT(LWARN, "%s(%d): size is %zu\n", + __func__, __LINE__, frm.size()); + LOG_FMT(LWARN, "%s(%d): File: %s, open_line is %zu, parent is %s: Unmatched %s\n", + __func__, __LINE__, cpd.filename.c_str(), frm.at(idx_temp).open_line, + get_token_name(frm.at(idx_temp).parent), + get_token_name(frm.at(idx_temp).type)); + exit(EX_IOERR); + } + + LOG_FMT(LINDLINE, "%s(%d): before quick_align_again\n", __func__, __LINE__); + quick_align_again(); + quick_indent_again(); + LOG_FMT(LINDLINE, "%s(%d): after quick_align_again\n", __func__, __LINE__); +} // indent_text + + +static bool single_line_comment_indent_rule_applies(Chunk *start, bool forward) +{ + LOG_FUNC_ENTRY(); + + if (!start->IsSingleLineComment()) + { + return(false); + } + Chunk *pc = start; + size_t nl_count = 0; + + while ((pc = forward ? pc->GetNext() : pc->GetPrev())->IsNotNullChunk()) + { + if (pc->IsNewline()) + { + if ( nl_count > 0 + || pc->GetNlCount() > 1) + { + return(false); + } + nl_count++; + } + else if (pc->IsSingleLineComment()) + { + nl_count = 0; + } + else if ( pc->Is(CT_COMMENT_MULTI) + || (forward && pc->IsBraceClose()) + || (!forward && pc->IsBraceOpen())) + { + /* + * check for things we wouldn't want to indent the comment for + * example: non-single line comment, closing brace + */ + return(false); + } + else + { + return(true); + } + } + return(false); +} // single_line_comment_indent_rule_applies + + +static bool is_end_of_assignment(Chunk *pc, const ParseFrame &frm) +{ + return( ( frm.top().type == CT_ASSIGN_NL + || frm.top().type == CT_MEMBER + || frm.top().type == CT_ASSIGN) + && ( pc->IsSemicolon() + || pc->Is(CT_COMMA) + || pc->Is(CT_BRACE_OPEN) + || pc->Is(CT_SPAREN_CLOSE) + || ( pc->Is(CT_SQUARE_OPEN) + && pc->GetParentType() == CT_ASSIGN)) + && pc->GetParentType() != CT_CPP_LAMBDA); +} + + +static size_t calc_comment_next_col_diff(Chunk *pc) +{ + Chunk *next = pc; // assumes pc has a comment type + + LOG_FMT(LCMTIND, "%s(%d): next->Text() is '%s'\n", + __func__, __LINE__, next->Text()); + + // Note: every comment is squashed into a single token + // (including newline chars for multiline comments) and is followed by + // a newline token (unless there are no more tokens left) + do + { + Chunk *newline_token = next->GetNext(); + LOG_FMT(LCMTIND, "%s(%d): newline_token->Text() is '%s', orig line is %zu, orig col is %zu\n", + __func__, __LINE__, newline_token->Text(), newline_token->GetOrigLine(), newline_token->GetOrigCol()); + + if ( newline_token->IsNullChunk() + || newline_token->GetNlCount() > 1) + { + return(5000); // FIXME: Max thresh magic number 5000 + } + next = newline_token->GetNext(); + + if (next->IsNotNullChunk()) + { + LOG_FMT(LCMTIND, "%s(%d): next->Text() is '%s', orig line is %zu, orig col is %zu\n", + __func__, __LINE__, next->Text(), next->GetOrigLine(), next->GetOrigCol()); + } + } while (next->IsComment()); + + if (next->IsNullChunk()) + { + return(5000); // FIXME: Max thresh magic number 5000 + } + LOG_FMT(LCMTIND, "%s(%d): next->Text() is '%s'\n", + __func__, __LINE__, next->Text()); + // here next is the first non comment, non newline token + return(next->GetOrigCol() > pc->GetOrigCol() + ? next->GetOrigCol() - pc->GetOrigCol() + : pc->GetOrigCol() - next->GetOrigCol()); +} + + +static void indent_comment(Chunk *pc, size_t col) +{ + LOG_FUNC_ENTRY(); + char copy[1000]; + + LOG_FMT(LCMTIND, "%s(%d): pc->Text() is '%s', orig line %zu, orig col %zu, level %zu\n", + __func__, __LINE__, pc->ElidedText(copy), pc->GetOrigLine(), pc->GetOrigCol(), pc->GetLevel()); + + // force column 1 comment to column 1 if not changing them + log_rule_B("indent_col1_comment"); + + if ( pc->GetOrigCol() == 1 + && !options::indent_col1_comment() + && !pc->TestFlags(PCF_INSERTED)) + { + LOG_FMT(LCMTIND, "%s(%d): rule 1 - keep in col 1\n", __func__, __LINE__); + reindent_line(pc, 1); + return; + } + Chunk *nl = pc->GetPrev(); + + if (nl->IsNotNullChunk()) + { + LOG_FMT(LCMTIND, "%s(%d): nl->Text() is '%s', orig line %zu, orig col %zu, level %zu\n", + __func__, __LINE__, nl->Text(), nl->GetOrigLine(), nl->GetOrigCol(), nl->GetLevel()); + } + + if (pc->GetOrigCol() > 1) + { + Chunk *prev = nl->GetPrev(); + + if (prev->IsNotNullChunk()) + { + LOG_FMT(LCMTIND, "%s(%d): prev->Text() is '%s', orig line %zu, orig col %zu, level %zu\n", + __func__, __LINE__, prev->Text(), prev->GetOrigLine(), prev->GetOrigCol(), prev->GetLevel()); + log_pcf_flags(LCMTIND, prev->GetFlags()); + } + + if ( prev->IsComment() + && nl->GetNlCount() == 1) + { + const size_t prev_col_diff = (prev->GetOrigCol() > pc->GetOrigCol()) + ? prev->GetOrigCol() - pc->GetOrigCol() + : pc->GetOrigCol() - prev->GetOrigCol(); + LOG_FMT(LCMTIND, "%s(%d): prev_col_diff is %zu\n", + __func__, __LINE__, prev_col_diff); + + /* + * Here we want to align comments that are relatively close one to + * another but not when the comment is a Doxygen comment (Issue #1134) + */ + if (prev_col_diff <= options::indent_comment_align_thresh()) + { + LOG_FMT(LCMTIND, "%s(%d): prev->Text() is '%s', Doxygen_comment(prev) is %s\n", + __func__, __LINE__, prev->Text(), prev->IsDoxygenComment() ? "TRUE" : "FALSE"); + LOG_FMT(LCMTIND, "%s(%d): pc->Text() is '%s', Doxygen_comment(pc) is %s\n", + __func__, __LINE__, pc->Text(), pc->IsDoxygenComment() ? "TRUE" : "FALSE"); + + if (prev->IsDoxygenComment() == pc->IsDoxygenComment()) + { + const size_t next_col_diff = calc_comment_next_col_diff(pc); + LOG_FMT(LCMTIND, "%s(%d): next_col_diff is %zu\n", + __func__, __LINE__, next_col_diff); + + // Align to the previous comment or to the next token? + if ( prev_col_diff <= next_col_diff + || next_col_diff == 5000) // FIXME: Max thresh magic number 5000 + { + LOG_FMT(LCMTIND, "%s(%d): rule 3 - prev comment, coldiff = %zu, now in %zu\n", + __func__, __LINE__, prev_col_diff, pc->GetColumn()); + reindent_line(pc, prev->GetColumn()); + return; + } + } + } + } + } + // check if special single-line-comment-before-code rule applies + log_rule_B("indent_single_line_comments_before"); + + if ( (options::indent_single_line_comments_before() > 0) + && single_line_comment_indent_rule_applies(pc, true)) + { + LOG_FMT(LCMTIND, "%s(%d): rule 4 - indent single line comments before code, now in %zu\n", + __func__, __LINE__, pc->GetColumn()); + reindent_line(pc, col + options::indent_single_line_comments_before()); + return; + } + // check if special single-line-comment-after-code rule applies + log_rule_B("indent_single_line_comments_after"); + + if ( (options::indent_single_line_comments_after() > 0) + && single_line_comment_indent_rule_applies(pc, false)) + { + LOG_FMT(LCMTIND, "%s(%d): rule 4 - indent single line comments after code, now in %zu\n", + __func__, __LINE__, pc->GetColumn()); + reindent_line(pc, col + options::indent_single_line_comments_after()); + return; + } + log_rule_B("indent_comment"); + + if ( pc->GetOrigCol() > 1 + && !options::indent_comment()) + { + LOG_FMT(LCMTIND, "%s(%d): rule 5 - keep in orig col\n", __func__, __LINE__); + reindent_line(pc, pc->GetOrigCol()); + return; + } + LOG_FMT(LCMTIND, "%s(%d): rule 6 - fall-through, stay in %zu\n", + __func__, __LINE__, col); + reindent_line(pc, col); +} // indent_comment + + +bool ifdef_over_whole_file() +{ + LOG_FUNC_ENTRY(); + + // if requested, treat an #if that guards the entire file the same as any other #if + // if running as frag, assume #if is not a guard + if ( options::pp_indent_in_guard() + || cpd.frag) + { + return(false); + } + + // the results for this file are cached + if (cpd.ifdef_over_whole_file) + { + return(cpd.ifdef_over_whole_file > 0); + } + Chunk *start_pp = Chunk::NullChunkPtr; + Chunk *end_pp = Chunk::NullChunkPtr; + size_t IFstage = 0; + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + LOG_FMT(LNOTE, "%s(%d): pc->pp level is %zu, pc orig line is %zu, orig col is %zu, pc->Text() is '%s'\n", + __func__, __LINE__, pc->GetPpLevel(), pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + + if (pc->IsCommentOrNewline()) + { + continue; + } + + if (IFstage == 0) // 0 is BEGIN + { + // Check the first preprocessor, make sure it is an #if type + if (pc->IsNot(CT_PREPROC)) + { + break; + } + Chunk *next = pc->GetNext(); + + if ( next->IsNullChunk() + || next->IsNot(CT_PP_IF)) + { + break; + } + IFstage = 1; // 1 is CT_PP_IF found + start_pp = pc; + } + else if (IFstage == 1) // 1 is CT_PP_IF found + { + // Scan until a preprocessor at level 0 is found - the close to the #if + if (pc->Is(CT_PREPROC)) + { + if (pc->GetPpLevel() == 0) + { + IFstage = 2; + end_pp = pc; + } + } + continue; + } + else if (IFstage == 2) + { + // We should only see the rest of the preprocessor + if ( pc->Is(CT_PREPROC) + || !pc->TestFlags(PCF_IN_PREPROC)) + { + IFstage = 0; + break; + } + } + } + + cpd.ifdef_over_whole_file = (IFstage == 2) ? 1 : -1; + + if (cpd.ifdef_over_whole_file > 0) + { + start_pp->SetFlagBits(PCF_WF_IF); + end_pp->SetFlagBits(PCF_WF_ENDIF); + } + LOG_FMT(LNOTE, "The whole file is%s covered by a #IF\n", + (cpd.ifdef_over_whole_file > 0) ? "" : " NOT"); + return(cpd.ifdef_over_whole_file > 0); +} // ifdef_over_whole_file + + +void indent_preproc() +{ + LOG_FUNC_ENTRY(); + + // Scan to see if the whole file is covered by one #ifdef + const size_t pp_level_sub = ifdef_over_whole_file() ? 1 : 0; + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + LOG_FMT(LPPIS, "%s(%d): orig line is %zu, orig col is %zu, pc->Text() is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + + if (pc->IsNot(CT_PREPROC)) + { + continue; + } + Chunk *next = pc->GetNextNcNnl(); + + if (next->IsNullChunk()) + { + break; + } + const size_t pp_level = (pc->GetPpLevel() > pp_level_sub) + ? pc->GetPpLevel() - pp_level_sub : 0; + + // Adjust the indent of the '#' + if (options::pp_indent() & IARF_ADD) + { + log_rule_B("pp_indent ADD"); + reindent_line(pc, 1 + pp_level * options::pp_indent_count()); + } + else if (options::pp_indent() & IARF_REMOVE) + { + log_rule_B("pp_indent REMOVE"); + reindent_line(pc, 1); + } + // Add spacing by adjusting the length + log_rule_B("pp_space_after"); + + if ( (options::pp_space_after() != IARF_IGNORE) + && next->IsNotNullChunk()) + { + if (options::pp_space_after() & IARF_ADD) + { + log_rule_B("pp_space_after ADD"); + const size_t mult = options::pp_space_count(); + reindent_line(next, pc->GetColumn() + pc->Len() + (pp_level * mult)); + } + else if (options::pp_space_after() & IARF_REMOVE) + { + log_rule_B("pp_space_after REMOVE"); + reindent_line(next, pc->GetColumn() + pc->Len()); + } + } + // Mark as already handled if not region stuff or in column 1 + log_rule_B("pp_indent_at_level"); + + bool at_file_level = pc->GetBraceLevel() <= ((pc->GetParentType() == CT_PP_DEFINE) ? 1 : 0); + + if ( ( ( at_file_level + && !options::pp_indent_at_level0()) + || ( !at_file_level + && !options::pp_indent_at_level())) + && pc->GetParentType() != CT_PP_REGION + && pc->GetParentType() != CT_PP_ENDREGION) + { + log_rule_B("pp_define_at_level"); + + if ( !options::pp_define_at_level() + || pc->GetParentType() != CT_PP_DEFINE) + { + pc->SetFlagBits(PCF_DONT_INDENT); + } + } + LOG_FMT(LPPIS, "%s(%d): orig line %zu to %zu (len %zu, next->col %zu)\n", + __func__, __LINE__, pc->GetOrigLine(), 1 + pp_level, pc->Len(), + next ? next->GetColumn() : -1); + } +} // indent_preproc diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/indent.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/indent.h new file mode 100644 index 00000000..e1fe384c --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/indent.h @@ -0,0 +1,59 @@ +/** + * @file indent.h + * prototypes for indent.c + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef INDENT_H_INCLUDED +#define INDENT_H_INCLUDED + +#include "uncrustify_types.h" + + +/** + * Change the top-level indentation only by changing the column member in + * the chunk structures. + * The level indicator must already be set. + */ +void indent_text(); + + +/** + * Indent the preprocessor stuff from column 1. + * FIXME: This is broken if there is a comment or escaped newline + * between '#' and 'define'. + */ +void indent_preproc(); + +/** + * + * @param pc chunk at the start of the line + * @param column desired column + */ +void indent_to_column(Chunk *pc, size_t column); + + +/** + * Same as indent_to_column, except we can move both ways + * + * @param pc chunk at the start of the line + * @param column desired column + */ +void align_to_column(Chunk *pc, size_t column); + + +//! Scan to see if the whole file is covered by one #ifdef +bool ifdef_over_whole_file(); + + +/** + * Changes the initial indent for a line to the given column + * + * @param pc The chunk at the start of the line + * @param column The desired column + */ +void reindent_line(Chunk *pc, size_t column); + + +#endif /* INDENT_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/keywords.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/keywords.cpp new file mode 100644 index 00000000..6b4757ca --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/keywords.cpp @@ -0,0 +1,679 @@ +/** + * @file keywords.cpp + * Manages the table of keywords. + * + * @author Ben Gardner + * @author Guy Maurel since version 0.62 for uncrustify4Qt + * October 2015, 2016 + * @license GPL v2+ + */ + +#include "keywords.h" + +#include "args.h" +#include "prototypes.h" +#include "uncrustify.h" +#include "uncrustify_limits.h" + +#include <cerrno> +#include <map> + + +using namespace std; + +// Dynamic keyword map +typedef map<string, E_Token> dkwmap; +static dkwmap dkwm; + + +/** + * Compares two chunk_tag_t entries using strcmp on the strings + * + * @param the 'left' entry + * @param the 'right' entry + * + * @return == 0 if both keywords are equal + * @return < 0 p1 is smaller than p2 + * @return > 0 p2 is smaller than p1 + */ +static int kw_compare(const void *p1, const void *p2); + + +/** + * search in static keywords for first occurrence of a given tag + * + * @param tag/keyword to search for + */ +static const chunk_tag_t *kw_static_first(const chunk_tag_t *tag); + + +static const chunk_tag_t *kw_static_match(bool orig_list, const chunk_tag_t *tag, int lang_flags); + +/** + * selected keywords for the chosen language. + */ + +static chunk_tag_t keyword_for_lang[uncrustify::limits::MAX_KEYWORDS]; +static size_t language_count; + +/** + * interesting static keywords - keep sorted. + * Table includes the Name, Type, and Language flags. + */ +static chunk_tag_t keywords[] = +{ + // TODO: it might be useful if users could add their custom keywords to this list + { "@autoreleasepool", CT_AUTORELEASEPOOL, LANG_OC }, + { "@available", CT_OC_AVAILABLE, LANG_OC }, + { "@catch", CT_CATCH, LANG_OC }, + { "@dynamic", CT_OC_DYNAMIC, LANG_OC }, + { "@end", CT_OC_END, LANG_OC }, + { "@finally", CT_FINALLY, LANG_OC }, + { "@implementation", CT_OC_IMPL, LANG_OC }, + { "@interface", CT_OC_INTF, LANG_OC }, + { "@interface", CT_CLASS, LANG_JAVA }, + { "@private", CT_ACCESS, LANG_OC }, + { "@property", CT_OC_PROPERTY, LANG_OC }, + { "@protected", CT_ACCESS, LANG_OC }, + { "@protocol", CT_OC_PROTOCOL, LANG_OC }, + { "@public", CT_ACCESS, LANG_OC }, + { "@selector", CT_OC_SEL, LANG_OC }, + { "@synchronized", CT_SYNCHRONIZED, LANG_OC }, + { "@synthesize", CT_OC_DYNAMIC, LANG_OC }, + { "@throw", CT_THROW, LANG_OC }, + { "@try", CT_TRY, LANG_OC }, + { "API_AVAILABLE", CT_ATTRIBUTE, LANG_OC }, + { "API_DEPRECATED", CT_ATTRIBUTE, LANG_OC }, + { "API_DEPRECATED_WITH_REPLACEMENT", CT_ATTRIBUTE, LANG_OC }, + { "API_UNAVAILABLE", CT_ATTRIBUTE, LANG_OC }, + { "BOOL", CT_TYPE, LANG_OC }, + { "INT16_C", CT_TYPE, LANG_CPP }, + { "INT32_C", CT_TYPE, LANG_CPP }, + { "INT64_C", CT_TYPE, LANG_CPP }, + { "INT8_C", CT_TYPE, LANG_CPP }, + { "INTMAX_C", CT_TYPE, LANG_CPP }, + { "NS_ENUM", CT_ENUM, LANG_OC }, + { "NS_OPTIONS", CT_ENUM, LANG_OC }, + { "Q_EMIT", CT_Q_EMIT, LANG_CPP }, + { "Q_FOREACH", CT_FOR, LANG_CPP }, + { "Q_FOREVER", CT_Q_FOREVER, LANG_CPP }, + { "Q_GADGET", CT_Q_GADGET, LANG_CPP }, + { "Q_OBJECT", CT_COMMENT_EMBED, LANG_CPP }, + { "Q_SIGNALS", CT_ACCESS, LANG_CPP }, + { "UINT16_C", CT_TYPE, LANG_CPP }, + { "UINT32_C", CT_TYPE, LANG_CPP }, + { "UINT64_C", CT_TYPE, LANG_CPP }, + { "UINT8_C", CT_TYPE, LANG_CPP }, + { "UINTMAX_C", CT_TYPE, LANG_CPP }, + { "_Bool", CT_TYPE, LANG_C | LANG_CPP }, + { "_Complex", CT_TYPE, LANG_C | LANG_CPP }, + { "_Imaginary", CT_TYPE, LANG_C | LANG_CPP }, + { "_Nonnull", CT_QUALIFIER, LANG_OC }, + { "_Null_unspecified", CT_QUALIFIER, LANG_OC }, + { "_Nullable", CT_QUALIFIER, LANG_OC }, + { "_Pragma", CT_PP_PRAGMA, LANG_ALL | FLAG_PP }, + { "__DI__", CT_DI, LANG_C | LANG_CPP }, + { "__HI__", CT_HI, LANG_C | LANG_CPP }, + { "__QI__", CT_QI, LANG_C | LANG_CPP }, + { "__SI__", CT_SI, LANG_C | LANG_CPP }, + { "__asm__", CT_ASM, LANG_C | LANG_CPP }, + { "__attribute__", CT_ATTRIBUTE, LANG_C | LANG_CPP | LANG_OC }, + { "__autoreleasing", CT_QUALIFIER, LANG_C | LANG_CPP }, + { "__block", CT_QUALIFIER, LANG_C | LANG_CPP | LANG_OC }, + { "__bridge", CT_QUALIFIER, LANG_C | LANG_CPP }, + { "__bridge_retained", CT_QUALIFIER, LANG_C | LANG_CPP }, + { "__bridge_transfer", CT_QUALIFIER, LANG_C | LANG_CPP }, + { "__const__", CT_QUALIFIER, LANG_C | LANG_CPP }, + { "__declspec", CT_DECLSPEC, LANG_C | LANG_CPP }, + { "__except", CT_CATCH, LANG_C | LANG_CPP }, + { "__finally", CT_FINALLY, LANG_C | LANG_CPP }, + { "__has_include", CT_CNG_HASINC, LANG_C | LANG_CPP | LANG_OC | FLAG_PP }, + { "__has_include_next", CT_CNG_HASINCN, LANG_C | LANG_CPP | FLAG_PP }, + { "__inline__", CT_QUALIFIER, LANG_C | LANG_CPP }, + { "__nonnull", CT_QUALIFIER, LANG_OC }, + { "__nothrow__", CT_NOTHROW, LANG_C | LANG_CPP }, + { "__null_unspecified", CT_QUALIFIER, LANG_OC }, + { "__nullable", CT_QUALIFIER, LANG_OC }, + { "__pragma", CT_PP_PRAGMA, LANG_ALL | FLAG_PP }, + { "__restrict", CT_QUALIFIER, LANG_C | LANG_CPP }, + { "__signed__", CT_TYPE, LANG_C | LANG_CPP }, + { "__strong", CT_QUALIFIER, LANG_C | LANG_CPP }, + { "__thread", CT_QUALIFIER, LANG_C | LANG_CPP }, + { "__traits", CT_QUALIFIER, LANG_D }, + { "__try", CT_TRY, LANG_C | LANG_CPP }, + { "__typeof", CT_DECLTYPE, LANG_C | LANG_CPP | LANG_OC }, + { "__typeof__", CT_DECLTYPE, LANG_C | LANG_CPP }, + { "__unsafe_unretained", CT_QUALIFIER, LANG_OC }, + { "__unused", CT_ATTRIBUTE, LANG_C | LANG_CPP }, + { "__volatile__", CT_QUALIFIER, LANG_C | LANG_CPP }, + { "__weak", CT_QUALIFIER, LANG_C | LANG_CPP }, + { "__word__", CT_WORD_, LANG_C | LANG_CPP }, + { "abstract", CT_QUALIFIER, LANG_CS | LANG_D | LANG_JAVA | LANG_VALA | LANG_ECMA }, + { "add", CT_GETSET, LANG_CS }, + { "alias", CT_USING, LANG_D }, + { "align", CT_ALIGN, LANG_D }, + { "alignof", CT_SIZEOF, LANG_CPP }, + { "and", CT_SBOOL, LANG_CPP }, + { "and_eq", CT_SASSIGN, LANG_CPP }, + { "as", CT_AS, LANG_CS | LANG_VALA }, + { "asm", CT_ASM, LANG_C | LANG_CPP | LANG_D }, + { "asm", CT_PP_ASM, LANG_ALL | FLAG_PP }, + { "assert", CT_ASSERT, LANG_JAVA }, + { "assert", CT_FUNCTION, LANG_D | LANG_PAWN }, + { "assert", CT_PP_ASSERT, LANG_PAWN | FLAG_PP }, + { "auto", CT_TYPE, LANG_C | LANG_CPP | LANG_D }, + { "base", CT_BASE, LANG_CS | LANG_VALA }, + { "bit", CT_TYPE, LANG_D }, + { "bitand", CT_ARITH, LANG_C | LANG_CPP }, + { "bitor", CT_ARITH, LANG_C | LANG_CPP }, + { "body", CT_BODY, LANG_D }, + { "bool", CT_TYPE, LANG_C | LANG_CPP | LANG_CS | LANG_VALA }, + { "boolean", CT_TYPE, LANG_JAVA | LANG_ECMA }, + { "break", CT_BREAK, LANG_ALL }, + { "byte", CT_TYPE, LANG_CS | LANG_D | LANG_JAVA | LANG_ECMA }, + { "callback", CT_QUALIFIER, LANG_VALA }, + { "case", CT_CASE, LANG_ALL }, + { "cast", CT_D_CAST, LANG_D }, + { "catch", CT_CATCH, LANG_CPP | LANG_CS | LANG_VALA | LANG_D | LANG_JAVA | LANG_ECMA }, + { "cdouble", CT_TYPE, LANG_D }, + { "cent", CT_TYPE, LANG_D }, + { "cfloat", CT_TYPE, LANG_D }, + { "char", CT_CHAR, LANG_PAWN }, + { "char", CT_TYPE, LANG_ALLC }, + { "checked", CT_QUALIFIER, LANG_CS }, + { "class", CT_CLASS, LANG_CPP | LANG_CS | LANG_D | LANG_JAVA | LANG_VALA | LANG_ECMA }, + { "compl", CT_ARITH, LANG_CPP }, + { "const", CT_QUALIFIER, LANG_ALL }, + { "const_cast", CT_TYPE_CAST, LANG_CPP }, + { "constexpr", CT_QUALIFIER, LANG_CPP }, + { "construct", CT_CONSTRUCT, LANG_VALA }, + { "continue", CT_CONTINUE, LANG_ALL }, + { "creal", CT_TYPE, LANG_D }, + { "dchar", CT_TYPE, LANG_D }, + { "debug", CT_DEBUG, LANG_D }, + { "debugger", CT_DEBUGGER, LANG_ECMA }, + { "decltype", CT_DECLTYPE, LANG_CPP }, + { "default", CT_DEFAULT, LANG_ALL }, + { "define", CT_PP_DEFINE, LANG_ALL | FLAG_PP }, + { "defined", CT_DEFINED, LANG_PAWN }, + { "defined", CT_PP_DEFINED, LANG_ALLC | FLAG_PP }, + { "delegate", CT_DELEGATE, LANG_CS | LANG_VALA | LANG_D }, + { "delete", CT_DELETE, LANG_CPP | LANG_D | LANG_ECMA | LANG_VALA }, + { "deprecated", CT_QUALIFIER, LANG_D }, + { "do", CT_DO, LANG_ALL }, + { "double", CT_TYPE, LANG_ALLC }, + { "dynamic_cast", CT_TYPE_CAST, LANG_CPP }, + { "elif", CT_PP_ELSE, LANG_ALLC | FLAG_PP }, + { "else", CT_ELSE, LANG_ALL }, + { "else", CT_PP_ELSE, LANG_ALL | FLAG_PP }, + { "elseif", CT_PP_ELSE, LANG_PAWN | FLAG_PP }, + { "emit", CT_PP_EMIT, LANG_PAWN | FLAG_PP }, + { "endif", CT_PP_ENDIF, LANG_ALL | FLAG_PP }, + { "endinput", CT_PP_ENDINPUT, LANG_PAWN | FLAG_PP }, + { "endregion", CT_PP_ENDREGION, LANG_ALL | FLAG_PP }, + { "endscript", CT_PP_ENDINPUT, LANG_PAWN | FLAG_PP }, + { "enum", CT_ENUM, LANG_ALL }, + { "error", CT_PP_ERROR, LANG_PAWN | FLAG_PP }, + { "errordomain", CT_ENUM, LANG_VALA }, + { "event", CT_TYPE, LANG_CS }, + { "exit", CT_FUNCTION, LANG_PAWN }, + { "explicit", CT_QUALIFIER, LANG_CPP | LANG_CS }, + { "export", CT_EXPORT, LANG_CPP | LANG_D | LANG_ECMA }, + { "extends", CT_QUALIFIER, LANG_JAVA | LANG_ECMA }, + { "extern", CT_EXTERN, LANG_C | LANG_CPP | LANG_OC | LANG_CS | LANG_D | LANG_VALA }, + { "false", CT_WORD, LANG_ALL }, + { "file", CT_PP_FILE, LANG_PAWN | FLAG_PP }, + { "final", CT_QUALIFIER, LANG_CPP | LANG_D | LANG_ECMA }, + { "finally", CT_FINALLY, LANG_D | LANG_CS | LANG_VALA | LANG_ECMA | LANG_JAVA }, + { "fixed", CT_FIXED, LANG_CS }, + { "flags", CT_TYPE, LANG_VALA }, + { "float", CT_TYPE, LANG_ALLC }, + { "for", CT_FOR, LANG_ALL }, + { "foreach", CT_FOR, LANG_CS | LANG_D | LANG_VALA }, + { "foreach_reverse", CT_FOR, LANG_D }, + { "forward", CT_FORWARD, LANG_PAWN }, + { "friend", CT_FRIEND, LANG_CPP }, + { "function", CT_FUNCTION, LANG_D | LANG_ECMA }, + { "get", CT_GETSET, LANG_CS | LANG_VALA }, + { "goto", CT_GOTO, LANG_ALL }, + { "idouble", CT_TYPE, LANG_D }, + { "if", CT_IF, LANG_ALL }, + { "if", CT_PP_IF, LANG_ALL | FLAG_PP }, + { "ifdef", CT_PP_IF, LANG_ALLC | FLAG_PP }, + { "ifloat", CT_TYPE, LANG_D }, + { "ifndef", CT_PP_IF, LANG_ALLC | FLAG_PP }, + { "implements", CT_QUALIFIER, LANG_JAVA | LANG_ECMA }, + { "implicit", CT_QUALIFIER, LANG_CS }, + { "import", CT_IMPORT, LANG_D | LANG_JAVA | LANG_ECMA }, + { "import", CT_PP_INCLUDE, LANG_OC | FLAG_PP }, + { "in", CT_IN, LANG_D | LANG_CS | LANG_VALA | LANG_ECMA | LANG_OC }, + { "include", CT_PP_INCLUDE, LANG_C | LANG_CPP | LANG_OC | LANG_PAWN | FLAG_PP }, + { "inline", CT_QUALIFIER, LANG_C | LANG_CPP }, + { "inout", CT_QUALIFIER, LANG_D }, + { "instanceof", CT_SIZEOF, LANG_JAVA | LANG_ECMA }, + { "int", CT_TYPE, LANG_ALLC }, + { "interface", CT_CLASS, LANG_CPP | LANG_CS | LANG_D | LANG_JAVA | LANG_VALA | LANG_ECMA }, + { "internal", CT_QUALIFIER, LANG_CS | LANG_VALA }, + { "invariant", CT_INVARIANT, LANG_D }, + { "ireal", CT_TYPE, LANG_D }, + { "is", CT_SCOMPARE, LANG_D | LANG_CS | LANG_VALA }, + { "lazy", CT_LAZY, LANG_D }, + { "line", CT_PP_LINE, LANG_PAWN | FLAG_PP }, + { "lock", CT_LOCK, LANG_CS | LANG_VALA }, + { "long", CT_TYPE, LANG_ALLC }, + { "macro", CT_D_MACRO, LANG_D }, + { "mixin", CT_CLASS, LANG_D }, // may need special handling + { "module", CT_D_MODULE, LANG_D }, + { "mutable", CT_QUALIFIER, LANG_CPP }, + { "namespace", CT_NAMESPACE, LANG_CPP | LANG_CS | LANG_VALA }, + { "native", CT_NATIVE, LANG_PAWN }, + { "native", CT_QUALIFIER, LANG_JAVA | LANG_ECMA }, + { "new", CT_NEW, LANG_CPP | LANG_CS | LANG_D | LANG_JAVA | LANG_PAWN | LANG_VALA | LANG_ECMA }, + { "noexcept", CT_NOEXCEPT, LANG_CPP }, + { "nonnull", CT_TYPE, LANG_OC }, + { "not", CT_SARITH, LANG_CPP }, + { "not_eq", CT_SCOMPARE, LANG_CPP }, +// { "null", CT_TYPE, LANG_CS | LANG_D | LANG_JAVA | LANG_VALA }, + { "null_resettable", CT_OC_PROPERTY_ATTR, LANG_OC }, + { "null_unspecified", CT_TYPE, LANG_OC }, + { "nullable", CT_TYPE, LANG_OC }, + { "object", CT_TYPE, LANG_CS }, + { "operator", CT_OPERATOR, LANG_CPP | LANG_CS | LANG_PAWN }, + { "or", CT_SBOOL, LANG_CPP }, + { "or_eq", CT_SASSIGN, LANG_CPP }, + { "out", CT_QUALIFIER, LANG_CS | LANG_D | LANG_VALA }, + { "override", CT_QUALIFIER, LANG_CPP | LANG_CS | LANG_D | LANG_VALA }, + { "package", CT_ACCESS, LANG_D }, + { "package", CT_PACKAGE, LANG_ECMA | LANG_JAVA }, + { "params", CT_TYPE, LANG_CS | LANG_VALA }, + { "pragma", CT_PP_PRAGMA, LANG_ALL | FLAG_PP }, + { "private", CT_ACCESS, LANG_ALLC }, // not C + { "property", CT_PP_PROPERTY, LANG_CS | FLAG_PP }, + { "protected", CT_ACCESS, LANG_ALLC }, // not C + { "public", CT_ACCESS, LANG_ALL }, // PAWN // not C + { "readonly", CT_QUALIFIER, LANG_CS }, + { "real", CT_TYPE, LANG_D }, + { "ref", CT_QUALIFIER, LANG_CS | LANG_VALA }, + { "region", CT_PP_REGION, LANG_ALL | FLAG_PP }, + { "register", CT_QUALIFIER, LANG_C | LANG_CPP }, + { "reinterpret_cast", CT_TYPE_CAST, LANG_CPP }, + { "remove", CT_GETSET, LANG_CS }, + { "restrict", CT_QUALIFIER, LANG_C | LANG_CPP }, + { "return", CT_RETURN, LANG_ALL }, + { "sbyte", CT_TYPE, LANG_CS }, + { "scope", CT_D_SCOPE, LANG_D }, + { "sealed", CT_QUALIFIER, LANG_CS }, + { "section", CT_PP_SECTION, LANG_PAWN | FLAG_PP }, + { "self", CT_THIS, LANG_OC }, + { "set", CT_GETSET, LANG_CS | LANG_VALA }, + { "short", CT_TYPE, LANG_ALLC }, + { "signal", CT_ACCESS, LANG_VALA }, + { "signals", CT_ACCESS, LANG_CPP }, + { "signed", CT_TYPE, LANG_C | LANG_CPP }, + { "size_t", CT_TYPE, LANG_ALLC }, + { "sizeof", CT_SIZEOF, LANG_C | LANG_CPP | LANG_CS | LANG_VALA | LANG_PAWN }, + { "sleep", CT_SIZEOF, LANG_PAWN }, + { "stackalloc", CT_NEW, LANG_CS }, + { "state", CT_STATE, LANG_PAWN }, + { "static", CT_QUALIFIER, LANG_ALL }, + { "static_cast", CT_TYPE_CAST, LANG_CPP }, + { "stock", CT_STOCK, LANG_PAWN }, + { "strictfp", CT_QUALIFIER, LANG_JAVA }, + { "string", CT_TYPE, LANG_CS | LANG_VALA }, + { "struct", CT_STRUCT, LANG_C | LANG_CPP | LANG_OC | LANG_CS | LANG_D | LANG_VALA }, + { "super", CT_SUPER, LANG_D | LANG_JAVA | LANG_ECMA }, + { "switch", CT_SWITCH, LANG_ALL }, + { "synchronized", CT_QUALIFIER, LANG_D | LANG_ECMA }, + { "synchronized", CT_SYNCHRONIZED, LANG_JAVA }, + { "tagof", CT_TAGOF, LANG_PAWN }, + { "template", CT_TEMPLATE, LANG_CPP | LANG_D }, + { "this", CT_THIS, LANG_CPP | LANG_CS | LANG_D | LANG_JAVA | LANG_VALA | LANG_ECMA }, + { "throw", CT_THROW, LANG_CPP | LANG_CS | LANG_VALA | LANG_D | LANG_JAVA | LANG_ECMA }, + { "throws", CT_QUALIFIER, LANG_JAVA | LANG_ECMA | LANG_VALA }, + { "transient", CT_QUALIFIER, LANG_JAVA | LANG_ECMA }, + { "true", CT_WORD, LANG_ALL }, + { "try", CT_TRY, LANG_CPP | LANG_CS | LANG_D | LANG_JAVA | LANG_ECMA | LANG_VALA }, + { "tryinclude", CT_PP_INCLUDE, LANG_PAWN | FLAG_PP }, + { "typedef", CT_TYPEDEF, LANG_C | LANG_CPP | LANG_OC | LANG_D }, + { "typeid", CT_SIZEOF, LANG_CPP | LANG_D }, + { "typename", CT_TYPENAME, LANG_CPP }, + { "typeof", CT_DECLTYPE, LANG_C | LANG_CPP }, + { "typeof", CT_SIZEOF, LANG_CS | LANG_D | LANG_VALA | LANG_ECMA }, + { "ubyte", CT_TYPE, LANG_D }, + { "ucent", CT_TYPE, LANG_D }, + { "uint", CT_TYPE, LANG_CS | LANG_VALA | LANG_D }, + { "ulong", CT_TYPE, LANG_CS | LANG_VALA | LANG_D }, + { "unchecked", CT_QUALIFIER, LANG_CS }, + { "undef", CT_PP_UNDEF, LANG_ALL | FLAG_PP }, + { "union", CT_UNION, LANG_C | LANG_CPP | LANG_D }, + { "unittest", CT_UNITTEST, LANG_D }, + { "unsafe", CT_UNSAFE, LANG_CS }, + { "unsafe_unretained", CT_QUALIFIER, LANG_OC }, + { "unsigned", CT_TYPE, LANG_C | LANG_CPP }, + { "ushort", CT_TYPE, LANG_CS | LANG_VALA | LANG_D }, + { "using", CT_USING, LANG_CPP | LANG_CS | LANG_VALA }, + { "var", CT_TYPE, LANG_CS | LANG_VALA | LANG_ECMA }, + { "version", CT_D_VERSION, LANG_D }, + { "virtual", CT_QUALIFIER, LANG_CPP | LANG_CS | LANG_VALA }, + { "void", CT_TYPE, LANG_ALLC }, + { "volatile", CT_QUALIFIER, LANG_C | LANG_CPP | LANG_CS | LANG_JAVA | LANG_ECMA }, + { "volatile", CT_VOLATILE, LANG_D }, + { "wchar", CT_TYPE, LANG_D }, + { "wchar_t", CT_TYPE, LANG_C | LANG_CPP }, + { "weak", CT_QUALIFIER, LANG_VALA }, + { "when", CT_WHEN, LANG_CS }, + { "where", CT_WHERE, LANG_CS }, + { "while", CT_WHILE, LANG_ALL }, + { "with", CT_D_WITH, LANG_D | LANG_ECMA }, + { "xor", CT_SARITH, LANG_CPP }, + { "xor_eq", CT_SASSIGN, LANG_CPP }, +}; + + +// Issue #3353 +void init_keywords_for_language() +{ + unsigned int local_flags = cpd.lang_flags; + size_t keywords_count = ARRAY_SIZE(keywords); + + language_count = 0; + + for (size_t idx = 0; idx < keywords_count; idx++) + { + chunk_tag_t *tag = &keywords[idx]; + + if ((tag->lang_flags & local_flags) != 0) + { + // for debugging only + // fprintf(stderr, "%s(%d): %zu Keyword: '%s', type is '%s'\n", + // __func__, __LINE__, idx, tag->tag, get_token_name(tag->type)); + keyword_for_lang[language_count].tag = tag->tag; + keyword_for_lang[language_count].type = tag->type; + keyword_for_lang[language_count].lang_flags = tag->lang_flags; + language_count++; + } + } + + LOG_FMT(LDYNKW, "%s(%d): Number of Keywords for language %d: '%zu'\n", + __func__, __LINE__, local_flags, language_count); +} // init_keywords_for_language + + +static int kw_compare(const void *p1, const void *p2) +{ + const chunk_tag_t *t1 = static_cast<const chunk_tag_t *>(p1); + const chunk_tag_t *t2 = static_cast<const chunk_tag_t *>(p2); + + return(strcmp(t1->tag, t2->tag)); +} // kw_compare + + +bool keywords_are_sorted() +{ + size_t keywords_count = ARRAY_SIZE(keywords); + + for (size_t idx = 1; idx < keywords_count; idx++) + { + if (kw_compare(&keywords[idx - 1], &keywords[idx]) > 0) + { + fprintf(stderr, "%s: bad sort order at idx %d, words '%s' and '%s'\n", + __func__, (int)idx - 1, keywords[idx - 1].tag, keywords[idx].tag); + // coveralls will always complain. + // these lines are only needed for the developer. + log_flush(true); + exit(EX_SOFTWARE); + } + } + + return(true); +} // keywords_are_sorted + + +void add_keyword(const std::string &tag, E_Token type) +{ + // See if the keyword has already been added + dkwmap::iterator it = dkwm.find(tag); + + if (it != dkwm.end()) + { + LOG_FMT(LDYNKW, "%s(%d): changed '%s' to '%s'\n", + __func__, __LINE__, tag.c_str(), get_token_name(type)); + (*it).second = type; + return; + } + // Insert the keyword + dkwm.insert(dkwmap::value_type(tag, type)); + LOG_FMT(LDYNKW, "%s(%d): added '%s' as '%s'\n", + __func__, __LINE__, tag.c_str(), get_token_name(type)); +} // add_keyword + + +static const chunk_tag_t *kw_static_first(const chunk_tag_t *tag) +{ + const chunk_tag_t *prev = tag - 1; + + // TODO: avoid pointer arithmetic + // loop over static keyword array + while ( prev >= &keyword_for_lang[0] // not at beginning of keyword array + && strcmp(prev->tag, tag->tag) == 0) // tags match + { + tag = prev; + prev--; + } + return(tag); +} // kw_static_first + + +static const chunk_tag_t *kw_static_match(bool orig_list, const chunk_tag_t *tag, int lang_flags) +{ + bool in_pp = ( cpd.in_preproc != CT_NONE + && cpd.in_preproc != CT_PP_DEFINE); + + for (const chunk_tag_t *iter = kw_static_first(tag); + (orig_list) ? (iter < &keywords[ARRAY_SIZE(keywords)]) : (iter < &keyword_for_lang[language_count]); + iter++) + { + bool pp_iter = (iter->lang_flags & FLAG_PP) != 0; // forcing value to bool + + if ( (strcmp(iter->tag, tag->tag) == 0) + && language_is_set(iter->lang_flags) + && (lang_flags & iter->lang_flags) + && in_pp == pp_iter) + { + return(iter); + } + } + + return(nullptr); +} // kw_static_match + + +E_Token find_keyword_type(const char *word, size_t len) +{ + if (len <= 0) + { + return(CT_NONE); + } + // check the dynamic word list first + string ss(word, len); + dkwmap::iterator it = dkwm.find(ss); + + if (it != dkwm.end()) + { + return((*it).second); + } + chunk_tag_t key; + + key.tag = ss.c_str(); + + // check the static word list + const chunk_tag_t *p_ret = static_cast<const chunk_tag_t *>( + bsearch(&key, keyword_for_lang, language_count, sizeof(keyword_for_lang[0]), kw_compare)); + + if (p_ret != nullptr) + { + if ( strcmp(p_ret->tag, "__pragma") == 0 + || strcmp(p_ret->tag, "_Pragma") == 0) + { + cpd.in_preproc = CT_PREPROC; + } + p_ret = kw_static_match(false, p_ret, cpd.lang_flags); + } + return((p_ret != nullptr) ? p_ret->type : CT_WORD); +} // find_keyword_type + + +int load_keyword_file(const char *filename) +{ + FILE *pf = fopen(filename, "r"); + + if (pf == nullptr) + { + LOG_FMT(LERR, "%s: fopen(%s) failed: %s (%d)\n", + __func__, filename, strerror(errno), errno); + exit(EX_IOERR); + } + const int max_line_length = 256; + const int max_arg_count = 2; + + // maximal length of a line in the file + char buf[max_line_length]; + char *args[max_arg_count]; + size_t line_no = 0; + + // read file line by line + while (fgets(buf, max_line_length, pf) != nullptr) + { + line_no++; + + // remove comments after '#' sign + char *ptr; + + if ((ptr = strchr(buf, '#')) != nullptr) + { + *ptr = 0; // set string end where comment begins + } + size_t argc = Args::SplitLine(buf, args, max_arg_count); + + if (argc > 0) + { + if ( argc == 1 + && CharTable::IsKw1(*args[0])) + { + add_keyword(args[0], CT_TYPE); + } + else + { + LOG_FMT(LWARN, "%s:%zu Invalid line (starts with '%s')\n", + filename, line_no, args[0]); + exit(EX_SOFTWARE); + } + } + else + { + continue; // the line is empty + } + } + fclose(pf); + return(EX_OK); +} // load_keyword_file + + +void print_custom_keywords(FILE *pfile) +{ + for (const auto &keyword_pair : dkwm) + { + E_Token tt = keyword_pair.second; + + if (tt == CT_TYPE) + { + fprintf(pfile, "custom type %*.s%s\n", + uncrustify::limits::MAX_OPTION_NAME_LEN - 10, " ", + keyword_pair.first.c_str()); + } + else if (tt == CT_MACRO_OPEN) + { + fprintf(pfile, "macro-open %*.s%s\n", + uncrustify::limits::MAX_OPTION_NAME_LEN - 11, " ", + keyword_pair.first.c_str()); + } + else if (tt == CT_MACRO_CLOSE) + { + fprintf(pfile, "macro-close %*.s%s\n", + uncrustify::limits::MAX_OPTION_NAME_LEN - 12, " ", + keyword_pair.first.c_str()); + } + else if (tt == CT_MACRO_ELSE) + { + fprintf(pfile, "macro-else %*.s%s\n", + uncrustify::limits::MAX_OPTION_NAME_LEN - 11, " ", + keyword_pair.first.c_str()); + } + else + { + const char *tn = get_token_name(tt); + + fprintf(pfile, "set %s %*.s%s\n", + tn, + uncrustify::limits::MAX_OPTION_NAME_LEN - (4 + static_cast<int>(strlen(tn))), + " ", keyword_pair.first.c_str()); + } + } +} // print_custom_keywords + + +void clear_keyword_file() +{ + dkwm.clear(); +} // clear_keyword_file + + +pattern_class_e get_token_pattern_class(E_Token tok) +{ + // TODO: instead of this switch better assign the pattern class to each statement + switch (tok) + { + case CT_IF: + case CT_ELSEIF: + case CT_SWITCH: + case CT_FOR: + case CT_WHILE: + case CT_SYNCHRONIZED: + case CT_USING_STMT: + case CT_LOCK: + case CT_D_WITH: + case CT_D_VERSION_IF: + case CT_D_SCOPE_IF: + return(pattern_class_e::PBRACED); + + case CT_ELSE: + return(pattern_class_e::ELSE); + + case CT_DO: + case CT_TRY: + case CT_FINALLY: + case CT_BODY: + case CT_UNITTEST: + case CT_UNSAFE: + case CT_VOLATILE: + case CT_GETSET: + return(pattern_class_e::BRACED); + + case CT_CATCH: + case CT_D_VERSION: + case CT_DEBUG: + return(pattern_class_e::OPBRACED); + + case CT_NAMESPACE: + return(pattern_class_e::VBRACED); + + case CT_WHILE_OF_DO: + return(pattern_class_e::PAREN); + + case CT_INVARIANT: + return(pattern_class_e::OPPAREN); + + default: + return(pattern_class_e::NONE); + } // switch +} // get_token_pattern_class diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/keywords.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/keywords.h new file mode 100644 index 00000000..7dc431c5 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/keywords.h @@ -0,0 +1,85 @@ +/** + * @file keywords.h + * prototypes for keywords.c + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef KEYWORDS_H_INCLUDED +#define KEYWORDS_H_INCLUDED + +#include "uncrustify_types.h" + +/** + * Initializes keywords table for a given language. + * + * Let us have a look on the problem is caused by the tokens "in" and "out", + * used in the file "Issue_3353.h" under. + * The strings representing the tokens ("in" and "out"), are found in the + * original table: static chunk_tag_t keywords[] because they are used by + * other languages. They are tokenized as CT_IN and CT_OUT. + * The correct tokenization is CT_FUNC_VAR. + * + * It is necessary to create (at run time) a new table with all the keywords + * proper to the used language. + * + */ + +/** + * The file + * "Issue_3353.h" + * struct A { + * void (*in)( + * void); + * void (*out)( + * void); + * }; + */ +void init_keywords_for_language(); + +/** + * Loads the dynamic keywords from a file + * + * @param filename The path to the file to load + * + * @retval EX_OK successfully read keywords from file + * @retval EX_IOERR reading keywords file failed + */ +int load_keyword_file(const char *filename); + + +/** + * Search first the dynamic and then the static table for a matching keyword + * + * @param word Pointer to the text -- NOT zero terminated + * @param len The length of the text + * + * @return CT_WORD (no match) or the keyword token + */ +E_Token find_keyword_type(const char *word, size_t len); + + +/** + * Adds a keyword to the list of dynamic keywords + * + * @param tag The tag (string) must be zero terminated + * @param type The type, usually CT_TYPE + */ +void add_keyword(const std::string &tag, E_Token type); + + +void print_custom_keywords(FILE *pfile); + + +void clear_keyword_file(); + + +//! Returns the pattern that the keyword needs based on the token +pattern_class_e get_token_pattern_class(E_Token tok); + + +bool keywords_are_sorted(); + + +#endif /* KEYWORDS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/lang_pawn.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/lang_pawn.cpp new file mode 100644 index 00000000..70722c74 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/lang_pawn.cpp @@ -0,0 +1,524 @@ +/** + * @file lang_pawn.cpp + * Special functions for pawn stuff + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "lang_pawn.h" + +#include "prototypes.h" + +using namespace uncrustify; + + +/** + * Checks to see if a token continues a statement to the next line. + * We need to check for 'open' braces/paren/etc because the level doesn't + * change until the token after the open. + */ +static bool pawn_continued(Chunk *pc, size_t br_level); + + +/** + * Functions prototypes and definitions can only appear in level 0. + * + * Function prototypes start with "native", "forward", or are just a function + * with a trailing semicolon instead of a open brace (or something else) + * + * somefunc(params) <-- def + * stock somefunc(params) <-- def + * somefunc(params); <-- proto + * forward somefunc(params) <-- proto + * native somefunc[rect](params) <-- proto + * + * Functions start with 'stock', 'static', 'public', or '@' (on level 0) + * + * Variable definitions start with 'stock', 'static', 'new', or 'public'. + */ +static Chunk *pawn_process_line(Chunk *start); + + +//! We are on a level 0 function proto of def +static Chunk *pawn_mark_function0(Chunk *start, Chunk *fcn); + + +/** + * follows a variable definition at level 0 until the end. + * Adds a semicolon at the end, if needed. + */ +static Chunk *pawn_process_variable(Chunk *start); + + +static Chunk *pawn_process_func_def(Chunk *pc); + + +Chunk *pawn_add_vsemi_after(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + if (pc->IsSemicolon()) + { + return(pc); + } + Chunk *next = pc->GetNextNc(); + + if ( next->IsNotNullChunk() + && next->IsSemicolon()) + { + return(pc); + } + Chunk chunk = *pc; + + chunk.SetType(CT_VSEMICOLON); + chunk.SetParentType(CT_NONE); + chunk.Str() = options::mod_pawn_semicolon() ? ";" : ""; + chunk.SetColumn(pc->GetColumn() + pc->Len()); + + LOG_FMT(LPVSEMI, "%s: Added VSEMI on line %zu, prev='%s' [%s]\n", + __func__, pc->GetOrigLine(), pc->Text(), + get_token_name(pc->GetType())); + + return(chunk.CopyAndAddAfter(pc)); +} + + +void pawn_scrub_vsemi() +{ + constexpr static auto LCURRENT = LPVSEMI; + + LOG_FUNC_ENTRY(); + + log_rule_B("mod_pawn_semicolon"); + + if (!options::mod_pawn_semicolon()) + { + return; + } + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if (pc->IsNot(CT_VSEMICOLON)) + { + continue; + } + Chunk *prev = pc->GetPrevNcNnl(); + + if (prev->Is(CT_BRACE_CLOSE)) + { + if ( prev->GetParentType() == CT_IF + || prev->GetParentType() == CT_ELSE + || prev->GetParentType() == CT_SWITCH + || prev->GetParentType() == CT_CASE + || prev->GetParentType() == CT_WHILE_OF_DO) + { + pc->Str().clear(); + } + } + } +} + + +static bool pawn_continued(Chunk *pc, size_t br_level) +{ + LOG_FUNC_ENTRY(); + + if (pc == nullptr) + { + return(false); + } + + if ( pc->GetLevel() > br_level + || pc->Is(CT_ARITH) + || pc->Is(CT_SHIFT) + || pc->Is(CT_CARET) + || pc->Is(CT_QUESTION) + || pc->Is(CT_BOOL) + || pc->Is(CT_ASSIGN) + || pc->Is(CT_COMMA) + || pc->Is(CT_COMPARE) + || pc->Is(CT_IF) + || pc->Is(CT_ELSE) + || pc->Is(CT_DO) + || pc->Is(CT_SWITCH) + || pc->Is(CT_WHILE) + || pc->Is(CT_BRACE_OPEN) + || pc->Is(CT_VBRACE_OPEN) + || pc->Is(CT_FPAREN_OPEN) + || pc->GetParentType() == CT_IF + || pc->GetParentType() == CT_ELSE + || pc->GetParentType() == CT_ELSEIF + || pc->GetParentType() == CT_DO + || pc->GetParentType() == CT_FOR + || pc->GetParentType() == CT_SWITCH + || pc->GetParentType() == CT_WHILE + || pc->GetParentType() == CT_FUNC_DEF + || pc->GetParentType() == CT_ENUM + || pc->GetFlags().test_any(PCF_IN_ENUM | PCF_IN_STRUCT) + || pc->IsString(":") + || pc->IsString("+") + || pc->IsString("-")) + { + return(true); + } + return(false); +} // pawn_continued + + +void pawn_prescan() +{ + LOG_FUNC_ENTRY(); + + /* + * Start at the beginning and step through the entire file, and clean up + * any questionable stuff + */ + bool did_nl = true; + Chunk *pc = Chunk::GetHead(); + + while ( pc != nullptr + && pc->IsNotNullChunk()) + { + if ( did_nl + && pc->IsNot(CT_PREPROC) + && !pc->IsNewline() + && pc->GetLevel() == 0) + { + // pc now points to the start of a line + pc = pawn_process_line(pc); + } + + // note that continued lines are ignored + if ( pc != nullptr + && pc->IsNotNullChunk()) + { + did_nl = (pc->Is(CT_NEWLINE)); + } + pc = pc->GetNextNc(); + } +} + + +static Chunk *pawn_process_line(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + //LOG_FMT(LSYS, "%s: %d - %s\n", __func__, + // start->GetOrigLine(), start->Text()); + + if ( start->Is(CT_NEW) + || start->IsString("const")) + { + return(pawn_process_variable(start)); + } + // if a open paren is found before an assign, then this is a function + Chunk *fcn = nullptr; + + if (start->Is(CT_WORD)) + { + fcn = start; + } + Chunk *pc = start; + + while ( ((pc = pc->GetNextNc())->IsNotNullChunk()) + && !pc->IsString("(") + && pc->IsNot(CT_ASSIGN) + && pc->IsNot(CT_NEWLINE)) + { + if ( pc->GetLevel() == 0 + && ( pc->Is(CT_FUNCTION) + || pc->Is(CT_WORD) + || pc->Is(CT_OPERATOR_VAL))) + { + fcn = pc; + } + } + + if (pc->IsNotNullChunk()) + { + if (pc->Is(CT_ASSIGN)) + { + return(pawn_process_variable(pc)); + } + } + + if (fcn != nullptr) + { + //LOG_FMT(LSYS, "FUNCTION: %s\n", fcn->Text()); + return(pawn_mark_function0(start, fcn)); + } + + if (start->Is(CT_ENUM)) + { + pc = start->GetNextType(CT_BRACE_CLOSE, start->GetLevel()); + return(pc); + } + //LOG_FMT(LSYS, "%s: Don't understand line %d, starting with '%s' [%s]\n", + // __func__, start->GetOrigLine(), start->Text(), get_token_name(start->GetType())); + return(start); +} // pawn_process_line + + +static Chunk *pawn_process_variable(Chunk *start) +{ + LOG_FUNC_ENTRY(); + Chunk *pc = Chunk::NullChunkPtr; + + if ( start != nullptr + && start->IsNotNullChunk()) + { + pc = start; + } + Chunk *prev = Chunk::NullChunkPtr; + + while ((pc = pc->GetNextNc())->IsNotNullChunk()) + { + if ( pc->Is(CT_NEWLINE) + && prev->IsNotNullChunk() + && !pawn_continued(prev, start->GetLevel())) + { + if (!prev->IsSemicolon()) + { + pawn_add_vsemi_after(prev); + } + break; + } + prev = pc; + } + return(pc); +} + + +void pawn_add_virtual_semicolons() +{ + LOG_FUNC_ENTRY(); + + // Add Pawn virtual semicolons + if (language_is_set(LANG_PAWN)) + { + Chunk *prev = Chunk::NullChunkPtr; + Chunk *pc = Chunk::GetHead(); + + while ((pc = pc->GetNext())->IsNotNullChunk()) + { + if ( !pc->IsCommentOrNewline() + && !pc->IsVBrace()) + { + prev = pc; + } + + if ( prev->IsNullChunk() + || ( pc->IsNot(CT_NEWLINE) + && !pc->IsBraceClose())) + { + continue; + } + + // we just hit a newline and we have a previous token + if ( !prev->TestFlags(PCF_IN_PREPROC) + && !prev->GetFlags().test_any(PCF_IN_ENUM | PCF_IN_STRUCT) + && !prev->IsSemicolon() + && !pawn_continued(prev, prev->GetBraceLevel())) + { + pawn_add_vsemi_after(prev); + prev = Chunk::NullChunkPtr; + } + } + } +} // pawn_add_virtual_semicolons + + +static Chunk *pawn_mark_function0(Chunk *start, Chunk *fcn) +{ + LOG_FUNC_ENTRY(); + + // handle prototypes + if (start == fcn) + { + Chunk *last = fcn->GetNextType(CT_PAREN_CLOSE, fcn->GetLevel())->GetNext(); + + if (last->Is(CT_SEMICOLON)) + { + LOG_FMT(LPFUNC, "%s: %zu] '%s' proto due to semicolon\n", + __func__, fcn->GetOrigLine(), fcn->Text()); + fcn->SetType(CT_FUNC_PROTO); + return(last); + } + } + else + { + if ( start->Is(CT_FORWARD) + || start->Is(CT_NATIVE)) + { + LOG_FMT(LPFUNC, "%s: %zu] '%s' [%s] proto due to %s\n", + __func__, fcn->GetOrigLine(), fcn->Text(), + get_token_name(fcn->GetType()), + get_token_name(start->GetType())); + fcn->SetType(CT_FUNC_PROTO); + return(fcn->GetNextNc()); + } + } + // Not a prototype, so it must be a function def + return(pawn_process_func_def(fcn)); +} + + +static Chunk *pawn_process_func_def(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + // We are on a function definition + pc->SetType(CT_FUNC_DEF); + + LOG_FMT(LPFUNC, "%s: %zu:%zu %s\n", + __func__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + + /* + * If we don't have a brace open right after the close fparen, then + * we need to add virtual braces around the function body. + */ + Chunk *clp = pc->GetNextString(")", 1, 0); + Chunk *last = clp->GetNextNcNnl(); + + if (last->IsNotNullChunk()) + { + LOG_FMT(LPFUNC, "%s: %zu] last is '%s' [%s]\n", + __func__, last->GetOrigLine(), last->Text(), get_token_name(last->GetType())); + } + + // See if there is a state clause after the function + if ( last->IsNotNullChunk() + && last->IsString("<")) + { + LOG_FMT(LPFUNC, "%s: %zu] '%s' has state angle open %s\n", + __func__, pc->GetOrigLine(), pc->Text(), get_token_name(last->GetType())); + + last->SetType(CT_ANGLE_OPEN); + last->SetParentType(CT_FUNC_DEF); + + while ( ((last = last->GetNext())->IsNotNullChunk()) + && !last->IsString(">")) + { + // do nothing just search, TODO: use search_chunk + } + + if (last->IsNotNullChunk()) + { + LOG_FMT(LPFUNC, "%s: %zu] '%s' has state angle close %s\n", + __func__, pc->GetOrigLine(), pc->Text(), get_token_name(last->GetType())); + last->SetType(CT_ANGLE_CLOSE); + last->SetParentType(CT_FUNC_DEF); + } + last = last->GetNextNcNnl(); + } + + if (last->IsNullChunk()) + { + return(last); + } + + if (last->Is(CT_BRACE_OPEN)) + { + last->SetParentType(CT_FUNC_DEF); + last = last->GetNextType(CT_BRACE_CLOSE, last->GetLevel()); + + if (last->IsNotNullChunk()) + { + last->SetParentType(CT_FUNC_DEF); + } + } + else + { + LOG_FMT(LPFUNC, "%s: %zu] '%s' fdef: expected brace open: %s\n", + __func__, pc->GetOrigLine(), pc->Text(), get_token_name(last->GetType())); + + // do not insert a vbrace before a preproc + if (last->TestFlags(PCF_IN_PREPROC)) + { + return(last); + } + Chunk chunk = *last; + chunk.Str().clear(); + chunk.SetType(CT_VBRACE_OPEN); + chunk.SetParentType(CT_FUNC_DEF); + + Chunk *prev = chunk.CopyAndAddBefore(last); + last = prev; + + // find the next newline at level 0 + prev = prev->GetNextNcNnl(); + + do + { + LOG_FMT(LPFUNC, "%s:%zu] check %s, level %zu\n", + __func__, prev->GetOrigLine(), get_token_name(prev->GetType()), prev->GetLevel()); + + if ( prev->Is(CT_NEWLINE) + && prev->GetLevel() == 0) + { + Chunk *next = prev->GetNextNcNnl(); + + if ( next->IsNotNullChunk() + && next->IsNot(CT_ELSE) + && next->IsNot(CT_WHILE_OF_DO)) + { + break; + } + } + prev->SetLevel(prev->GetLevel() + 1); + prev->SetBraceLevel(prev->GetBraceLevel() + 1); + last = prev; + } while ((prev = prev->GetNext())->IsNotNullChunk()); + + if ( last != nullptr + && last->IsNotNullChunk()) + { + LOG_FMT(LPFUNC, "%s:%zu] ended on %s, level %zu\n", + __func__, last->GetOrigLine(), get_token_name(last->GetType()), last->GetLevel()); + } + chunk = *last; + chunk.Str().clear(); + chunk.SetType(CT_VBRACE_CLOSE); + chunk.SetParentType(CT_FUNC_DEF); + chunk.SetColumn(chunk.GetColumn() + last->Len()); + chunk.SetLevel(0); + chunk.SetBraceLevel(0); + last = chunk.CopyAndAddAfter(last); + } + return(last); +} // pawn_process_func_def + + +Chunk *pawn_check_vsemicolon(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + // Grab the open VBrace + Chunk *vb_open = pc->GetPrevType(CT_VBRACE_OPEN); + + /* + * Grab the item before the newline + * Don't do anything if: + * - the only thing previous is the V-Brace open + * - in a preprocessor + * - level > (vb_open->GetLevel() + 1) -- ie, in () or [] + * - it is something that needs a continuation + * + arith, assign, bool, comma, compare + */ + Chunk *prev = pc->GetPrevNcNnl(); + + if ( prev->IsNullChunk() + || prev == vb_open + || prev->TestFlags(PCF_IN_PREPROC) + || pawn_continued(prev, vb_open->GetLevel() + 1)) + { + if (prev->IsNotNullChunk()) + { + LOG_FMT(LPVSEMI, "%s: no VSEMI on line %zu, prev='%s' [%s]\n", + __func__, prev->GetOrigLine(), prev->Text(), get_token_name(prev->GetType())); + } + return(pc); + } + return(pawn_add_vsemi_after(prev)); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/lang_pawn.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/lang_pawn.h new file mode 100644 index 00000000..03766a08 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/lang_pawn.h @@ -0,0 +1,49 @@ +/** + * @file long_pawn.h + * prototypes for long_pawn.c + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef LONG_PAWN_H_INCLUDED +#define LONG_PAWN_H_INCLUDED + +#include "uncrustify_types.h" + + +/** + * Does a scan of level 0 BEFORE stuff in combine.cpp is called. + * At this point, VSemis have been added only in VBraces. + * Otherwise, all level info is correct, except for unbraced functions. + * + * We are looking for unbraced functions. + */ +void pawn_prescan(); + + +void pawn_add_virtual_semicolons(); + + +/** + * We are in a virtual brace and hit a newline. + * If this should end the vbrace, then insert a VSEMICOLON and return that. + * + * @param pc The newline (CT_NEWLINE) + * + * @return Either the newline or the newly inserted virtual semicolon + */ +Chunk *pawn_check_vsemicolon(Chunk *pc); + + +/** + * Turns certain virtual semicolons invisible. + * - after a close brace with a parent of switch, case, else, if + */ +void pawn_scrub_vsemi(); + + +//! add a semicolon after ... +Chunk *pawn_add_vsemi_after(Chunk *pc); + + +#endif /* LONG_PAWN_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/language_tools.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/language_tools.cpp new file mode 100644 index 00000000..77e577f4 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/language_tools.cpp @@ -0,0 +1,17 @@ +/** + * @file language_tools.cpp + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#include "language_tools.h" + + +/** + * check if the language(s) is/are set + */ +bool language_is_set(size_t lang) +{ + return((cpd.lang_flags & lang) != 0); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/language_tools.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/language_tools.h new file mode 100644 index 00000000..5f57c3f1 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/language_tools.h @@ -0,0 +1,18 @@ +/** + * @file language_tools.h + * + * @author Guy Maurel + * @license GPL v2+ + */ +#ifndef LANGUAGE_TOOLS_H_INCLUDED +#define LANGUAGE_TOOLS_H_INCLUDED + +#include "uncrustify_types.h" + + +/** + * check if the language(s) is/are set + */ +bool language_is_set(size_t lang); + +#endif /* LANGUAGE_TOOLS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/log_levels.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/log_levels.h new file mode 100644 index 00000000..266e1981 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/log_levels.h @@ -0,0 +1,139 @@ +/** + * @file log_levels.h + * + * Enum for log levels. + * Use these for the log severities in LOG_FMT(), etc. + * + * @author Ben Gardner + * @author Guy Maurel October 2015- 2021 + * @license GPL v2+ + */ + +#ifndef LOG_LEVELS_H_INCLUDED +#define LOG_LEVELS_H_INCLUDED + +/** + * list of available log levels + * + * The user defines which log level is active using the + * -L or -log option. + * use -L A to set all the levels + * All messages which have a level that is active will be stored to the log + * file. + * All other log messages will be discarded. + * Different parts of the software use different log levels. + * This allows to log only operations of a specific operation. + * This eases debugging. + * To get all log messages use the option -La + * By default only system messages (level=LSYS) are logged. + */ +enum log_sev_t +{ + LSYS = 0, //! system messages + LERR = 1, //! error messages + LWARN = 2, //! warnings + LNOTE = 3, //! user notifications + LINFO = 4, //! user information + LDATA = 5, //! data logging + + LFILELIST = 8, //! Files in the file list file + LLINEENDS = 9, //! Show which line endings are used + LCASTS = 10, //! align casts + LALBR = 11, //! align braces + LALTD = 12, //! Align Typedef + LALPP = 13, //! align #define + LALPROTO = 14, //! align prototype + LALNLC = 15, //! align backslash-newline + LALTC = 16, //! align trailing comments + LALADD = 17, //! align add + LALASS = 18, //! align assign + LFVD = 19, //! fix_var_def + LFVD2 = 20, //! fix_var_def-2 + LINDENT = 21, //! indent_text + LINDENT2 = 22, //! indent_text tab level + LINDPSE = 23, //! indent_text stack + LINDPC = 24, //! indent play-by-play + LNEWLINE = 25, //! newlines + LPF = 26, //! Parse Frame + LSTMT = 27, //! Marking statements/expressions + LTOK = 28, //! Tokenize + LALRC = 29, //! align right comment + LCMTIND = 30, //! Comment Indent + LINDLINE = 31, //! indent line + LSIB = 32, //! Scan IB + LRETURN = 33, //! add/remove parens for return or throw + LBRDEL = 34, //! brace removal + LFCN = 35, //! function detection + LFCNP = 36, //! function parameters + LPCU = 37, //! parse cleanup + LDYNKW = 38, //! dynamic keywords + LOUTIND = 39, //! output indent + LBCSAFTER = 40, //! Brace cleanup stack - after each token + LBCSPOP = 41, //! Brace cleanup stack - log pops + LBCSPUSH = 42, //! Brace cleanup stack - log push + LBCSSWAP = 43, //! Brace cleanup stack - log swaps + LFTOR = 44, //! Class Ctor or Dtor + LAS = 45, //! align_stack + LPPIS = 46, //! Preprocessor Indent and Space + LTYPEDEF = 47, //! Typedef and function types + LVARDEF = 48, //! Variable def marking + LDEFVAL = 49, //! define values + LPVSEMI = 50, //! Pawn: virtual semicolons + LPFUNC = 51, //! Pawn: function recognition + LSPLIT = 52, //! Line splitting + LFTYPE = 53, //! Function type detection + LTEMPL = 54, //! Template detection + LPARADD = 55, //! adding parens in if/while + LPARADD2 = 56, //! adding parens in if/while - details + LBLANKD = 57, //! blank line details + LTEMPFUNC = 58, //! Template function detection + LSCANSEMI = 59, //! scan semicolon removal + LDELSEMI = 60, //! Removing semicolons + LFPARAM = 61, //! Testing for a full parameter + LNL1LINE = 62, //! NL check for 1 liners + LPFCHK = 63, //! Parse Frame check function call + LAVDB = 64, //! align var def braces + LSORT = 65, //! Sorting + LSPACE = 66, //! Space + LALIGN = 67, //! align + LALAGAIN = 68, //! align again + LOPERATOR = 69, //! operator + LASFCP = 70, //! Align Same Function Call Params + LINDLINED = 71, //! indent line details + LBCTRL = 72, //! beautifier control + LRMRETURN = 73, //! remove 'return;' + LPPIF = 74, //! #if/#else/#endif pair processing + LMCB = 75, //! mod_case_brace + LBRCH = 76, //! if brace chain + LFCNR = 77, //! function return type + LOCCLASS = 78, //! OC Class stuff + LOCMSG = 79, //! OC Message stuff + LBLANK = 80, //! Blank Lines + LOBJCWORD = 81, //! Convert keyword to CT_WORD in certain circumstances + LCHANGE = 82, //! something changed + LCONTTEXT = 83, //! comment cont_text set + LANNOT = 84, //! Java annotation + LOCBLK = 85, //! OC Block stuff + LFLPAREN = 86, //! Flag paren + LOCMSGD = 87, //! OC Message declaration + LINDENTAG = 88, //! indent again + LNFD = 89, //! newline-function-def + LJDBI = 90, //! Java Double Brace Init + LSETPAR = 91, //! Chunk::SetParentTypeReal() + LSETTYP = 92, //! Chunk::SetTypeReal() + LSETFLG = 93, //! set_chunk_flags() + LNLFUNCT = 94, //! newlines before function + LCHUNK = 95, //! Add or delete chunk + LBC = 96, //! brace cleanup + LCOMBINE = 97, //! combine + LGUY98 = 98, //! for guy-test + LGUY = 99, //! for guy-test + LBR = 100, //! braces + LOUTPUT = 101, //! output + LUNC = 102, //! rules used in uncrustify.cpp + LQT = 103, //! load/save options for Qt + LVARDFBLK = 104, //! newlines for variable definition blocks + LOTHER = 255, //! stuff that doesn't neatly fit any other category +}; + +#endif /* LOG_LEVELS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/log_rules.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/log_rules.cpp new file mode 100644 index 00000000..ec5f6240 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/log_rules.cpp @@ -0,0 +1,106 @@ +/** + * @file log_rules.cpp + * is an extract from space.cpp + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#include "log_rules.h" + +#include "unc_tools.h" + + +void log_rule2(const char *func, size_t line, const char *rule, Chunk *first, Chunk *second) +{ + LOG_FUNC_ENTRY(); + + if (second->IsNot(CT_NEWLINE)) + { + LOG_FMT(LSPACE, "%s(%zu): first orig line is %zu, orig col is %zu, Text() is '%s', [%s/%s] <===>\n", + func, line, first->GetOrigLine(), first->GetOrigCol(), first->Text(), + get_token_name(first->GetType()), get_token_name(first->GetParentType())); + LOG_FMT(LSPACE, " second orig line is %zu, orig col is %zu, Text() is '%s', [%s/%s] :", + second->GetOrigLine(), second->GetOrigCol(), second->Text(), + get_token_name(second->GetType()), get_token_name(second->GetParentType())); + LOG_FMT(LSPACE, " rule %s[line %zu]\n", + rule, line); + } +} + + +#ifdef SUPER_LOG + + +void log_rule3(log_sev_t sev, const char *func, size_t line, const char *rule) +#else + + +void log_rule3(log_sev_t sev, const char *func, const char *rule) +#endif +{ + // some Windows platforms provide a qualified function name ("ABC::XYZ::function_Name") + // as __func__; call get_unqualified_func_name() to return an unqualified function name + + func = get_unqualified_func_name(func); + +#ifdef SUPER_LOG + LOG_FMT(sev, "log_rule(%s:%zu): rule is '%s'\n", func, line, rule); +#else + LOG_FMT(sev, "log_rule(%s): rule is '%s'\n", func, rule); +#endif +} + + +void log_rule4(const char *rule, Chunk *first) +{ + if (!(cpd.html_type == tracking_type_e::TT_SPACE)) + { + return; + } + + if (first->GetTrackingData() == nullptr) + { + first->TrackingData() = new track_list; + } + // copy the rule + size_t length = strlen(rule) + 1; + char *r = (char *)malloc(length); + + strcpy(r, rule); + size_t a_number = get_A_Number(); + Track_nr A = make_pair(a_number, r); + + first->TrackingData()->push_back(A); + size_t sizeOfTrack = first->GetTrackingData()->size(); + + LOG_FMT(LSPACE, "log_rule4(%d): rule is '%s', after '%s', at line %zu, tracking number is %zu, size is %zu\n", + __LINE__, rule, first->Text(), first->GetOrigLine(), a_number, sizeOfTrack); +} + + +void log_ruleNL(const char *rule, Chunk *pc) +{ + if (!(cpd.html_type == tracking_type_e::TT_NEWLINE)) + { + return; + } + + if (pc->GetTrackingData() == nullptr) + { + pc->TrackingData() = new track_list; + } + // copy the rule + size_t length = strlen(rule) + 1; + char *r = (char *)malloc(length); + + strcpy(r, rule); + size_t a_number = get_A_Number(); + Track_nr A = make_pair(a_number, r); + + pc->TrackingData()->push_back(A); + size_t sizeOfTrack = pc->GetTrackingData()->size(); + + LOG_FMT(LSPACE, "log_rule4(%d): rule is '%s', after '%s', at line %zu, tracking number is %zu, size is %zu\n", + __LINE__, rule, pc->Text(), pc->GetOrigLine(), a_number, sizeOfTrack); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/log_rules.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/log_rules.h new file mode 100644 index 00000000..02345a25 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/log_rules.h @@ -0,0 +1,59 @@ +/** + * @file log_rules.h + * prototypes for log_rules.cpp + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#ifndef LOG_RULES_H_INCLUDED +#define LOG_RULES_H_INCLUDED + +#include "chunk.h" +#include "uncrustify.h" + +using namespace uncrustify; + +#if defined DEBUG +#define log_rule(rule) \ + log_rule2(__func__, __LINE__, (rule), first, second); \ + log_rule4((rule), first) +#else +#define log_rule(rule) \ + log_rule2(__func__, __LINE__, (rule), first, second) +#endif + +// if you need more debug information, remove the comment at the next line +#define SUPER_LOG 1 +#ifdef SUPER_LOG +#define log_rule_B(rule) \ + log_rule3(LCURRENT, __func__, __LINE__, (rule)) +#else +#define log_rule_B(rule) \ + log_rule3(LCURRENT, __func__, (rule)) +#endif + +#ifdef SUPER_LOG +#define log_rule_NL(rule) \ + log_ruleNL((rule), pc) +#else +#define log_rule_NL(rule) \ + log_ruleNL(LCURRENT, __func__, (rule)) +#endif + +void log_rule2(const char *func, size_t line, const char *rule, Chunk *first, Chunk *second); + + +#ifdef SUPER_LOG +void log_rule3(log_sev_t sev, const char *func, size_t line, const char *rule); + +#else +void log_rule3(log_sev_t sev, const char *func, const char *rule); + +#endif + +void log_rule4(const char *rule, Chunk *first); + +void log_ruleNL(const char *rule, Chunk *pc); + +#endif /* LOG_RULES_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/logger.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/logger.cpp new file mode 100644 index 00000000..c9a50682 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/logger.cpp @@ -0,0 +1,336 @@ +/** + * @file logger.cpp + * + * Functions to do logging. + * + * If a log statement ends in a newline, the current log is ended. + * When the log severity changes, an implicit newline is inserted. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "logger.h" + +#include "compat.h" + +#include <cstdarg> // to get va_start, va_end + + +struct log_fcn_info +{ + log_fcn_info(const char *name_, int line_) + : name(name_) + , line(line_) + { + } + + const char *name; + int line; +}; +static std::deque<log_fcn_info> g_fq; + +//! Private log structure +struct log_buf +{ + log_buf() + : log_file(nullptr) + , sev(LSYS) + , in_log(0) + , buf_len(0) + , show_hdr(false) + { + bufX.clear(); + bufX.resize(256); + } + + FILE *log_file; //! file where the log messages are stored into + log_sev_t sev; //! log level determines which messages are logged + int in_log; //! flag indicates if a log operation is going on + size_t buf_len; //! number of characters currently stored in buffer + std::vector<char> bufX; //! buffer holds the log message + log_mask_t mask; + bool show_hdr; //! flag determine if a header gets added to log message +}; + + +static struct log_buf g_log; + + +/** + * Starts the log statement by flushing if needed and printing the header + * + * @param sev The log severity + * + * @return The number of bytes available + */ +static size_t log_start(log_sev_t sev); + + +/** + * Cleans up after a log statement by detecting whether the log is done, + * (it ends in a newline) and possibly flushing the log. + */ +static void log_end(); + + +/** + * Initializes the log subsystem - call this first. + * This function sets the log stream and enables the top 3 sevs (0-2). + * + * @param log_file NULL for stderr or the FILE stream for logs. + */ +void log_init(FILE *log_file) +{ + // set the top 3 severities + logmask_set_all(g_log.mask, false); + log_set_sev(LSYS, true); + log_set_sev(LERR, true); + log_set_sev(LWARN, true); + + g_log.log_file = (log_file != nullptr) ? log_file : stderr; +} + + +void log_show_sev(bool show) +{ + g_log.show_hdr = show; +} + + +bool log_sev_on(log_sev_t sev) +{ + return(logmask_test(g_log.mask, sev)); +} + + +void log_set_sev(log_sev_t sev, bool value) +{ + logmask_set_sev(g_log.mask, sev, value); +} + + +void log_set_mask(const log_mask_t &mask) +{ + g_log.mask = mask; +} + + +void log_get_mask(log_mask_t &mask) +{ + mask = g_log.mask; +} + + +void log_flush(bool force_nl) +{ + if (g_log.buf_len > 0) + { + if ( force_nl + && g_log.bufX[g_log.buf_len - 1] != '\n') + { + g_log.bufX[g_log.buf_len++] = '\n'; + g_log.bufX[g_log.buf_len] = 0; + } + size_t retlength = fwrite(&g_log.bufX[0], g_log.buf_len, 1, g_log.log_file); + + if (retlength != 1) + { + // maybe we should log something to complain... =) + } + g_log.buf_len = 0; + } +} + + +static size_t log_start(log_sev_t sev) +{ + if (sev != g_log.sev) + { + if (g_log.buf_len > 0) + { + log_flush(true); + } + g_log.sev = sev; + g_log.in_log = false; + } + + // If not in a log, the buffer is empty. Add the header, if enabled. + if ( !g_log.in_log + && g_log.show_hdr) + { + g_log.buf_len = static_cast<size_t>(snprintf(&g_log.bufX[0], g_log.bufX.size(), "<%d>", sev)); + } + size_t cap = (g_log.bufX.size() - 2) - g_log.buf_len; + + return((cap > 0) ? cap : 0); +} + + +static void log_end() +{ + g_log.in_log = (g_log.bufX[g_log.buf_len - 1] != '\n'); + + if ( !g_log.in_log + || (g_log.buf_len > (g_log.bufX.size() / 2))) + { + log_flush(false); + } +} + + +void log_fmt(log_sev_t sev, const char *fmt, ...) +{ + if ( fmt == nullptr + || !log_sev_on(sev)) + { + return; + } + // Issue #1203 + unsigned int length = strlen(fmt); + + if (length == 0) + { + return; + } + // the value of buffer_length is experimental + const int buffer_length = 40000; + char buf[buffer_length]; + + // it MUST be a 'unsigned int' variable to be runable under windows + + if (length >= buffer_length) + { + fprintf(stderr, "FATAL(1): The variable 'buf' is not big enough:\n"); + fprintf(stderr, " it should be bigger as %u\n", length); + fprintf(stderr, "Please make a report.\n"); + fprintf(stderr, "For the buffer: %s\n", fmt); + exit(EX_SOFTWARE); + } + memcpy(buf, fmt, length); + buf[length] = 0; + convert_log_zu2lu(buf); + + while (true) + { + /* Some implementation of vsnprintf() return the number of characters + * that would have been stored if the buffer was large enough instead of + * the number of characters actually stored. + * + * this gets the number of characters that fit into the log buffer + */ + size_t cap = log_start(sev); + // Add on the variable log parameters to the log string + va_list args; // determine list of arguments ... + va_start(args, fmt); + size_t which = g_log.buf_len; + char *where = &g_log.bufX[which]; + size_t lenX = static_cast<size_t>(vsnprintf(where, cap, buf, args)); + va_end(args); + + if (lenX > 0) + { + // The functions snprintf() and vsnprintf() do not write more than size bytes + // (including the terminating null byte ('\0')). If the output was truncated due + // to this limit, then the return value is the number of characters (excluding the + // terminating null byte) which would have been written to the final string if + // enough space had been available. Thus, a return value of size or more means + // that the output was truncated. + if (lenX > cap) + { + size_t bufXLength = g_log.bufX.size(); + size_t X = bufXLength * 2; + + if (X >= buffer_length) + { + fprintf(stderr, "FATAL(2): The variable 'buf' is not big enough:\n"); + fprintf(stderr, " it should be bigger as %zu\n", X); + fprintf(stderr, "Please make a report.\n"); + fprintf(stderr, "For the buffer: %s\n", fmt); + exit(EX_SOFTWARE); + } + g_log.bufX.resize(X); + } + else + { + g_log.buf_len += lenX; + g_log.bufX[g_log.buf_len] = 0; + break; + } + } + } + log_end(); +} // log_fmt + + +log_func::log_func(const char *name, int line) +{ + g_fq.push_back(log_fcn_info(name, line)); +} + + +log_func::~log_func() +{ + g_fq.pop_back(); +} + + +void log_func_stack(log_sev_t sev, const char *prefix, const char *suffix, size_t skip_cnt) +{ + UNUSED(skip_cnt); + + if (prefix) + { + LOG_FMT(sev, "%s", prefix); + } +#ifdef DEBUG + const char *sep = ""; + size_t g_fq_size = g_fq.size(); + size_t begin_with; + + if (g_fq_size > (skip_cnt + 1)) + { + begin_with = g_fq_size - (skip_cnt + 1); + + for (size_t idx = begin_with; idx != 0; idx--) + { + LOG_FMT(sev, "%s %s:%d", sep, g_fq[idx].name, g_fq[idx].line); + sep = ","; + } + + LOG_FMT(sev, "%s %s:%d", sep, g_fq[0].name, g_fq[0].line); + } +#else + LOG_FMT(sev, "-DEBUG NOT SET-"); +#endif + + if (suffix) + { + LOG_FMT(sev, "%s", suffix); + } +} + + +const char *get_unqualified_func_name(const char *func) +{ + /** + * we look for the last ':' character; + */ + for (auto i = strlen(func); i > 0; --i) + { + if (func[i - 1] == ':') + { + /** + * function name is qualified, so return the + * unqualified portion + */ + return(func + i); + } + } + + /** + * input function name is unqualified + */ + + return(func); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/logger.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/logger.h new file mode 100644 index 00000000..9b27fbab --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/logger.h @@ -0,0 +1,184 @@ +/** + * @file logger.h + * + * Functions to do logging. + * The macros check whether the logsev is active before evaluating the + * parameters. Use them instead of the functions. + * + * If a log statement ends in a newline, the current log is ended. + * When the log severity changes, an implicit newline is inserted. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef LOGGER_H_INCLUDED +#define LOGGER_H_INCLUDED + +#include "logmask.h" + +#include <cstdio> // FILE + + +/** + * Initializes the log subsystem - call this first. + * This function sets the log stream and enables the top 3 sevs (0-2). + * + * @param log_file nullptr for stderr or the FILE stream for logs. + */ +void log_init(FILE *log_file); + + +/** + * Show or hide the severity prefix "<1>" + * + * @param show true=show, false=hide + */ +void log_show_sev(bool show); + + +/** + * Returns whether a log severity is active. + * + * @param sev severity log level + * + * @return true/false + */ +bool log_sev_on(log_sev_t sev); + + +/** + * Sets a log sev on or off + * + * @param sev severity log level to modify + * @param val new value for severity log level + * + * @return true/false + */ +void log_set_sev(log_sev_t sev, bool value); + + +/** + * Sets the log mask + * + * @param mask The mask to copy + */ +void log_set_mask(const log_mask_t &mask); + + +/** + * Gets the log mask + * + * @param mask Where to copy the mask + */ +void log_get_mask(log_mask_t &mask); + + +#ifdef __MINGW_PRINTF_FORMAT +// On MinGW, the printf functions can be provided by a number of different +// implementations, with different format string support. Annontate log_fmt +// below with the same format attribute as the currently chosen default printf +// function. +#define PRINTF_FORMAT __MINGW_PRINTF_FORMAT +#else +#define PRINTF_FORMAT printf +#endif + +/** + * Logs a formatted string -- similar to printf() + * + * @param sev The severity + * @param fmt The format string + * @param ... Additional arguments + */ +void log_fmt(log_sev_t sev, const char *fmt, ...) __attribute__((format(PRINTF_FORMAT, 2, 3))); + + +/** + * Flushes the cached log text to the stream + * + * @param force_nl Append NL if not present + */ +void log_flush(bool force_nl); + + +// it is necessary to make at least one time pro change a check of all the +// uses of the MACRO LOG_FMT under Linux. This to detect all the used pointers, +// which might be nullptr. +// uncomment the define to do that. +// #define NO_MACRO_VARARG + +#ifdef NO_MACRO_VARARG +#define LOG_FMT log_fmt +// TODO during debugging add source file and line number +#else +#define LOG_FMT(sev, ...) \ + if (log_sev_on(sev)) { log_fmt(sev, __VA_ARGS__); } +#endif + + +#define __unqualified_func__ get_unqualified_func_name(__func__) + + +#define LOG_CHUNK(sev, pc_current) \ + if (pc_current->Is(CT_NEWLINE)) \ + { \ + LOG_FMT(sev, "%s(%d): orig line is %zu, orig col is %zu, <Newline>, PRE is %s\n", \ + __func__, __LINE__, pc_current->GetOrigLine(), pc_current->GetOrigCol(), pc_current->IsPreproc() ? "true" : "false"); \ + } \ + else if (pc_current->Is(CT_NL_CONT)) \ + { \ + LOG_FMT(sev, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s, PRE is %s\n", \ + __func__, __LINE__, pc_current->GetOrigLine(), pc_current->GetOrigCol(), pc_current->Text(), get_token_name(pc_current->GetType()), pc_current->IsPreproc() ? "true" : "false"); \ + } \ + else \ + { \ + LOG_FMT(sev, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s, PRE is %s\n", \ + __func__, __LINE__, pc_current->GetOrigLine(), pc_current->GetOrigCol(), pc_current->Text(), get_token_name(pc_current->GetType()), pc_current->IsPreproc() ? "true" : "false"); \ + } + + +#ifdef DEBUG +/** + * This should be called as the first thing in a function. + * It uses the log_func class to add an entry to the function log stack. + * It is automatically removed when the function returns. + */ +#define LOG_FUNC_ENTRY() log_func log_fe = log_func(__unqualified_func__, __LINE__) + + +#else +#define LOG_FUNC_ENTRY() +#endif + + +/** + * This class just adds a entry to the top of the stack on construction and + * removes it on destruction. + * RAII for the win. + */ +class log_func +{ +public: + log_func(const char *name, int line); + + + ~log_func(); +}; + + +void log_func_stack(log_sev_t sev, const char *prefix = 0, const char *suffix = "\n", size_t skip_cnt = 0); + + +/** + * Return the unqualified function name from the input argument + * @param the qualified function name, usually provided by __func__ macro + * @return the corresponding unqualified name + */ +const char *get_unqualified_func_name(const char *func); + + +#define log_func_stack_inline(_sev) log_func_stack((_sev), " [CallStack:", "]\n", 0) + + +#endif /* LOGGER_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/logmask.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/logmask.cpp new file mode 100644 index 00000000..148ce193 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/logmask.cpp @@ -0,0 +1,142 @@ +/** + * @file logmask.cpp + * + * Functions to convert between a string and a severity mask. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "logmask.h" + +#include "unc_ctype.h" + +#include <cstdio> // snprintf() +#include <cstdlib> // strtoul() + +#ifdef DEVELOP_ONLY + + +/* + * the test suite Coveralls: https://coveralls.io + * will complains because these functions are only + * used at development time. + * Don't worry about unused lines for the functions: + * logmask_to_str + */ +char *logmask_to_str(const log_mask_t &mask, char *buf, int size) +{ + if ( buf == nullptr + || size <= 0) + { + return(buf); + } + int last_sev = -1; + bool is_range = false; + int len = 0; + + for (int sev = 0; sev < 256; sev++) + { + if (logmask_test(mask, static_cast<log_sev_t>(sev))) + { + if (last_sev == -1) + { + len += snprintf(&buf[len], size - len, "%d,", sev); + } + else + { + is_range = true; + } + last_sev = sev; + } + else + { + if (is_range) + { + buf[len - 1] = '-'; // change last comma to a dash + len += snprintf(&buf[len], size - len, "%d,", last_sev); + is_range = false; + } + last_sev = -1; + } + } + + // handle a range that ends on the last bit + if ( is_range + && last_sev != -1) + { + buf[len - 1] = '-'; // change last comma to a dash + len += snprintf(&buf[len], size - len, "%d", last_sev); + } + else + { + // Eat the last comma + if (len > 0) + { + len--; + } + } + buf[len] = 0; + + return(buf); +} // logmask_to_str +#endif /* DEVELOP_ONLY */ + + +void logmask_from_string(const char *str, log_mask_t &mask) +{ + if (str == nullptr) + { + return; + } + logmask_set_all(mask, false); // Start with a clean mask + + // If the first character is 'a' or 'A', set all severities + if (unc_toupper(*str) == 'A') + { + logmask_set_all(mask, true); + str++; + } + char *ptmp; + bool was_dash = false; + int last_level = -1; + + while (*str != 0) // check string until termination character + { + if (unc_isspace(*str)) // ignore spaces and go on with next character + { + str++; + continue; + } + + if (unc_isdigit(*str)) + { + int level = strtoul(str, &ptmp, 10); + str = ptmp; + + logmask_set_sev(mask, static_cast<log_sev_t>(level), true); + + if (was_dash) + { + for (int idx = last_level + 1; idx < level; idx++) + { + logmask_set_sev(mask, static_cast<log_sev_t>(idx), true); + } + + was_dash = false; + } + last_level = level; + } + else if (*str == '-') // a dash marks all bits until the next number + { + was_dash = true; + str++; + } + else // probably a comma + { + last_level = -1; + was_dash = false; + str++; + } + } +} // logmask_from_string diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/logmask.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/logmask.h new file mode 100644 index 00000000..ef00e1d0 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/logmask.h @@ -0,0 +1,103 @@ +/** + * @file logmask.h + * + * Functions to manipulate a log severity mask. + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef LOGMASK_H_INCLUDED +#define LOGMASK_H_INCLUDED + +#include "base_types.h" +#include "log_levels.h" + +#include <bitset> +#include <cstring> // memset() + +/* + * the test suite Coveralls: https://coveralls.io + * will complains because these functions are only + * used at development time. + * Don't worry about unused lines for the functions: + * logmask_test + * logmask_set_all + */ + +//! A simple array of 256 bits +typedef std::bitset<256> log_mask_t; + + +/** + * Tests whether a sev bit is set in the mask + * + * @param mask log mask to evaluate + * @param sev severity bit to check + * + * @return true (is set) or false (not set) + */ +static inline bool logmask_test(const log_mask_t &mask, log_sev_t sev) +{ + return(mask.test(sev)); +} + + +/** + * Sets a set bit in the mask + * + * @param mask log mask to modify + * @param sev The severity to check + * @param value true (set bit) or false (clear bit) + */ +static inline void logmask_set_sev(log_mask_t &mask, log_sev_t sev, bool value) +{ + mask.set(sev, value); +} + + +/** + * Sets all bits to the same value + * + * @param mast log mask to operate on + * @param value true (set bit) or false (clear bit) + */ +static inline void logmask_set_all(log_mask_t &mask, bool value) +{ + if (value) + { + mask.set(); + } + else + { + mask.reset(); + } +} + + +#ifdef DEVELOP_ONLY +/** + * Convert a logmask into a string. + * The string is a comma-delimited list of severities. + * Example: 1,3,5-10 + * + * @param mask the mask to convert + * @param buf the buffer to hold the string + * @param size the size of the buffer + * + * @return buf (pass through) + */ +char *logmask_to_str(const log_mask_t &mask, char *buf, int size); + +#endif /* DEVELOP_ONLY */ + + +/** + * Parses a string into a log severity + * + * @param str string to parse + * @param mask bit mask to populate with log levels + */ +void logmask_from_string(const char *str, log_mask_t &mask); + + +#endif /* LOGMASK_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/mark_question_colon.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/mark_question_colon.cpp new file mode 100644 index 00000000..cd058697 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/mark_question_colon.cpp @@ -0,0 +1,112 @@ +/** + * @file mark_question_colon.cpp + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#include "mark_question_colon.h" + +#include "chunk.h" +#include "combine_tools.h" +#include "log_levels.h" +#include "unc_tools.h" + + +/* + * Issue #3558 + * will be called if a chunk ? (CT_QUESTION) is entcountered + * return the chunk : + * return nullptr is a chunk ; (CT_SEMI_COLON) is found + */ +Chunk *search_for_colon(Chunk *pc_local) +{ + Chunk *pc2; + + LOG_FMT(LCOMBINE, "%s(%d): orig line is %zu, orig col is %zu, level is %zu, Text() is '%s'\n", + __func__, __LINE__, pc_local->GetOrigLine(), pc_local->GetOrigCol(), pc_local->GetLevel(), pc_local->Text()); + Chunk *colon = pc_local->GetNextType(CT_COLON, pc_local->GetLevel()); + + if (colon != nullptr) + { + LOG_FMT(LCOMBINE, "%s(%d): orig line is %zu, orig col is %zu, level is %zu, Text() is '%s'\n", + __func__, __LINE__, colon->GetOrigLine(), colon->GetOrigCol(), colon->GetLevel(), colon->Text()); + colon->SetType(CT_COND_COLON); + flag_series(pc_local, colon, PCF_IN_CONDITIONAL); + + // examine the next tokens, search for a next CT_QUESTION + for (pc2 = colon->GetNext(); pc2->IsNotNullChunk(); pc2 = pc2->GetNextNcNnl()) + { + LOG_FMT(LCOMBINE, "%s(%d): THE NEXT: orig line is %zu, orig col is %zu, level is %zu, Text() is '%s'\n", + __func__, __LINE__, pc2->GetOrigLine(), pc2->GetOrigCol(), pc2->GetLevel(), pc2->Text()); + pc2->SetFlagBits(PCF_IN_CONDITIONAL); + log_pcf_flags(LCOMBINE, pc2->GetFlags()); + + if (pc2->Is(CT_SEMICOLON)) + { + LOG_FMT(LCOMBINE, "%s(%d): orig line is %zu, orig col is %zu, level is %zu, Text() is '%s'\n", + __func__, __LINE__, pc2->GetOrigLine(), pc2->GetOrigCol(), pc2->GetLevel(), pc2->Text()); + return(pc2); + } + else if (pc2->Is(CT_QUESTION)) + { + LOG_FMT(LCOMBINE, "%s(%d): orig line is %zu, orig col is %zu, level is %zu, Text() is '%s'\n", + __func__, __LINE__, pc2->GetOrigLine(), pc2->GetOrigCol(), pc2->GetLevel(), pc2->Text()); + pc2 = search_for_colon(pc2); + LOG_FMT(LCOMBINE, "%s(%d): orig line is %zu, orig col is %zu, level is %zu, Text() is '%s'\n", + __func__, __LINE__, pc2->GetOrigLine(), pc2->GetOrigCol(), pc2->GetLevel(), pc2->Text()); + return(pc2); + } + } + } + else + { + LOG_FMT(LWARN, "%s(%d): %zu: Error: Expected a colon\n", + __func__, __LINE__, pc_local->GetOrigLine()); + exit(EX_SOFTWARE); + } + LOG_FMT(LCOMBINE, "%s(%d): orig line is %zu, orig col is %zu, level is %zu, Text() is '?'\n", + __func__, __LINE__, pc2->GetOrigLine(), pc2->GetOrigCol(), pc2->GetLevel()); + return(pc2); +} // search_for_colon + + +void mark_question_colon() +{ + LOG_FUNC_ENTRY(); + Chunk *pc; + + // Issue #3558 + for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + LOG_FMT(LCOMBINE, "%s(%d): orig line is %zu, orig col is %zu, level is %zu, Text() '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->GetLevel(), pc->Text()); + log_pcf_flags(LCOMBINE, pc->GetFlags()); + + if (pc->Is(CT_QUESTION)) + { + Chunk *colon = search_for_colon(pc); + + if (colon != nullptr) + { + LOG_FMT(LCOMBINE, "%s(%d): orig line is %zu, orig col is %zu, level is %zu, Text() is '%s'\n", + __func__, __LINE__, colon->GetOrigLine(), colon->GetOrigCol(), colon->GetLevel(), colon->Text()); + + if (colon->Is(CT_SEMICOLON)) + { + // set at the end of the question statement ... + pc = colon; + LOG_FMT(LCOMBINE, "%s(%d): orig line is %zu, orig col is %zu, level is %zu, Text() is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->GetLevel(), pc->Text()); + // ... and go on + } + } + else + { + LOG_FMT(LWARN, "%s(%d): %zu: Error: Expected a colon\n", + __func__, __LINE__, pc->GetOrigLine()); + exit(EX_SOFTWARE); + } + } + } +} // mark_question_colon diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/mark_question_colon.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/mark_question_colon.h new file mode 100644 index 00000000..20fca294 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/mark_question_colon.h @@ -0,0 +1,13 @@ +/** + * @file mark_question_colon.h + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#ifndef MARK_QUESTION_COLON_H_INCLUDED +#define MARK_QUESTION_COLON_H_INCLUDED + +void mark_question_colon(); + +#endif /* MARK_QUESTION_COLON_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/md5.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/md5.cpp new file mode 100644 index 00000000..af8874a4 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/md5.cpp @@ -0,0 +1,308 @@ +/** + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legales + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * @license Public Domain / GPL v2+ + */ + +#include "md5.h" + +#include <string.h> + + +void MD5::reverse_u32(UINT8 *buf, int n_u32) +{ + UINT8 tmp; + + if (m_big_endian) + { + // change { 4, 3, 2, 1 } => { 1, 2, 3, 4 } + while (n_u32-- > 0) + { + tmp = buf[0]; + buf[0] = buf[3]; + buf[3] = tmp; + + tmp = buf[1]; + buf[1] = buf[2]; + buf[2] = tmp; + + buf += 4; + } + } + else + { + // change { 4, 3, 2, 1 } => { 3, 4, 1, 2 } + while (n_u32-- > 0) + { + tmp = buf[0]; + buf[0] = buf[1]; + buf[1] = tmp; + + tmp = buf[2]; + buf[2] = buf[3]; + buf[3] = tmp; + + buf += 4; + } + } +} + + +MD5::MD5() +{ + m_buf[0] = 0x01020304; + + /* + * Little endian = { 4, 3, 2, 1 } + * Big endian = { 1, 2, 3, 4 } + * PDP endian = { 3, 4, 1, 2 } + * + * The MD5 stuff is written for little endian. + */ + + m_in8 = (UINT8 *)m_in32; + m_need_byteswap = *(UINT8 *)m_buf != 4; + m_big_endian = *(UINT8 *)m_buf == 1; +} + + +//! Start MD5 accumulation. +void MD5::Init() +{ + m_buf[0] = 0x67452301; + m_buf[1] = 0xefcdab89; + m_buf[2] = 0x98badcfe; + m_buf[3] = 0x10325476; + + m_bits[0] = 0; + m_bits[1] = 0; +} + + +//! Update context to reflect the concatenation of another buffer full of bytes. +void MD5::Update(const void *data, UINT32 len) +{ + const UINT8 *buf = (const UINT8 *)data; + + UINT32 t = m_bits[0]; // Update bitcount + + if ((m_bits[0] = t + ((UINT32)len << 3)) < t) + { + m_bits[1]++; // Carry from low to high + } + m_bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; // Bytes already in shsInfo->data + + // Handle any leading odd-sized chunks + if (t) + { + UINT8 *p = m_in8 + t; + + t = 64 - t; + + if (len < t) + { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + + if (m_need_byteswap) + { + reverse_u32(m_in8, 16); + } + Transform(m_buf, m_in32); + buf += t; + len -= t; + } + + // Process data in 64-byte chunks + while (len >= 64) + { + memcpy(m_in32, buf, 64); + + if (m_need_byteswap) + { + reverse_u32(m_in8, 16); + } + Transform(m_buf, m_in32); + buf += 64; // TODO: possible creation of out-of-bounds pointer 64 beyond end of data + len -= 64; + } + // Save off any remaining bytes of data + memcpy(m_in32, buf, len); // TODO: possible access beyond array +} // MD5::Update + + +void MD5::Final(UINT8 digest[16]) +{ + // Compute number of bytes modulo 64 + UINT32 count = (m_bits[0] >> 3) & 0x3F; + + /* + * Set the first char of padding to 0x80. This is safe since there is always + * at least one byte free + */ + UINT8 *p = m_in8 + count; + + *p++ = 0x80; + + // Bytes of padding needed to make 64 bytes + count = 64 - 1 - count; + + // Pad out to 56 modulo 64 + if (count < 8) + { + // Two lots of padding: Pad the first block to 64 bytes + memset(p, 0, count); + + if (m_need_byteswap) + { + reverse_u32(m_in8, 16); + } + Transform(m_buf, m_in32); + + // Now fill the next block with 56 bytes + memset(m_in32, 0, 56); + } + else + { + // Pad block to 56 bytes + memset(p, 0, count - 8); + } + + if (m_need_byteswap) + { + reverse_u32(m_in8, 14); + } + // Append length in bits and transform + memcpy(m_in8 + 56, &m_bits[0], 4); + memcpy(m_in8 + 60, &m_bits[1], 4); + + Transform(m_buf, m_in32); + + if (m_need_byteswap) + { + reverse_u32((UINT8 *)m_buf, 4); + } + memcpy(digest, m_buf, 16); +} // MD5::Final + + +// The four core functions - F1 is optimized somewhat +// #define F1(x, y, z) (x & y | ~x & z) +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + + +// This is the central step in the MD5 algorithm. +#define MD5STEP(f, w, x, y, z, data, s) \ + ((w) += f((x), (y), (z)) + (data), (w) = (w) << (s) | (w) >> (32 - (s)), (w) += (x)) + + +void MD5::Transform(UINT32 buf[4], UINT32 in_data[16]) +{ + UINT32 a = buf[0]; + UINT32 b = buf[1]; + UINT32 c = buf[2]; + UINT32 d = buf[3]; + + MD5STEP(F1, a, b, c, d, in_data[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in_data[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in_data[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in_data[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in_data[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in_data[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in_data[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in_data[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in_data[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in_data[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in_data[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in_data[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in_data[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in_data[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in_data[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in_data[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in_data[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in_data[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in_data[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in_data[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in_data[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in_data[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in_data[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in_data[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in_data[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in_data[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in_data[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in_data[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in_data[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in_data[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in_data[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in_data[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in_data[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in_data[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in_data[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in_data[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in_data[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in_data[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in_data[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in_data[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in_data[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in_data[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in_data[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in_data[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in_data[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in_data[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in_data[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in_data[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in_data[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in_data[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in_data[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in_data[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in_data[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in_data[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in_data[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in_data[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in_data[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in_data[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in_data[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in_data[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in_data[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in_data[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in_data[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in_data[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} // MD5::Transform + + +void MD5::Calc(const void *data, UINT32 length, UINT8 digest[16]) +{ + MD5 md5; + + md5.Init(); + md5.Update(data, length); + md5.Final(digest); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/md5.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/md5.h new file mode 100644 index 00000000..d1148b5e --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/md5.h @@ -0,0 +1,85 @@ +/** + * @file md5.h + * A simple class for MD5 calculation + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef MD5_H_INCLUDED +#define MD5_H_INCLUDED + +#include "base_types.h" + +class MD5 +{ +public: + MD5(); + + + ~MD5() + { + } + + + /** + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ + void Init(); + + + /** + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ + void Update(const void *data, UINT32 len); + + + /** + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + * + * @param[out] digest calculated MD5 checksum + */ + void Final(UINT8 digest[16]); + + + /** + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5::Update blocks + * the data and converts bytes into longwords for this routine. + */ + static void Transform(UINT32 buf[4], UINT32 in_data[16]); + + + /** + * Calculates MD5 for a block of data + * + * @param data data to calculate MD5 for + * @param length number of bytes in data + * @param[out] digest calculated MD5 checksum + */ + static void Calc(const void *data, UINT32 length, UINT8 digest[16]); + + +private: + UINT32 m_buf[4]; + UINT32 m_bits[2]; + UINT32 m_in32[16]; + // Alternate view of m_in32 + UINT8 *m_in8; + bool m_need_byteswap; + bool m_big_endian; + + + /** + * Reverse the bytes in 32-bit chunks. + * 'buf' might not be word-aligned. + * + * @param buf The byte array to reverse + * @param n_u32 The number of UINT32's in the data + */ + void reverse_u32(UINT8 *buf, int n_u32); +}; + +#endif /* MD5_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/newlines.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/newlines.cpp new file mode 100644 index 00000000..ca24e941 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/newlines.cpp @@ -0,0 +1,6845 @@ +/** + * @file newlines.cpp + * Adds or removes newlines. + * + * Information + * "Ignore" means do not change it. + * "Add" in the context of spaces means make sure there is at least 1. + * "Add" elsewhere means make sure one is present. + * "Remove" mean remove the space/brace/newline/etc. + * "Force" in the context of spaces means ensure that there is exactly 1. + * "Force" in other contexts means the same as "add". + * + * Rmk: spaces = space + nl + * + * @author Ben Gardner + * @author Guy Maurel + * @license GPL v2+ + */ + +#include "newlines.h" + +#include "align_stack.h" +#include "combine_skip.h" +#include "flag_parens.h" +#include "indent.h" +#include "keywords.h" +#include "prototypes.h" +#include "space.h" +#include "unc_tools.h" + +#ifdef WIN32 +#include <algorithm> // to get max +#endif // ifdef WIN32 + + +constexpr static auto LCURRENT = LNEWLINE; + +using namespace std; +using namespace uncrustify; + + +static void mark_change(const char *func, size_t line); + + +/** + * Check to see if we are allowed to increase the newline count. + * We can't increase the newline count: + * - if nl_squeeze_ifdef and a preproc is after the newline. + * - if eat_blanks_before_close_brace and the next is '}' + * - unless function contains an empty body and + * nl_inside_empty_func is non-zero + * - if eat_blanks_after_open_brace and the prev is '{' + * - unless the brace belongs to a namespace + * and nl_inside_namespace is non-zero + */ +static bool can_increase_nl(Chunk *nl); + + +/** + * Basic approach: + * 1. Find next open brace + * 2. Find next close brace + * 3. Determine why the braces are there + * a. struct/union/enum "enum [name] {" + * c. assignment "= {" + * b. if/while/switch/for/etc ") {" + * d. else "} else {" + */ +static void setup_newline_add(Chunk *prev, Chunk *nl, Chunk *next); + + +//! Make sure there is a blank line after a commented group of values +static void newlines_double_space_struct_enum_union(Chunk *open_brace); + + +//! If requested, make sure each entry in an enum is on its own line +static void newlines_enum_entries(Chunk *open_brace, iarf_e av); + + +/** + * Checks to see if it is OK to add a newline around the chunk. + * Don't want to break one-liners... + * return value: + * true: a new line may be added + * false: a new line may NOT be added + */ +static bool one_liner_nl_ok(Chunk *pc); + + +static void nl_create_one_liner(Chunk *vbrace_open); + + +static void nl_create_list_liner(Chunk *brace_open); + + +/** + * Test if a chunk belongs to a one-liner method definition inside a class body + */ +static bool is_class_one_liner(Chunk *pc); + + +/** + * Test if a chunk may be combined with a function prototype group. + * + * If nl_class_leave_one_liner_groups is enabled, a chunk may be combined with + * a function prototype group if it is a one-liner inside a class body, and is + * a definition of the same sort as surrounding prototypes. This checks against + * either the function name, or the function closing brace. + */ +bool is_func_proto_group(Chunk *pc, E_Token one_liner_type); + +/** + * Test if an opening brace is part of a function call or definition. + */ +static bool is_func_call_or_def(Chunk *pc); + + +//! Find the next newline or nl_cont +static void nl_handle_define(Chunk *pc); + + +/** + * Does the Ignore, Add, Remove, or Force thing between two chunks + * + * @param before The first chunk + * @param after The second chunk + * @param av The IARF value + */ +static void newline_iarf_pair(Chunk *before, Chunk *after, iarf_e av, bool check_nl_assign_leave_one_liners = false); + + +/** + * Adds newlines to multi-line function call/decl/def + * Start points to the open paren + */ +static void newline_func_multi_line(Chunk *start); + + +static void newline_template(Chunk *start); + + +/** + * Formats a function declaration + * Start points to the open paren + */ +static void newline_func_def_or_call(Chunk *start); + + +/** + * Formats a message, adding newlines before the item before the colons. + * + * Start points to the open '[' in: + * [myObject doFooWith:arg1 name:arg2 // some lines with >1 arg + * error:arg3]; + */ +static void newline_oc_msg(Chunk *start); + + +//! Ensure that the next non-comment token after close brace is a newline +static void newline_end_newline(Chunk *br_close); + + +/** + * Add or remove a newline between the closing paren and opening brace. + * Also uncuddles anything on the closing brace. (may get fixed later) + * + * "if (...) { \n" or "if (...) \n { \n" + * + * For virtual braces, we can only add a newline after the vbrace open. + * If we do so, also add a newline after the vbrace close. + */ +static bool newlines_if_for_while_switch(Chunk *start, iarf_e nl_opt); + + +/** + * Add or remove extra newline before the chunk. + * Adds before comments + * Doesn't do anything if open brace before it + * "code\n\ncomment\nif (...)" or "code\ncomment\nif (...)" + */ +static void newlines_if_for_while_switch_pre_blank_lines(Chunk *start, iarf_e nl_opt); + + +static void blank_line_set(Chunk *pc, Option<unsigned> &opt); + + +/** + * Add one/two newline(s) before the chunk. + * Adds before comments + * Adds before destructor + * Doesn't do anything if open brace before it + * "code\n\ncomment\nif (...)" or "code\ncomment\nif (...)" + */ +static void newlines_func_pre_blank_lines(Chunk *start, E_Token start_type); + + +static Chunk *get_closing_brace(Chunk *start); + + +/** + * remove any consecutive newlines following this chunk + * skip vbraces + */ +static void remove_next_newlines(Chunk *start); + + +/** + * Add or remove extra newline after end of the block started in chunk. + * Doesn't do anything if close brace after it + * Interesting issue is that at this point, nls can be before or after vbraces + * VBraces will stay VBraces, conversion to real ones should have already happened + * "if (...)\ncode\ncode" or "if (...)\ncode\n\ncode" + */ +static void newlines_if_for_while_switch_post_blank_lines(Chunk *start, iarf_e nl_opt); + + +/** + * Adds or removes a newline between the keyword and the open brace. + * If there is something after the '{' on the same line, then + * the newline is removed unconditionally. + * If there is a '=' between the keyword and '{', do nothing. + * + * "struct [name] {" or "struct [name] \n {" + */ +static void newlines_struct_union(Chunk *start, iarf_e nl_opt, bool leave_trailing); +static void newlines_enum(Chunk *start); +static void newlines_namespace(Chunk *start); // Issue #2186 + + +/** + * Cuddles or un-cuddles a chunk with a previous close brace + * + * "} while" vs "} \n while" + * "} else" vs "} \n else" + * + * @param start The chunk - should be CT_ELSE or CT_WHILE_OF_DO + */ +static void newlines_cuddle_uncuddle(Chunk *start, iarf_e nl_opt); + + +/** + * Adds/removes a newline between else and '{'. + * "else {" or "else \n {" + */ +static void newlines_do_else(Chunk *start, iarf_e nl_opt); + + +//! Check if token starts a variable declaration +static bool is_var_def(Chunk *pc, Chunk *next); + + +//! Put newline(s) before and/or after a block of variable definitions +static Chunk *newline_var_def_blk(Chunk *start); + + +/** + * Handles the brace_on_func_line setting and decides if the closing brace + * of a pair should be right after a newline. + * The only cases where the closing brace shouldn't be the first thing on a line + * is where the opening brace has junk after it AND where a one-liner in a + * class is supposed to be preserved. + * + * General rule for break before close brace: + * If the brace is part of a function (call or definition) OR if the only + * thing after the opening brace is comments, the there must be a newline + * before the close brace. + * + * Example of no newline before close + * struct mystring { int len; + * char str[]; }; + * while (*(++ptr) != 0) { } + * + * Examples of newline before close + * void foo() { + * } + */ +static void newlines_brace_pair(Chunk *br_open); + + +/** + * Put a empty line between the 'case' statement and the previous case colon + * or semicolon. + * Does not work with PAWN (?) + */ +static void newline_case(Chunk *start); + + +static void newline_case_colon(Chunk *start); + + +//! Put a blank line before a return statement, unless it is after an open brace +static void newline_before_return(Chunk *start); + + +/** + * Put a empty line after a return statement, unless it is followed by a + * close brace. + * + * May not work with PAWN + */ +static void newline_after_return(Chunk *start); + + +static void blank_line_max(Chunk *pc, Option<unsigned> &opt); + + +static iarf_e newline_template_option(Chunk *pc, iarf_e special, iarf_e base, iarf_e fallback); + + +#define MARK_CHANGE() mark_change(__func__, __LINE__) + + +static void mark_change(const char *func, size_t line) +{ + LOG_FUNC_ENTRY(); + + cpd.changes++; + + if (cpd.pass_count == 0) + { + LOG_FMT(LCHANGE, "%s(%d): change %d on %s:%zu\n", + __func__, __LINE__, cpd.changes, func, line); + } +} // mark_change + + +static bool can_increase_nl(Chunk *nl) +{ + LOG_FUNC_ENTRY(); + + Chunk *prev = nl->GetPrevNc(); + + Chunk *pcmt = nl->GetPrev(); + Chunk *next = nl->GetNext(); + + if (options::nl_squeeze_ifdef()) + { + log_rule_B("nl_squeeze_ifdef"); + + Chunk *pp_start = prev->GetPpStart(); + + if ( pp_start->IsNotNullChunk() + && ( pp_start->GetParentType() == CT_PP_IF + || pp_start->GetParentType() == CT_PP_ELSE) + && ( pp_start->GetLevel() > 0 + || options::nl_squeeze_ifdef_top_level())) + { + log_rule_B("nl_squeeze_ifdef_top_level"); + bool rv = ifdef_over_whole_file() && pp_start->TestFlags(PCF_WF_IF); + LOG_FMT(LBLANKD, "%s(%d): nl_squeeze_ifdef %zu (prev) pp_lvl=%zu rv=%d\n", + __func__, __LINE__, nl->GetOrigLine(), nl->GetPpLevel(), rv); + return(rv); + } + + if ( next->Is(CT_PREPROC) + && ( next->GetParentType() == CT_PP_ELSE + || next->GetParentType() == CT_PP_ENDIF) + && ( next->GetLevel() > 0 + || options::nl_squeeze_ifdef_top_level())) + { + log_rule_B("nl_squeeze_ifdef_top_level"); + bool rv = ifdef_over_whole_file() && next->TestFlags(PCF_WF_ENDIF); + LOG_FMT(LBLANKD, "%s(%d): nl_squeeze_ifdef %zu (next) pp_lvl=%zu rv=%d\n", + __func__, __LINE__, nl->GetOrigLine(), nl->GetPpLevel(), rv); + return(rv); + } + } + + if (next->Is(CT_BRACE_CLOSE)) + { + if ( options::nl_inside_namespace() > 0 + && next->GetParentType() == CT_NAMESPACE) + { + log_rule_B("nl_inside_namespace"); + LOG_FMT(LBLANKD, "%s(%d): nl_inside_namespace %zu\n", + __func__, __LINE__, nl->GetOrigLine()); + return(true); + } + + if ( options::nl_inside_empty_func() > 0 + && prev->Is(CT_BRACE_OPEN) + && ( next->GetParentType() == CT_FUNC_DEF + || next->GetParentType() == CT_FUNC_CLASS_DEF)) + { + log_rule_B("nl_inside_empty_func"); + LOG_FMT(LBLANKD, "%s(%d): nl_inside_empty_func %zu\n", + __func__, __LINE__, nl->GetOrigLine()); + return(true); + } + + if (options::eat_blanks_before_close_brace()) + { + log_rule_B("eat_blanks_before_close_brace"); + LOG_FMT(LBLANKD, "%s(%d): eat_blanks_before_close_brace %zu\n", + __func__, __LINE__, nl->GetOrigLine()); + return(false); + } + } + + if (prev->Is(CT_BRACE_CLOSE)) + { + if ( options::nl_before_namespace() + && prev->GetParentType() == CT_NAMESPACE) + { + log_rule_B("nl_before_namespace"); + LOG_FMT(LBLANKD, "%s(%d): nl_before_namespace %zu\n", + __func__, __LINE__, nl->GetOrigLine()); + return(true); + } + } + + if (prev->Is(CT_BRACE_OPEN)) + { + if ( options::nl_inside_namespace() > 0 + && prev->GetParentType() == CT_NAMESPACE) + { + log_rule_B("nl_inside_namespace"); + LOG_FMT(LBLANKD, "%s(%d): nl_inside_namespace %zu\n", + __func__, __LINE__, nl->GetOrigLine()); + return(true); + } + + if ( options::nl_inside_empty_func() > 0 + && next->Is(CT_BRACE_CLOSE) + && ( prev->GetParentType() == CT_FUNC_DEF + || prev->GetParentType() == CT_FUNC_CLASS_DEF)) + { + log_rule_B("nl_inside_empty_func"); + LOG_FMT(LBLANKD, "%s(%d): nl_inside_empty_func %zu\n", + __func__, __LINE__, nl->GetOrigLine()); + return(true); + } + + if (options::eat_blanks_after_open_brace()) + { + log_rule_B("eat_blanks_after_open_brace"); + LOG_FMT(LBLANKD, "%s(%d): eat_blanks_after_open_brace %zu\n", + __func__, __LINE__, nl->GetOrigLine()); + return(false); + } + } + log_rule_B("nl_start_of_file"); + + if ( !pcmt + && (options::nl_start_of_file() != IARF_IGNORE)) + { + LOG_FMT(LBLANKD, "%s(%d): SOF no prev %zu\n", __func__, __LINE__, nl->GetOrigLine()); + return(false); + } + log_rule_B("nl_end_of_file"); + + if ( next->IsNullChunk() + && (options::nl_end_of_file() != IARF_IGNORE)) + { + LOG_FMT(LBLANKD, "%s(%d): EOF no next %zu\n", __func__, __LINE__, nl->GetOrigLine()); + return(false); + } + return(true); +} // can_increase_nl + + +static void setup_newline_add(Chunk *prev, Chunk *nl, Chunk *next) +{ + LOG_FUNC_ENTRY(); + + if ( prev == nullptr + || nl == nullptr + || next == nullptr) + { + return; + } + undo_one_liner(prev); + + nl->SetOrigLine(prev->GetOrigLine()); + nl->SetLevel(prev->GetLevel()); + nl->SetPpLevel(prev->GetPpLevel()); + nl->SetBraceLevel(prev->GetBraceLevel()); + nl->SetPpLevel(prev->GetPpLevel()); + nl->SetNlCount(1); + nl->SetFlags((prev->GetFlags() & PCF_COPY_FLAGS) & ~PCF_IN_PREPROC); + nl->SetOrigCol(prev->GetOrigColEnd()); + nl->SetColumn(prev->GetOrigCol()); + + if ( prev->TestFlags(PCF_IN_PREPROC) + && next->TestFlags(PCF_IN_PREPROC)) + { + nl->SetFlagBits(PCF_IN_PREPROC); + } + + if (nl->TestFlags(PCF_IN_PREPROC)) + { + nl->SetType(CT_NL_CONT); + nl->Str() = "\\\n"; + } + else + { + nl->SetType(CT_NEWLINE); + nl->Str() = "\n"; + } +} // setup_newline_add + + +void double_newline(Chunk *nl) +{ + LOG_FUNC_ENTRY(); + + Chunk *prev = Chunk::NullChunkPtr; + + if (nl != nullptr) + { + prev = nl->GetPrev(); + } + + if (prev->IsNullChunk()) + { + return; + } + LOG_FMT(LNEWLINE, "%s(%d): add newline after ", __func__, __LINE__); + + if (prev->Is(CT_VBRACE_CLOSE)) + { + LOG_FMT(LNEWLINE, "VBRACE_CLOSE "); + } + else + { + LOG_FMT(LNEWLINE, "'%s' ", prev->Text()); + } + LOG_FMT(LNEWLINE, "on line %zu", prev->GetOrigLine()); + + if (!can_increase_nl(nl)) + { + LOG_FMT(LNEWLINE, " - denied\n"); + return; + } + LOG_FMT(LNEWLINE, " - done\n"); + + if (nl->GetNlCount() != 2) + { + nl->SetNlCount(2); + MARK_CHANGE(); + } +} // double_newline + + +Chunk *newline_add_before(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + Chunk nl; + Chunk *prev = pc->GetPrevNvb(); + + if (prev->IsNewline()) + { + // Already has a newline before this chunk + return(prev); + } + LOG_FMT(LNEWLINE, "%s(%d): Text() '%s', on orig line is %zu, orig col is %zu, pc column is %zu", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol(), pc->GetColumn()); + log_func_stack_inline(LNEWLINE); + + setup_newline_add(prev, &nl, pc); + nl.SetOrigCol(pc->GetOrigCol()); + nl.SetPpLevel(pc->GetPpLevel()); + LOG_FMT(LNEWLINE, "%s(%d): nl column is %zu\n", + __func__, __LINE__, nl.GetColumn()); + + MARK_CHANGE(); + return(nl.CopyAndAddBefore(pc)); +} // newline_add_before + + +Chunk *newline_force_before(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + Chunk *nl = newline_add_before(pc); + + if ( nl->IsNotNullChunk() + && nl->GetNlCount() > 1) + { + nl->SetNlCount(1); + MARK_CHANGE(); + } + return(nl); +} // newline_force_before + + +Chunk *newline_add_after(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + if (pc == nullptr) + { + return(Chunk::NullChunkPtr); + } + Chunk *next = pc->GetNextNvb(); + + if (next->IsNewline()) + { + // Already has a newline after this chunk + return(next); + } + LOG_FMT(LNEWLINE, "%s(%d): '%s' on line %zu", + __func__, __LINE__, pc->Text(), pc->GetOrigLine()); + log_func_stack_inline(LNEWLINE); + + Chunk nl; + + nl.SetOrigLine(pc->GetOrigLine()); + nl.SetOrigCol(pc->GetOrigCol()); + setup_newline_add(pc, &nl, next); + + MARK_CHANGE(); + // TO DO: check why the next statement is necessary + nl.SetOrigCol(pc->GetOrigCol()); + nl.SetPpLevel(pc->GetPpLevel()); + return(nl.CopyAndAddAfter(pc)); +} // newline_add_after + + +Chunk *newline_force_after(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + Chunk *nl = newline_add_after(pc); // add a newline + + if ( nl->IsNotNullChunk() + && nl->GetNlCount() > 1) // check if there are more than 1 newline + { + nl->SetNlCount(1); // if so change the newline count back to 1 + MARK_CHANGE(); + } + return(nl); +} // newline_force_after + + +static void newline_end_newline(Chunk *br_close) +{ + LOG_FUNC_ENTRY(); + + Chunk *next = br_close->GetNext(); + Chunk nl; + + if (!next->IsCommentOrNewline()) + { + nl.SetOrigLine(br_close->GetOrigLine()); + nl.SetOrigCol(br_close->GetOrigCol()); + nl.SetNlCount(1); + nl.SetPpLevel(0); + nl.SetFlags((br_close->GetFlags() & PCF_COPY_FLAGS) & ~PCF_IN_PREPROC); + + if ( br_close->TestFlags(PCF_IN_PREPROC) + && next->IsNotNullChunk() + && next->TestFlags(PCF_IN_PREPROC)) + { + nl.SetFlagBits(PCF_IN_PREPROC); + } + + if (nl.TestFlags(PCF_IN_PREPROC)) + { + nl.SetType(CT_NL_CONT); + nl.Str() = "\\\n"; + } + else + { + nl.SetType(CT_NEWLINE); + nl.Str() = "\n"; + } + MARK_CHANGE(); + LOG_FMT(LNEWLINE, "%s(%d): %zu:%zu add newline after '%s'\n", + __func__, __LINE__, br_close->GetOrigLine(), br_close->GetOrigCol(), br_close->Text()); + nl.CopyAndAddAfter(br_close); + } +} // newline_end_newline + + +static void newline_min_after(Chunk *ref, size_t count, E_PcfFlag flag) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LNEWLINE, "%s(%d): for '%s', at orig line %zu, count is %zu,\n flag is %s:", + __func__, __LINE__, ref->Text(), ref->GetOrigLine(), count, + pcf_flags_str(flag).c_str()); + log_func_stack_inline(LNEWLINE); + + Chunk *pc = ref; + + do + { + pc = pc->GetNext(); + } while ( pc->IsNotNullChunk() + && !pc->IsNewline()); + + if (pc->IsNotNullChunk()) // Coverity CID 76002 + { + LOG_FMT(LNEWLINE, "%s(%d): type is %s, orig line %zu, orig col %zu\n", + __func__, __LINE__, get_token_name(pc->GetType()), pc->GetOrigLine(), pc->GetOrigCol()); + } + Chunk *next = pc->GetNext(); + + if (next->IsNullChunk()) + { + return; + } + + if ( next->IsComment() + && next->GetNlCount() == 1 + && pc->GetPrev()->IsComment()) + { + newline_min_after(next, count, flag); + return; + } + pc->SetFlagBits(flag); + + if ( pc->IsNewline() + && can_increase_nl(pc)) + { + if (pc->GetNlCount() < count) + { + pc->SetNlCount(count); + MARK_CHANGE(); + } + } +} // newline_min_after + + +Chunk *newline_add_between(Chunk *start, Chunk *end) +{ + LOG_FUNC_ENTRY(); + + if ( start == nullptr + || end == nullptr + || end->Is(CT_IGNORED)) + { + return(nullptr); + } + LOG_FMT(LNEWLINE, "%s(%d): start->Text() is '%s', type is %s, orig line is %zu, orig col is %zu\n", + __func__, __LINE__, start->Text(), get_token_name(start->GetType()), + start->GetOrigLine(), start->GetOrigCol()); + LOG_FMT(LNEWLINE, "%s(%d): and end->Text() is '%s', orig line is %zu, orig col is %zu\n ", + __func__, __LINE__, end->Text(), end->GetOrigLine(), end->GetOrigCol()); + log_func_stack_inline(LNEWLINE); + + // Back-up check for one-liners (should never be true!) + if (!one_liner_nl_ok(start)) + { + return(nullptr); + } + + /* + * Scan for a line break, if there is a line break between start and end + * we won't add another one + */ + for (Chunk *pc = start; pc != end; pc = pc->GetNext()) + { + if (pc->IsNewline()) + { + return(pc); + } + } + + /* + * If the second one is a brace open, then check to see + * if a comment + newline follows + */ + if (end->Is(CT_BRACE_OPEN)) + { + Chunk *pc = end->GetNext(); + + if (pc->IsComment()) + { + pc = pc->GetNext(); + + if (pc->IsNewline()) + { + // are there some more (comment + newline)s ? + Chunk *pc1 = end->GetNextNcNnl(); + + if (!pc1->IsNewline()) + { + // yes, go back + Chunk *pc2 = pc1->GetPrev(); + pc = pc2; + } + + if (end == pc) + { + LOG_FMT(LNEWLINE, "%s(%d): pc1 and pc are identical\n", + __func__, __LINE__); + } + else + { + // Move the open brace to after the newline + end->MoveAfter(pc); + } + LOG_FMT(LNEWLINE, "%s(%d):\n", __func__, __LINE__); + newline_add_after(end); + return(pc); + } + else // Issue #3873 + { + LOG_FMT(LNEWLINE, "%s(%d):\n", __func__, __LINE__); + } + } + else + { + LOG_FMT(LNEWLINE, "%s(%d):\n", __func__, __LINE__); + } + } + else + { + LOG_FMT(LNEWLINE, "%s(%d):\n", __func__, __LINE__); + } + Chunk *tmp = newline_add_before(end); + + return(tmp); +} // newline_add_between + + +void newline_del_between(Chunk *start, Chunk *end) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LNEWLINE, "%s(%d): start->Text() is '%s', orig line is %zu, orig col is %zu\n", + __func__, __LINE__, start->Text(), start->GetOrigLine(), start->GetOrigCol()); + LOG_FMT(LNEWLINE, "%s(%d): and end->Text() is '%s', orig line is %zu, orig col is %zu: preproc=%c/%c\n", + __func__, __LINE__, end->Text(), end->GetOrigLine(), end->GetOrigCol(), + start->TestFlags(PCF_IN_PREPROC) ? 'y' : 'n', + end->TestFlags(PCF_IN_PREPROC) ? 'y' : 'n'); + log_func_stack_inline(LNEWLINE); + + // Can't remove anything if the preproc status differs + if (!start->IsSamePreproc(end)) + { + return; + } + Chunk *pc = start; + bool start_removed = false; + + do + { + Chunk *next = pc->GetNext(); + + if (pc->IsNewline()) + { + Chunk *prev = pc->GetPrev(); + + if ( ( !prev->IsComment() + && !next->IsComment()) + || prev->IsNewline() + || next->IsNewline()) + { + if (pc->SafeToDeleteNl()) + { + if (pc == start) + { + start_removed = true; + } + Chunk::Delete(pc); + MARK_CHANGE(); + + if (prev->IsNotNullChunk()) + { + align_to_column(next, prev->GetColumn() + space_col_align(prev, next)); + } + } + } + else + { + if (pc->GetNlCount() > 1) + { + pc->SetNlCount(1); + MARK_CHANGE(); + } + } + } + pc = next; + } while (pc != end); + + if ( !start_removed + && end->IsString("{") + && ( start->IsString(")") + || start->Is(CT_DO) + || start->Is(CT_ELSE))) + { + end->MoveAfter(start); + } +} // newline_del_between + + +void newlines_sparens() +{ + LOG_FUNC_ENTRY(); + + //Chunk *sparen_open; + + for (Chunk *sparen_open = Chunk::GetHead()->GetNextType(CT_SPAREN_OPEN, ANY_LEVEL); + sparen_open->IsNotNullChunk(); + sparen_open = sparen_open->GetNextType(CT_SPAREN_OPEN, ANY_LEVEL)) + { + Chunk *sparen_close = sparen_open->GetNextType(CT_SPAREN_CLOSE, sparen_open->GetLevel()); + + if (sparen_close->IsNullChunk()) + { + continue; + } + Chunk *sparen_content_start = sparen_open->GetNextNnl(); + Chunk *sparen_content_end = sparen_close->GetPrevNnl(); + bool is_multiline = ( + sparen_content_start != sparen_content_end + && !sparen_content_start->IsOnSameLine(sparen_content_end)); + + // Add a newline after '(' if an if/for/while/switch condition spans multiple lines, + // as e.g. required by the ROS 2 development style guidelines: + // https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#open-versus-cuddled-braces + if (is_multiline) + { + log_rule_B("nl_multi_line_sparen_open"); + newline_iarf(sparen_open, options::nl_multi_line_sparen_open()); + } + + // Add a newline before ')' if an if/for/while/switch condition spans multiple lines. Overrides nl_before_if_closing_paren if both are specified. + if ( is_multiline + && options::nl_multi_line_sparen_close() != IARF_IGNORE) + { + log_rule_B("nl_multi_line_sparen_close"); + newline_iarf(sparen_content_end, options::nl_multi_line_sparen_close()); + } + else + { + // add/remove trailing newline in an if condition + Chunk *ctrl_structure = sparen_open->GetPrevNcNnl(); + + if ( ctrl_structure->Is(CT_IF) + || ctrl_structure->Is(CT_ELSEIF)) + { + log_rule_B("nl_before_if_closing_paren"); + newline_iarf_pair(sparen_content_end, sparen_close, options::nl_before_if_closing_paren()); + } + } + } +} // newlines_sparens + + +static bool newlines_if_for_while_switch(Chunk *start, iarf_e nl_opt) +{ + LOG_FUNC_ENTRY(); + + log_rule_B("nl_define_macro"); + + if ( nl_opt == IARF_IGNORE + || ( start->TestFlags(PCF_IN_PREPROC) + && !options::nl_define_macro())) + { + return(false); + } + bool retval = false; + Chunk *pc = start->GetNextNcNnl(); + + if (pc->Is(CT_SPAREN_OPEN)) + { + Chunk *close_paren = pc->GetNextType(CT_SPAREN_CLOSE, pc->GetLevel()); + Chunk *brace_open = close_paren->GetNextNcNnl(); + + if ( ( brace_open->Is(CT_BRACE_OPEN) + || brace_open->Is(CT_VBRACE_OPEN)) + && one_liner_nl_ok(brace_open)) + { + log_rule_B("nl_multi_line_cond"); + + if (options::nl_multi_line_cond()) + { + while ((pc = pc->GetNext()) != close_paren) + { + if (pc->IsNewline()) + { + nl_opt = IARF_ADD; + break; + } + } + } + + if (brace_open->Is(CT_VBRACE_OPEN)) + { + // Can only add - we don't want to create a one-line here + if (nl_opt & IARF_ADD) + { + newline_iarf_pair(close_paren, brace_open->GetNextNcNnl(), nl_opt); + pc = brace_open->GetNextType(CT_VBRACE_CLOSE, brace_open->GetLevel()); + + if ( !pc->GetPrevNc()->IsNewline() + && !pc->GetNextNc()->IsNewline()) + { + newline_add_after(pc); + retval = true; + } + } + } + else + { + newline_iarf_pair(close_paren, brace_open, nl_opt); + Chunk *next = brace_open->GetNextNcNnl(); + + if (brace_open->GetType() != next->GetType()) // Issue #2836 + { + newline_add_between(brace_open, brace_open->GetNextNcNnl()); + } + // Make sure nothing is cuddled with the closing brace + pc = brace_open->GetNextType(CT_BRACE_CLOSE, brace_open->GetLevel()); + newline_add_between(pc, pc->GetNextNcNnlNet()); + retval = true; + } + } + } + return(retval); +} // newlines_if_for_while_switch + + +static void newlines_if_for_while_switch_pre_blank_lines(Chunk *start, iarf_e nl_opt) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LNEWLINE, "%s(%d): start->Text() is '%s', type is %s, orig line is %zu, orig col is %zu\n", + __func__, __LINE__, start->Text(), get_token_name(start->GetType()), start->GetOrigLine(), start->GetOrigCol()); + + log_rule_B("nl_define_macro"); + + if ( nl_opt == IARF_IGNORE + || ( start->TestFlags(PCF_IN_PREPROC) + && !options::nl_define_macro())) + { + return; + } + + /* + * look backwards until we find + * open brace (don't add or remove) + * 2 newlines in a row (don't add) + * something else (don't remove) + */ + for (Chunk *pc = start->GetPrev(); pc->IsNotNullChunk(); pc = pc->GetPrev()) + { + size_t level = start->GetLevel(); + bool do_add = (nl_opt & IARF_ADD) != IARF_IGNORE; // forcing value to bool + Chunk *last_nl = nullptr; + + if (pc->IsNewline()) + { + last_nl = pc; + + // if we found 2 or more in a row + if ( pc->GetNlCount() > 1 + || pc->GetPrevNvb()->IsNewline()) + { + // need to remove + if ( (nl_opt & IARF_REMOVE) + && !pc->TestFlags(PCF_VAR_DEF)) + { + // if we're also adding, take care of that here + size_t nl_count = do_add ? 2 : 1; + + if (nl_count != pc->GetNlCount()) + { + pc->SetNlCount(nl_count); + MARK_CHANGE(); + } + Chunk *prev; + + // can keep using pc because anything other than newline stops loop, and we delete if newline + while ((prev = pc->GetPrevNvb())->IsNewline()) + { + // Make sure we don't combine a preproc and non-preproc + if (!prev->SafeToDeleteNl()) + { + break; + } + Chunk::Delete(prev); + MARK_CHANGE(); + } + } + return; + } + } + else if ( pc->IsBraceOpen() + || pc->GetLevel() < level) + { + return; + } + else if (pc->IsComment()) + { + // vbrace close is ok because it won't go into output, so we should skip it + last_nl = nullptr; + continue; + } + else + { + if ( pc->Is(CT_CASE_COLON) + && options::nl_before_ignore_after_case()) + { + return; + } + + if (do_add) // we found something previously besides a comment or a new line + { + // if we have run across a newline + if ( last_nl != nullptr + && last_nl->IsNotNullChunk()) + { + if (last_nl->GetNlCount() < 2) + { + double_newline(last_nl); + } + } + else + { + Chunk *next; + + // we didn't run into a newline, so we need to add one + if ( ((next = pc->GetNext())->IsNotNullChunk()) + && next->IsComment()) + { + pc = next; + } + + if ((last_nl = newline_add_after(pc))->IsNotNullChunk()) + { + double_newline(last_nl); + } + } + } + return; + } + } +} // newlines_if_for_while_switch_pre_blank_lines + + +static void blank_line_set(Chunk *pc, Option<unsigned> &opt) +{ + LOG_FUNC_ENTRY(); + + if (pc == nullptr) + { + return; + } + const unsigned optval = opt(); + + if ( (optval > 0) + && (pc->GetNlCount() != optval)) + { + LOG_FMT(LBLANKD, "%s(%d): do_blank_lines: %s set line %zu to %u\n", + __func__, __LINE__, opt.name(), pc->GetOrigLine(), optval); + pc->SetNlCount(optval); + MARK_CHANGE(); + } +} // blank_line_set + + +bool do_it_newlines_func_pre_blank_lines(Chunk *last_nl, E_Token start_type) +{ + LOG_FUNC_ENTRY(); + + if (last_nl == nullptr) + { + return(false); + } + LOG_FMT(LNLFUNCT, "%s(%d): orig line is %zu, orig col is %zu, type is %s, Text() is '%s'\n", + __func__, __LINE__, + last_nl->GetOrigLine(), last_nl->GetOrigCol(), get_token_name(last_nl->GetType()), last_nl->Text()); + + switch (start_type) + { + case CT_FUNC_CLASS_DEF: + { + log_rule_B("nl_before_func_class_def"); + bool diff = options::nl_before_func_class_def() <= last_nl->GetNlCount(); + LOG_FMT(LNLFUNCT, "%s(%d): is %s\n", + __func__, __LINE__, diff ? "TRUE" : "FALSE"); + + log_rule_B("nl_before_func_class_def"); + + if (options::nl_before_func_class_def() != last_nl->GetNlCount()) + { + LOG_FMT(LNLFUNCT, "%s(%d): set blank line(s) to %u\n", + __func__, __LINE__, options::nl_before_func_class_def()); + blank_line_set(last_nl, options::nl_before_func_class_def); + } + return(diff); + } + + case CT_FUNC_CLASS_PROTO: + { + log_rule_B("nl_before_func_class_proto"); + bool diff = options::nl_before_func_class_proto() <= last_nl->GetNlCount(); + LOG_FMT(LNLFUNCT, "%s(%d): is %s\n", + __func__, __LINE__, diff ? "TRUE" : "FALSE"); + + log_rule_B("nl_before_func_class_proto"); + + if (options::nl_before_func_class_proto() != last_nl->GetNlCount()) + { + LOG_FMT(LNLFUNCT, "%s(%d): set blank line(s) to %u\n", + __func__, __LINE__, options::nl_before_func_class_proto()); + blank_line_set(last_nl, options::nl_before_func_class_proto); + } + return(diff); + } + + case CT_FUNC_DEF: + { + LOG_FMT(LNLFUNCT, "%s(%d): nl_before_func_body_def() is %u, last_nl new line count is %zu\n", + __func__, __LINE__, options::nl_before_func_body_def(), last_nl->GetNlCount()); + log_rule_B("nl_before_func_body_def"); + bool diff = options::nl_before_func_body_def() <= last_nl->GetNlCount(); + LOG_FMT(LNLFUNCT, "%s(%d): is %s\n", + __func__, __LINE__, diff ? "TRUE" : "FALSE"); + + log_rule_B("nl_before_func_body_def"); + + if (options::nl_before_func_body_def() != last_nl->GetNlCount()) + { + LOG_FMT(LNLFUNCT, "%s(%d): set blank line(s) to %u\n", + __func__, __LINE__, options::nl_before_func_body_def()); + log_rule_B("nl_before_func_body_def"); + blank_line_set(last_nl, options::nl_before_func_body_def); + } + LOG_FMT(LNLFUNCT, "%s(%d): nl_before_func_body_def() is %u, last_nl new line count is %zu\n", + __func__, __LINE__, options::nl_before_func_body_def(), last_nl->GetNlCount()); + return(diff); + } + + case CT_FUNC_PROTO: + { + log_rule_B("nl_before_func_body_proto"); + bool diff = options::nl_before_func_body_proto() <= last_nl->GetNlCount(); + LOG_FMT(LNLFUNCT, "%s(%d): is %s\n", + __func__, __LINE__, diff ? "TRUE" : "FALSE"); + + log_rule_B("nl_before_func_body_proto"); + + if (options::nl_before_func_body_proto() != last_nl->GetNlCount()) + { + LOG_FMT(LNLFUNCT, "%s(%d): set blank line(s) to %u\n", + __func__, __LINE__, options::nl_before_func_body_proto()); + log_rule_B("nl_before_func_body_proto"); + blank_line_set(last_nl, options::nl_before_func_body_proto); + } + return(diff); + } + + default: + { + LOG_FMT(LERR, "%s(%d): setting to blank line(s) at line %zu not possible\n", + __func__, __LINE__, last_nl->GetOrigLine()); + return(false); + } + } // switch +} // do_it_newlines_func_pre_blank_lines + + +static void newlines_func_pre_blank_lines(Chunk *start, E_Token start_type) +{ + LOG_FUNC_ENTRY(); + + log_rule_B("nl_before_func_class_def"); + log_rule_B("nl_before_func_class_proto"); + log_rule_B("nl_before_func_body_def"); + log_rule_B("nl_before_func_body_proto"); + + if ( start == nullptr + || ( ( start_type != CT_FUNC_CLASS_DEF + || options::nl_before_func_class_def() == 0) + && ( start_type != CT_FUNC_CLASS_PROTO + || options::nl_before_func_class_proto() == 0) + && ( start_type != CT_FUNC_DEF + || options::nl_before_func_body_def() == 0) + && ( start_type != CT_FUNC_PROTO + || options::nl_before_func_body_proto() == 0))) + { + return; + } + LOG_FMT(LNLFUNCT, "%s(%d): set blank line(s): for <NL> at line %zu, column %zu, start_type is %s\n", + __func__, __LINE__, start->GetOrigLine(), start->GetOrigCol(), get_token_name(start_type)); + LOG_FMT(LNLFUNCT, "%s(%d): BEGIN set blank line(s) for '%s' at line %zu\n", + __func__, __LINE__, start->Text(), start->GetOrigLine()); + /* + * look backwards until we find: + * - open brace (don't add or remove) + * - two newlines in a row (don't add) + * - a destructor + * - something else (don't remove) + */ + Chunk *pc = nullptr; + Chunk *last_nl = nullptr; + Chunk *last_comment = nullptr; + size_t first_line = start->GetOrigLine(); + + for (pc = start->GetPrev(); pc->IsNotNullChunk(); pc = pc->GetPrev()) + { + LOG_FMT(LNLFUNCT, "%s(%d): orig line is %zu, orig col is %zu, type is %s, Text() is '%s', new line count is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType()), pc->Text(), pc->GetNlCount()); + + if (pc->IsNewline()) + { + last_nl = pc; + LOG_FMT(LNLFUNCT, "%s(%d): <Chunk::IsNewline> found at line %zu, column %zu, new line count is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->GetNlCount()); + LOG_FMT(LNLFUNCT, "%s(%d): last_nl set to %zu\n", + __func__, __LINE__, last_nl->GetOrigLine()); + bool break_now = false; + + if (pc->GetNlCount() > 1) + { + break_now = do_it_newlines_func_pre_blank_lines(last_nl, start_type); + LOG_FMT(LNLFUNCT, "%s(%d): break_now is %s\n", + __func__, __LINE__, break_now ? "TRUE" : "FALSE"); + } + + if (break_now) + { + break; + } + else + { + continue; + } + } + else if (pc->IsComment()) + { + LOG_FMT(LNLFUNCT, "%s(%d): <Chunk::IsComment> found at line %zu, column %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + + if ( ( pc->GetOrigLine() < first_line + && ((first_line - pc->GetOrigLine() + - (pc->Is(CT_COMMENT_MULTI) ? pc->GetNlCount() : 0))) < 2) + || ( last_comment != nullptr + && pc->Is(CT_COMMENT_CPP) // combine only cpp comments + && last_comment->Is(pc->GetType()) // don't mix comment types + && last_comment->GetOrigLine() > pc->GetOrigLine() + && (last_comment->GetOrigLine() - pc->GetOrigLine()) < 2)) + { + last_comment = pc; + continue; + } + bool break_now = do_it_newlines_func_pre_blank_lines(last_nl, start_type); + LOG_FMT(LNLFUNCT, "%s(%d): break_now is %s\n", + __func__, __LINE__, break_now ? "TRUE" : "FALSE"); + continue; + } + else if ( pc->Is(CT_DESTRUCTOR) + || pc->Is(CT_TYPE) + || pc->Is(CT_TEMPLATE) + || pc->Is(CT_QUALIFIER) + || pc->Is(CT_PTR_TYPE) + || pc->Is(CT_BYREF) // Issue #2163 + || pc->Is(CT_DC_MEMBER) + || pc->Is(CT_EXTERN) + || ( pc->Is(CT_STRING) + && pc->GetParentType() == CT_EXTERN)) + { + LOG_FMT(LNLFUNCT, "%s(%d): first_line set to %zu\n", + __func__, __LINE__, pc->GetOrigLine()); + first_line = pc->GetOrigLine(); + continue; + } + else if ( pc->Is(CT_ANGLE_CLOSE) + && pc->GetParentType() == CT_TEMPLATE) + { + LOG_FMT(LNLFUNCT, "%s(%d):\n", __func__, __LINE__); + // skip template stuff to add newlines before it + pc = pc->GetOpeningParen(); + + if (pc->IsNotNullChunk()) + { + first_line = pc->GetOrigLine(); + } + continue; + } + else + { + LOG_FMT(LNLFUNCT, "%s(%d): else ==================================\n", + __func__, __LINE__); + bool break_now = do_it_newlines_func_pre_blank_lines(last_nl, start_type); + LOG_FMT(LNLFUNCT, "%s(%d): break_now is %s\n", + __func__, __LINE__, break_now ? "TRUE" : "FALSE"); + break; + } + } +} // newlines_func_pre_blank_lines + + +static Chunk *get_closing_brace(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + Chunk *pc; + size_t level = start->GetLevel(); + + for (pc = start; (pc = pc->GetNext())->IsNotNullChunk();) + { + if ( (pc->IsBraceClose()) + && pc->GetLevel() == level) + { + return(pc); + } + + // for some reason, we can have newlines between if and opening brace that are lower level than either + if ( !pc->IsNewline() + && pc->GetLevel() < level) + { + return(nullptr); + } + } + + return(nullptr); +} // get_closing_brace + + +static void remove_next_newlines(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + Chunk *next; + + while ((next = start->GetNext())->IsNotNullChunk()) + { + if ( next->IsNewline() + && next->SafeToDeleteNl()) + { + Chunk::Delete(next); + MARK_CHANGE(); + } + else if (next->IsVBrace()) + { + start = next; + } + else + { + break; + } + } +} // remove_next_newlines + + +static void newlines_if_for_while_switch_post_blank_lines(Chunk *start, iarf_e nl_opt) +{ + LOG_FUNC_ENTRY(); + + Chunk *prev; + + LOG_FMT(LNEWLINE, "%s(%d): start->Text() is '%s', type is %s, orig line is %zu, orig col is %zu\n", + __func__, __LINE__, start->Text(), get_token_name(start->GetType()), start->GetOrigLine(), start->GetOrigCol()); + + log_rule_B("nl_define_macro"); + + if ( nl_opt == IARF_IGNORE + || ( start->TestFlags(PCF_IN_PREPROC) + && !options::nl_define_macro())) + { + return; + } + Chunk *pc = get_closing_brace(start); + + // first find ending brace + if (pc == nullptr) + { + return; + } + LOG_FMT(LNEWLINE, "%s(%d): pc->Text() is '%s', type is %s, orig line is %zu, orig col is %zu\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType()), pc->GetOrigLine(), pc->GetOrigCol()); + + /* + * if we're dealing with an if, we actually want to add or remove + * blank lines after any else + */ + if (start->Is(CT_IF)) + { + Chunk *next; + + while (true) + { + next = pc->GetNextNcNnl(); + + if ( next->IsNotNullChunk() + && ( next->Is(CT_ELSE) + || next->Is(CT_ELSEIF))) + { + // point to the closing brace of the else + if ((pc = get_closing_brace(next)) == nullptr) + { + return; + } + LOG_FMT(LNEWLINE, "%s(%d): pc->Text() is '%s', type %s, orig line %zu, orig col %zu\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType()), pc->GetOrigLine(), pc->GetOrigCol()); + } + else + { + break; + } + } + } + + /* + * if we're dealing with a do/while, we actually want to add or + * remove blank lines after while and its condition + */ + if (start->Is(CT_DO)) + { + // point to the next semicolon + if ((pc = pc->GetNextType(CT_SEMICOLON, start->GetLevel()))->IsNullChunk()) + { + return; + } + LOG_FMT(LNEWLINE, "%s(%d): pc->Text() is '%s', type %s, orig line %zu, orig col %zu\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType()), pc->GetOrigLine(), pc->GetOrigCol()); + } + bool isVBrace = (pc->Is(CT_VBRACE_CLOSE)); + + if (isVBrace) + { + LOG_FMT(LNEWLINE, "%s(%d): isVBrace is TRUE\n", __func__, __LINE__); + } + else + { + LOG_FMT(LNEWLINE, "%s(%d): isVBrace is FALSE\n", __func__, __LINE__); + } + + if ((prev = pc->GetPrevNvb())->IsNullChunk()) + { + return; + } + bool have_pre_vbrace_nl = isVBrace && prev->IsNewline(); + + if (have_pre_vbrace_nl) + { + LOG_FMT(LNEWLINE, "%s(%d): have_pre_vbrace_nl is TRUE\n", __func__, __LINE__); + } + else + { + LOG_FMT(LNEWLINE, "%s(%d): have_pre_vbrace_nl is FALSE\n", __func__, __LINE__); + } + + if (nl_opt & IARF_REMOVE) + { + Chunk *next; + + // if chunk before is a vbrace, remove any newlines after it + if (have_pre_vbrace_nl) + { + if (prev->GetNlCount() != 1) + { + prev->SetNlCount(1); + MARK_CHANGE(); + } + remove_next_newlines(pc); + } + else if ( ((next = pc->GetNextNvb())->IsNewline()) + && !next->TestFlags(PCF_VAR_DEF)) + { + // otherwise just deal with newlines after brace + if (next->GetNlCount() != 1) + { + next->SetNlCount(1); + MARK_CHANGE(); + } + remove_next_newlines(next); + } + } + + // may have a newline before and after vbrace + // don't do anything with it if the next non newline chunk is a closing brace + if (nl_opt & IARF_ADD) + { + Chunk *next = pc->GetNextNnl(); + + do + { + if (next->IsNullChunk()) + { + return; + } + + if (next->IsNot(CT_VBRACE_CLOSE)) + { + break; + } + next = next->GetNextNnl(); + } while (true); + + LOG_FMT(LNEWLINE, "%s(%d): next->Text() is '%s', type %s, orig line %zu, orig col %zu\n", + __func__, __LINE__, next->Text(), get_token_name(next->GetType()), next->GetOrigLine(), next->GetOrigCol()); + + if (next->IsNot(CT_BRACE_CLOSE)) + { + // if vbrace, have to check before and after + // if chunk before vbrace, check its count + size_t nl_count = have_pre_vbrace_nl ? prev->GetNlCount() : 0; + LOG_FMT(LNEWLINE, "%s(%d): new line count %zu\n", __func__, __LINE__, nl_count); + + if ((next = pc->GetNextNvb())->IsNewline()) + { + LOG_FMT(LNEWLINE, "%s(%d): next->Text() is '%s', type %s, orig line %zu, orig col %zu\n", + __func__, __LINE__, next->Text(), get_token_name(next->GetType()), next->GetOrigLine(), next->GetOrigCol()); + nl_count += next->GetNlCount(); + LOG_FMT(LNEWLINE, "%s(%d): new line count is %zu\n", __func__, __LINE__, nl_count); + } + + // if we have no newlines, add one and make it double + if (nl_count == 0) + { + LOG_FMT(LNEWLINE, "%s(%d): new line count is 0\n", __func__, __LINE__); + + if ( ((next = pc->GetNext())->IsNotNullChunk()) + && next->IsComment()) + { + LOG_FMT(LNEWLINE, "%s(%d): next->Text() is '%s', type %s, orig line %zu, orig col %zu\n", + __func__, __LINE__, next->Text(), get_token_name(next->GetType()), next->GetOrigLine(), next->GetOrigCol()); + pc = next; + LOG_FMT(LNEWLINE, "%s(%d): pc->Text() is '%s', type %s, orig line %zu, orig col %zu\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType()), pc->GetOrigLine(), pc->GetOrigCol()); + } + + if ((next = newline_add_after(pc))->IsNullChunk()) + { + return; + } + LOG_FMT(LNEWLINE, "%s(%d): next->Text() is '%s', type %s, orig line %zu, orig col %zu\n", + __func__, __LINE__, next->Text(), get_token_name(next->GetType()), next->GetOrigLine(), next->GetOrigCol()); + double_newline(next); + } + else if (nl_count == 1) // if we don't have enough newlines + { + LOG_FMT(LNEWLINE, "%s(%d): new line count is 1\n", __func__, __LINE__); + + // if we have a preceding vbrace, add one after it + if (have_pre_vbrace_nl) + { + LOG_FMT(LNEWLINE, "%s(%d): have_pre_vbrace_nl is TRUE\n", __func__, __LINE__); + next = newline_add_after(pc); + LOG_FMT(LNEWLINE, "%s(%d): next->Text() is '%s', type %s, orig line %zu, orig col %zu\n", + __func__, __LINE__, next->Text(), get_token_name(next->GetType()), next->GetOrigLine(), next->GetOrigCol()); + } + else + { + LOG_FMT(LNEWLINE, "%s(%d): have_pre_vbrace_nl is FALSE\n", __func__, __LINE__); + prev = next->GetPrevNnl(); + LOG_FMT(LNEWLINE, "%s(%d): prev->Text() is '%s', type %s, orig line %zu, orig col %zu\n", + __func__, __LINE__, prev->Text(), get_token_name(prev->GetType()), prev->GetOrigLine(), prev->GetOrigCol()); + pc = next->GetNextNl(); + LOG_FMT(LNEWLINE, "%s(%d): pc->Text() is '%s', type %s, orig line %zu, orig col %zu\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType()), pc->GetOrigLine(), pc->GetOrigCol()); + Chunk *pc2 = pc->GetNext(); + + if (pc2->IsNotNullChunk()) + { + pc = pc2; + LOG_FMT(LNEWLINE, "%s(%d): pc->Text() is '%s', type %s, orig line %zu, orig col %zu\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType()), pc->GetOrigLine(), pc->GetOrigCol()); + } + else + { + LOG_FMT(LNEWLINE, "%s(%d): no next found: <EOF>\n", __func__, __LINE__); + } + log_rule_B("nl_squeeze_ifdef"); + + if ( pc->Is(CT_PREPROC) + && pc->GetParentType() == CT_PP_ENDIF + && options::nl_squeeze_ifdef()) + { + LOG_FMT(LNEWLINE, "%s(%d): cannot add newline after orig line %zu due to nl_squeeze_ifdef\n", + __func__, __LINE__, prev->GetOrigLine()); + } + else + { + // make newline after double + LOG_FMT(LNEWLINE, "%s(%d): call double_newline\n", __func__, __LINE__); + double_newline(next); + } + } + } + } + } +} // newlines_if_for_while_switch_post_blank_lines + + +static void newlines_struct_union(Chunk *start, iarf_e nl_opt, bool leave_trailing) +{ + LOG_FUNC_ENTRY(); + + log_rule_B("nl_define_macro"); + + if ( nl_opt == IARF_IGNORE + || ( start->TestFlags(PCF_IN_PREPROC) + && !options::nl_define_macro())) + { + return; + } + /* + * step past any junk between the keyword and the open brace + * Quit if we hit a semicolon or '=', which are not expected. + */ + size_t level = start->GetLevel(); + Chunk *pc = start->GetNextNcNnl(); + + while ( pc->IsNotNullChunk() + && pc->GetLevel() >= level) + { + if ( pc->GetLevel() == level + && ( pc->Is(CT_BRACE_OPEN) + || pc->IsSemicolon() + || pc->Is(CT_ASSIGN))) + { + break; + } + start = pc; + pc = pc->GetNextNcNnl(); + } + + // If we hit a brace open, then we need to toy with the newlines + if (pc->Is(CT_BRACE_OPEN)) + { + // Skip over embedded C comments + Chunk *next = pc->GetNext(); + + while (next->Is(CT_COMMENT)) + { + next = next->GetNext(); + } + + if ( leave_trailing + && !next->IsCommentOrNewline()) + { + nl_opt = IARF_IGNORE; + } + newline_iarf_pair(start, pc, nl_opt); + } +} // newlines_struct_union + + +// enum { +// enum class angle_state_e : unsigned int { +// enum-key attr(optional) identifier(optional) enum-base(optional) { enumerator-list(optional) } +// enum-key attr(optional) nested-name-specifier(optional) identifier enum-base(optional) ; TODO +// enum-key - one of enum, enum class or enum struct TODO +// identifier - the name of the enumeration that's being declared +// enum-base(C++11) - colon (:), followed by a type-specifier-seq +// enumerator-list - comma-separated list of enumerator definitions +static void newlines_enum(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + log_rule_B("nl_define_macro"); + + if ( start->TestFlags(PCF_IN_PREPROC) + && !options::nl_define_macro()) + { + return; + } + // look for 'enum class' + Chunk *pcClass = start->GetNextNcNnl(); + + if (pcClass->Is(CT_ENUM_CLASS)) + { + log_rule_B("nl_enum_class"); + newline_iarf_pair(start, pcClass, options::nl_enum_class()); + // look for 'identifier'/ 'type' + Chunk *pcType = pcClass->GetNextNcNnl(); + + if (pcType->Is(CT_TYPE)) + { + log_rule_B("nl_enum_class_identifier"); + newline_iarf_pair(pcClass, pcType, options::nl_enum_class_identifier()); + // look for ':' + Chunk *pcColon = pcType->GetNextNcNnl(); + + if (pcColon->Is(CT_BIT_COLON)) + { + log_rule_B("nl_enum_identifier_colon"); + newline_iarf_pair(pcType, pcColon, options::nl_enum_identifier_colon()); + // look for 'type' i.e. unsigned + Chunk *pcType1 = pcColon->GetNextNcNnl(); + + if (pcType1->Is(CT_TYPE)) + { + log_rule_B("nl_enum_colon_type"); + newline_iarf_pair(pcColon, pcType1, options::nl_enum_colon_type()); + // look for 'type' i.e. int + Chunk *pcType2 = pcType1->GetNextNcNnl(); + + if (pcType2->Is(CT_TYPE)) + { + log_rule_B("nl_enum_colon_type"); + newline_iarf_pair(pcType1, pcType2, options::nl_enum_colon_type()); + } + } + } + } + } + /* + * step past any junk between the keyword and the open brace + * Quit if we hit a semicolon or '=', which are not expected. + */ + size_t level = start->GetLevel(); + Chunk *pc = start->GetNextNcNnl(); + + while ( pc->IsNotNullChunk() + && pc->GetLevel() >= level) + { + if ( pc->GetLevel() == level + && ( pc->Is(CT_BRACE_OPEN) + || pc->IsSemicolon() + || pc->Is(CT_ASSIGN))) + { + break; + } + start = pc; + pc = pc->GetNextNcNnl(); + } + + // If we hit a brace open, then we need to toy with the newlines + if (pc->Is(CT_BRACE_OPEN)) + { + // Skip over embedded C comments + Chunk *next = pc->GetNext(); + + while (next->Is(CT_COMMENT)) + { + next = next->GetNext(); + } + iarf_e nl_opt; + + if (!next->IsCommentOrNewline()) + { + nl_opt = IARF_IGNORE; + } + else + { + log_rule_B("nl_enum_brace"); + nl_opt = options::nl_enum_brace(); + } + newline_iarf_pair(start, pc, nl_opt); + } +} // newlines_enum + + +// namespace { +// namespace word { +// namespace type::word { +static void newlines_namespace(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + log_rule_B("nl_namespace_brace"); + + // Add or remove newline between 'namespace' and 'BRACE_OPEN' + log_rule_B("nl_define_macro"); + iarf_e nl_opt = options::nl_namespace_brace(); + + if ( nl_opt == IARF_IGNORE + || ( start->TestFlags(PCF_IN_PREPROC) + && !options::nl_define_macro())) + { + return; + } + Chunk *braceOpen = start->GetNextType(CT_BRACE_OPEN, start->GetLevel()); + + LOG_FMT(LNEWLINE, "%s(%d): braceOpen orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, braceOpen->GetOrigLine(), braceOpen->GetOrigCol(), braceOpen->Text()); + // produces much more log output. Use it only debugging purpose + //log_pcf_flags(LNEWLINE, braceOpen->GetFlags()); + + if (braceOpen->TestFlags(PCF_ONE_LINER)) + { + LOG_FMT(LNEWLINE, "%s(%d): is one_liner\n", + __func__, __LINE__); + return; + } + Chunk *beforeBrace = braceOpen->GetPrev(); + + LOG_FMT(LNEWLINE, "%s(%d): beforeBrace orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, beforeBrace->GetOrigLine(), beforeBrace->GetOrigCol(), beforeBrace->Text()); + // 'namespace' 'BRACE_OPEN' + newline_iarf_pair(beforeBrace, braceOpen, nl_opt); +} // newlines_namespace + + +static void newlines_cuddle_uncuddle(Chunk *start, iarf_e nl_opt) +{ + LOG_FUNC_ENTRY(); + + log_rule_B("nl_define_macro"); + + if ( start->TestFlags(PCF_IN_PREPROC) + && !options::nl_define_macro()) + { + return; + } + Chunk *br_close = start->GetPrevNcNnlNi(); // Issue #2279 + + if (br_close->Is(CT_BRACE_CLOSE)) + { + newline_iarf_pair(br_close, start, nl_opt); + } +} // newlines_cuddle_uncuddle + + +static void newlines_do_else(Chunk *start, iarf_e nl_opt) +{ + LOG_FUNC_ENTRY(); + + log_rule_B("nl_define_macro"); + log_ruleNL("nl_define_macro", start); + + if ( nl_opt == IARF_IGNORE + || ( start->TestFlags(PCF_IN_PREPROC) + && !options::nl_define_macro())) + { + return; + } + Chunk *next = start->GetNextNcNnl(); + + if ( next->IsNotNullChunk() + && ( next->Is(CT_BRACE_OPEN) + || next->Is(CT_VBRACE_OPEN))) + { + if (!one_liner_nl_ok(next)) + { + LOG_FMT(LNL1LINE, "%s(%d): a new line may NOT be added\n", __func__, __LINE__); + return; + } + LOG_FMT(LNL1LINE, "%s(%d): a new line may be added\n", __func__, __LINE__); + + if (next->Is(CT_VBRACE_OPEN)) + { + // Can only add - we don't want to create a one-line here + if (nl_opt & IARF_ADD) + { + newline_iarf_pair(start, next->GetNextNcNnl(), nl_opt); + Chunk *tmp = next->GetNextType(CT_VBRACE_CLOSE, next->GetLevel()); + + if ( !tmp->GetNextNc()->IsNewline() + && !tmp->GetPrevNc()->IsNewline()) + { + newline_add_after(tmp); + } + } + } + else + { + newline_iarf_pair(start, next, nl_opt); + newline_add_between(next, next->GetNextNcNnl()); + } + } +} // newlines_do_else + + +static bool is_var_def(Chunk *pc, Chunk *next) +{ + if ( pc->Is(CT_DECLTYPE) + && next->Is(CT_PAREN_OPEN)) + { + // If current token starts a decltype expression, skip it + next = next->GetClosingParen(); + next = next->GetNextNcNnl(); + } + else if (!pc->IsTypeDefinition()) + { + // Otherwise, if the current token is not a type --> not a declaration + return(false); + } + else if (next->Is(CT_DC_MEMBER)) + { + // If next token is CT_DC_MEMBER, skip it + next = next->SkipDcMember(); + } + else if (next->Is(CT_ANGLE_OPEN)) + { + // If we have a template type, skip it + next = next->GetClosingParen(); + next = next->GetNextNcNnl(); + } + bool is = ( ( next->IsTypeDefinition() + && next->GetParentType() != CT_FUNC_DEF) // Issue #2639 + || next->Is(CT_WORD) + || next->Is(CT_FUNC_CTOR_VAR)); + + return(is); +} // is_var_def + + +static bool is_func_call_or_def(Chunk *pc) +{ + if ( pc->GetParentType() == CT_FUNC_DEF + || pc->GetParentType() == CT_FUNC_CALL + || pc->GetParentType() == CT_FUNC_CALL_USER + || pc->GetParentType() == CT_FUNC_CLASS_DEF + || pc->GetParentType() == CT_OC_CLASS + || pc->GetParentType() == CT_OC_MSG_DECL + || pc->GetParentType() == CT_CS_PROPERTY + || pc->GetParentType() == CT_CPP_LAMBDA) + { + return(true); + } + return(false); +} // is_func_call_or_def + + +// Put newline(s) before and/or after a block of variable definitions +static Chunk *newline_var_def_blk(Chunk *start) +{ +//prot_the_line(__func__, __LINE__, 15, 4); + LOG_FUNC_ENTRY(); + + Chunk *pc = start; + Chunk *prev = start->GetPrevNcNnlNi(); // Issue #2279 + bool did_this_line = false; + bool fn_top = false; + bool var_blk = false; + bool first_var_blk = true; + + LOG_FMT(LVARDFBLK, "%s(%d): start orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, start->GetOrigLine(), start->GetOrigCol(), start->Text()); + + if (start->Is(CT_BRACE_OPEN)) + { + // can't be any variable definitions in a "= {" block + if ( (prev != nullptr) + && prev->IsNotNullChunk() + && prev->Is(CT_ASSIGN)) + { + Chunk *tmp = start->GetClosingParen(); + return(tmp->GetNextNcNnl()); + } + // check if we're at the top of a function definition, or function call with a + // possible variable block + fn_top = is_func_call_or_def(start); + // opening brace is processed, start with next chunk + pc = pc->GetNext(); + } + + while ( pc->IsNotNullChunk() + && ( pc->GetLevel() >= start->GetLevel() + || pc->GetLevel() == 0)) + { + LOG_CHUNK(LTOK, pc); + + Chunk *next_pc = pc->GetNext(); + LOG_FMT(LVARDFBLK, "%s(%d): next_pc orig line is %zu, orig col is %zu, type is %s, Text() is '%s'\n", + __func__, __LINE__, next_pc->GetOrigLine(), next_pc->GetOrigCol(), get_token_name(next_pc->GetType()), next_pc->Text()); + + // If next_pc token is CT_DC_MEMBER, skip it + if (next_pc->Is(CT_DC_MEMBER)) + { + pc = pc->SkipDcMember(); + } + + // skip qualifiers + if (pc->Is(CT_QUALIFIER)) + { + pc = pc->GetNext(); + continue; + } + + if (pc->IsComment()) + { + pc = pc->GetNext(); + continue; + } + + // process nested braces + if (pc->Is(CT_BRACE_OPEN)) + { + pc = newline_var_def_blk(pc); + continue; + } + + // Done with this brace set? + if (pc->Is(CT_BRACE_CLOSE)) + { + pc = pc->GetNext(); + break; + } + + // skip vbraces + if (pc->Is(CT_VBRACE_OPEN)) + { + pc = pc->GetNextType(CT_VBRACE_CLOSE, pc->GetLevel()); + pc = pc->GetNext(); + continue; + } + + // Ignore stuff inside parenthesis/squares/angles + if (pc->GetLevel() > pc->GetBraceLevel()) + { + pc = pc->GetNext(); + continue; + } + + if (pc->IsNewline()) + { + did_this_line = false; + pc = pc->GetNext(); + continue; + } + + // Determine if this is a variable definition or code + if ( !did_this_line + && pc->IsNot(CT_FUNC_CLASS_DEF) + && pc->IsNot(CT_FUNC_CLASS_PROTO) + && ( (pc->GetLevel() == (start->GetLevel() + 1)) + || pc->GetLevel() == 0)) + { + Chunk *next = pc->GetNextNcNnl(); + LOG_FMT(LVARDFBLK, "%s(%d): next orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, next->GetOrigLine(), next->GetOrigCol(), next->Text()); + + // skip over all other type-like things + while ( next->Is(CT_PTR_TYPE) // Issue #2692 + || next->Is(CT_BYREF) // Issue #3018 + || next->Is(CT_QUALIFIER) + || next->Is(CT_TSQUARE)) + { + next = next->GetNextNcNnl(); + LOG_FMT(LVARDFBLK, "%s(%d): next orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, next->GetOrigLine(), next->GetOrigCol(), next->Text()); + } + + if (next->IsNullChunk()) + { + break; + } + LOG_FMT(LVARDFBLK, "%s(%d): next orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, next->GetOrigLine(), next->GetOrigCol(), next->Text()); + + prev = pc->GetPrevNcNnl(); + + while ( prev->Is(CT_DC_MEMBER) + || prev->Is(CT_QUALIFIER) + || prev->Is(CT_TYPE)) + { + prev = prev->GetPrevNcNnl(); + } + + if (!( prev->IsBraceOpen() + || prev->IsBraceClose())) + { + prev = pc->GetPrevType(CT_SEMICOLON, pc->GetLevel()); + } + + if (prev->IsNullChunk()) + { + prev = pc->GetPrevType(CT_BRACE_OPEN, pc->GetLevel() - 1); // Issue #2692 + } + + if ( prev->Is(CT_STRING) + && prev->GetParentType() == CT_EXTERN + && prev->GetPrev()->Is(CT_EXTERN)) + { + prev = prev->GetPrev()->GetPrevNcNnlNi(); // Issue #2279 + } + LOG_FMT(LVARDFBLK, "%s(%d): pc orig line is %zu, orig col is %zu, type is %s, Text() is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType()), pc->Text()); + LOG_FMT(LVARDFBLK, "%s(%d): next orig line is %zu, orig col is %zu, type is %s, Text() is '%s'\n", + __func__, __LINE__, next->GetOrigLine(), next->GetOrigCol(), get_token_name(next->GetType()), next->Text()); + + if (is_var_def(pc, next)) + { + LOG_FMT(LVARDFBLK, "%s(%d): 'typ==var' found: '%s %s' at line %zu\n", + __func__, __LINE__, pc->Text(), next->Text(), pc->GetOrigLine()); + LOG_FMT(LBLANKD, "%s(%d): var_blk %s, first_var_blk %s, fn_top %s\n", + __func__, __LINE__, var_blk ? "TRUE" : "FALSE", + first_var_blk ? "TRUE" : "FALSE", fn_top ? "TRUE" : "FALSE"); + // Put newline(s) before a block of variable definitions + log_rule_B("nl_var_def_blk_start"); + + if ( !var_blk + && !first_var_blk + && options::nl_var_def_blk_start() > 0) + { + LOG_FMT(LVARDFBLK, "%s(%d): pc is '%s', orig line is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine()); + + if (prev == nullptr) + { + LOG_FMT(LVARDFBLK, "%s(%d): prev is nullptr\n", __func__, __LINE__); + } + else + { + LOG_FMT(LVARDFBLK, "%s(%d): prev is '%s', orig line is %zu\n", + __func__, __LINE__, prev->Text(), prev->GetOrigLine()); + + if (!prev->IsBraceOpen()) + { + newline_min_after(prev, options::nl_var_def_blk_start() + 1, PCF_VAR_DEF); + } + } + } + // set newlines within var def block + log_rule_B("nl_var_def_blk_in"); + + if ( var_blk + && (options::nl_var_def_blk_in() > 0)) + { + prev = pc->GetPrev(); + LOG_FMT(LVARDFBLK, "%s(%d): prev orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, prev->GetOrigLine(), prev->GetOrigCol(), prev->Text()); + + if (prev->IsNewline()) + { + if (prev->GetNlCount() > options::nl_var_def_blk_in()) + { + prev->SetNlCount(options::nl_var_def_blk_in()); + MARK_CHANGE(); + } + } + } + pc = pc->GetNextType(CT_SEMICOLON, pc->GetLevel()); + var_blk = true; + } + else if (var_blk) + { + LOG_FMT(LVARDFBLK, "%s(%d): var_blk %s, first_var_blk %s, fn_top %s\n", + __func__, __LINE__, var_blk ? "TRUE" : "FALSE", + first_var_blk ? "TRUE" : "FALSE", fn_top ? "TRUE" : "FALSE"); + log_rule_B("nl_var_def_blk_end_func_top"); + log_rule_B("nl_var_def_blk_end"); + + if ( first_var_blk + && fn_top) + { + // set blank lines after first var def block at the top of a function + if (options::nl_var_def_blk_end_func_top() > 0) + { + LOG_FMT(LVARDFBLK, "%s(%d): nl_var_def_blk_end_func_top at line %zu\n", + __func__, __LINE__, prev->GetOrigLine()); + prot_the_line(__func__, __LINE__, 15, 4); + newline_min_after(prev, options::nl_var_def_blk_end_func_top() + 1, PCF_VAR_DEF); + } + } + else if ( !pc->IsPreproc() + && options::nl_var_def_blk_end() > 0) + { + // set blank lines after other var def blocks + LOG_FMT(LVARDFBLK, "%s(%d): nl_var_def_blk_end at line %zu\n", + __func__, __LINE__, prev->GetOrigLine()); + // Issue #3516 + newline_min_after(prev, options::nl_var_def_blk_end() + 1, PCF_VAR_DEF); + } + // reset the variables for the next block + prot_the_line(__func__, __LINE__, 15, 4); + first_var_blk = false; + var_blk = false; + } + else + { + first_var_blk = false; + var_blk = false; + } + } + else + { + if (pc->Is(CT_FUNC_CLASS_DEF)) + { + log_rule_B("nl_var_def_blk_end"); + + if ( var_blk + && options::nl_var_def_blk_end() > 0) + { + prev = pc->GetPrev(); + prev = prev->GetPrev(); + newline_min_after(prev, options::nl_var_def_blk_end() + 1, PCF_VAR_DEF); + pc = pc->GetNext(); + first_var_blk = false; + var_blk = false; + } + } + } + did_this_line = true; + + if (pc == nullptr) + { + pc = Chunk::NullChunkPtr; + } + pc = pc->GetNext(); + } + LOG_FMT(LVARDFBLK, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s', level is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), pc->GetLevel()); + LOG_FMT(LVARDFBLK, "%s(%d): start orig line is %zu, orig col is %zu, Text() is '%s', level is %zu\n", + __func__, __LINE__, start->GetOrigLine(), start->GetOrigCol(), start->Text(), start->GetLevel()); + //prot_the_line(__func__, __LINE__, 15, 4); + return(pc); +} // newline_var_def_blk + + +static void collapse_empty_body(Chunk *br_open) +{ + for (Chunk *pc = br_open->GetNext(); pc->IsNot(CT_BRACE_CLOSE); pc = pc->GetNext()) + { + if ( pc->Is(CT_NEWLINE) + && pc->SafeToDeleteNl()) + { + pc = pc->GetPrev(); + Chunk *next = pc->GetNext(); + Chunk::Delete(next); + MARK_CHANGE(); + } + } +} // collapse_empty_body + + +static void newlines_brace_pair(Chunk *br_open) +{ + LOG_FUNC_ENTRY(); + + log_rule_B("nl_define_macro"); + + if ( br_open->TestFlags(PCF_IN_PREPROC) + && !options::nl_define_macro()) + { + return; + } + + //fixes 1235 Add single line namespace support + if ( br_open->Is(CT_BRACE_OPEN) + && (br_open->GetParentType() == CT_NAMESPACE) + && br_open->GetPrev()->IsNewline()) + { + Chunk *chunk_brace_close = br_open->GetClosingParen(); + + if (chunk_brace_close->IsNotNullChunk()) + { + if (br_open->IsOnSameLine(chunk_brace_close)) + { + log_rule_B("nl_namespace_two_to_one_liner - 1"); + + if (options::nl_namespace_two_to_one_liner()) + { + Chunk *prev = br_open->GetPrevNnl(); + newline_del_between(prev, br_open); + } + /* Below code is to support conversion of 2 liner to 4 liners + * else + * { + * Chunk *nxt = br_open->GetNext(); + * newline_add_between(br_open, nxt); + * }*/ + } + } + } + // fix 1247 oneliner function support - converts 4,3,2 liners to oneliner + log_rule_B("nl_create_func_def_one_liner"); + + if ( br_open->GetParentType() == CT_FUNC_DEF + && options::nl_create_func_def_one_liner() + && !br_open->TestFlags(PCF_NOT_POSSIBLE)) // Issue #2795 + { + Chunk *br_close = br_open->GetClosingParen(); + Chunk *tmp = br_open->GetPrevNcNnlNi(); // Issue #2279 + + if ( br_close->IsNotNullChunk() // Issue #2594 + && ((br_close->GetOrigLine() - br_open->GetOrigLine()) <= 2) + && tmp->IsParenClose()) // need to check the conditions. + { + // Issue #1825 + bool is_it_possible = true; + + while ( tmp->IsNotNullChunk() + && (tmp = tmp->GetNext())->IsNotNullChunk() + && !tmp->IsBraceClose() + && (tmp->GetNext()->IsNotNullChunk())) + { + LOG_FMT(LNL1LINE, "%s(%d): tmp orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, tmp->GetOrigLine(), tmp->GetOrigCol(), tmp->Text()); + + if (tmp->IsComment()) + { + is_it_possible = false; + break; + } + } + + if (is_it_possible) + { + // Issue 2795 + // we have to check if it could be too long for code_width + // make a vector to save the chunk + vector<Chunk> saved_chunk; + log_rule_B("code_width"); + + if (options::code_width() > 0) + { + saved_chunk.reserve(16); + Chunk *current = br_open->GetPrevNcNnlNi(); + Chunk *next_br_close = br_close->GetNext(); + current = current->GetNext(); + + while (current->IsNotNullChunk()) + { + LOG_FMT(LNL1LINE, "%s(%d): zu kopieren: current orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, current->GetOrigLine(), current->GetOrigCol(), current->Text()); + saved_chunk.push_back(*current); + Chunk *the_next = current->GetNext(); + + if ( the_next->IsNullChunk() + || the_next == next_br_close) + { + break; + } + current = the_next; + } + } + Chunk *tmp_1 = br_open->GetPrevNcNnlNi(); + + while ( tmp_1->IsNotNullChunk() + && (tmp_1 = tmp_1->GetNext())->IsNotNullChunk() + && !tmp_1->IsBraceClose() + && (tmp_1->GetNext()->IsNotNullChunk())) + { + LOG_FMT(LNL1LINE, "%s(%d): tmp_1 orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, tmp_1->GetOrigLine(), tmp_1->GetOrigCol(), tmp_1->Text()); + + if (tmp_1->IsNewline()) + { + tmp_1 = tmp_1->GetPrev(); // Issue #1825 + newline_iarf_pair(tmp_1, tmp_1->GetNextNcNnl(), IARF_REMOVE); + } + } + br_open->SetFlagBits(PCF_ONE_LINER); // set the one liner flag if needed + br_close->SetFlagBits(PCF_ONE_LINER); + log_rule_B("code_width"); + + if ( options::code_width() > 0 + && br_close->GetColumn() > options::code_width()) + { + // the created line is too long + // it is not possible to make an one_liner + // because the line would be too long + br_open->SetFlagBits(PCF_NOT_POSSIBLE); + // restore the code + size_t count; + Chunk tmp_2; + Chunk *current = br_open; + + for (count = 0; count < saved_chunk.size(); count++) + { + tmp_2 = saved_chunk.at(count); + + if (tmp_2.GetOrigLine() != current->GetOrigLine()) + { + // restore the newline + Chunk chunk; + chunk.SetType(CT_NEWLINE); + chunk.SetOrigLine(current->GetOrigLine()); + chunk.SetOrigCol(current->GetOrigCol()); + chunk.SetPpLevel(current->GetPpLevel()); + chunk.SetNlCount(1); + chunk.CopyAndAddBefore(current); + LOG_FMT(LNEWLINE, "%s(%d): %zu:%zu add newline before '%s'\n", + __func__, __LINE__, current->GetOrigLine(), current->GetOrigCol(), current->Text()); + } + else + { + current = current->GetNext(); + } + } + } + } + } + } + + // Make sure we don't break a one-liner + if (!one_liner_nl_ok(br_open)) + { + LOG_FMT(LNL1LINE, "%s(%d): br_open orig line is %zu, orig col is %zu, a new line may NOT be added\n", + __func__, __LINE__, br_open->GetOrigLine(), br_open->GetOrigCol()); + return; + } + LOG_FMT(LNL1LINE, "%s(%d): a new line may be added\n", __func__, __LINE__); + + Chunk *next = br_open->GetNextNc(); + + // Insert a newline between the '=' and open brace, if needed + LOG_FMT(LNL1LINE, "%s(%d): br_open->Text() '%s', br_open->GetType() [%s], br_open->GetParentType() [%s]\n", + __func__, __LINE__, br_open->Text(), get_token_name(br_open->GetType()), + get_token_name(br_open->GetParentType())); + + if (br_open->GetParentType() == CT_ASSIGN) + { + // Only mess with it if the open brace is followed by a newline + if (next->IsNewline()) + { + Chunk *prev = br_open->GetPrevNcNnlNi(); // Issue #2279 + log_rule_B("nl_assign_brace"); + newline_iarf_pair(prev, br_open, options::nl_assign_brace()); + } + } + + if ( br_open->GetParentType() == CT_OC_MSG_DECL + || br_open->GetParentType() == CT_FUNC_DEF + || br_open->GetParentType() == CT_FUNC_CLASS_DEF + || br_open->GetParentType() == CT_OC_CLASS + || br_open->GetParentType() == CT_CS_PROPERTY + || br_open->GetParentType() == CT_CPP_LAMBDA + || br_open->GetParentType() == CT_FUNC_CALL + || br_open->GetParentType() == CT_FUNC_CALL_USER) + { + Chunk *prev = Chunk::NullChunkPtr; + iarf_e val; + + if (br_open->GetParentType() == CT_OC_MSG_DECL) + { + log_rule_B("nl_oc_mdef_brace"); + val = options::nl_oc_mdef_brace(); + } + else + { + if ( br_open->GetParentType() == CT_FUNC_DEF + || br_open->GetParentType() == CT_FUNC_CLASS_DEF + || br_open->GetParentType() == CT_OC_CLASS) + { + val = IARF_NOT_DEFINED; + log_rule_B("nl_fdef_brace_cond"); + const iarf_e nl_fdef_brace_cond_v = options::nl_fdef_brace_cond(); + + if (nl_fdef_brace_cond_v != IARF_IGNORE) + { + prev = br_open->GetPrevNcNnlNi(); // Issue #2279 + + if (prev->Is(CT_FPAREN_CLOSE)) + { + val = nl_fdef_brace_cond_v; + } + } + + if (val == IARF_NOT_DEFINED) + { + log_rule_B("nl_fdef_brace"); + val = options::nl_fdef_brace(); + } + } + else + { + log_rule_B("nl_property_brace"); + log_rule_B("nl_cpp_ldef_brace"); + log_rule_B("nl_fcall_brace"); + val = ((br_open->GetParentType() == CT_CS_PROPERTY) ? + options::nl_property_brace() : + ((br_open->GetParentType() == CT_CPP_LAMBDA) ? + options::nl_cpp_ldef_brace() : + options::nl_fcall_brace())); + } + } + + if (val != IARF_IGNORE) + { + if (prev->IsNullChunk()) + { + // Grab the chunk before the open brace + prev = br_open->GetPrevNcNnlNi(); // Issue #2279 + } + newline_iarf_pair(prev, br_open, val); + } + } + + if (br_open->GetNextNnl()->Is(CT_BRACE_CLOSE)) + { + // Chunk is "{" and "}" with only whitespace/newlines in between + + if (br_open->GetParentType() == CT_FUNC_DEF) + { + // Braces belong to a function definition + log_rule_B("nl_collapse_empty_body_functions"); + + if (options::nl_collapse_empty_body_functions()) + { + collapse_empty_body(br_open); + return; + } + } + else + { + log_rule_B("nl_collapse_empty_body"); + + if (options::nl_collapse_empty_body()) + { + collapse_empty_body(br_open); + return; + } + } + } + //fixes #1245 will add new line between tsquare and brace open based on nl_tsquare_brace + + if (br_open->Is(CT_BRACE_OPEN)) + { + Chunk *chunk_closing_brace = br_open->GetClosingParen(); + + if (chunk_closing_brace->IsNotNullChunk()) + { + if (chunk_closing_brace->GetOrigLine() > br_open->GetOrigLine()) + { + Chunk *prev = br_open->GetPrevNc(); + + if ( prev->Is(CT_TSQUARE) + && next->IsNewline()) + { + log_rule_B("nl_tsquare_brace"); + newline_iarf_pair(prev, br_open, options::nl_tsquare_brace()); + } + } + } + } + // Eat any extra newlines after the brace open + log_rule_B("eat_blanks_after_open_brace"); + + if (options::eat_blanks_after_open_brace()) + { + if (next->IsNewline()) + { + log_rule_B("nl_inside_empty_func"); + log_rule_B("nl_inside_namespace"); + + if ( options::nl_inside_empty_func() > 0 + && br_open->GetNextNnl()->Is(CT_BRACE_CLOSE) + && ( br_open->GetParentType() == CT_FUNC_CLASS_DEF + || br_open->GetParentType() == CT_FUNC_DEF)) + { + blank_line_set(next, options::nl_inside_empty_func); + } + else if ( options::nl_inside_namespace() > 0 + && br_open->GetParentType() == CT_NAMESPACE) + { + blank_line_set(next, options::nl_inside_namespace); + } + else if (next->GetNlCount() > 1) + { + next->SetNlCount(1); + LOG_FMT(LBLANKD, "%s(%d): eat_blanks_after_open_brace %zu\n", + __func__, __LINE__, next->GetOrigLine()); + MARK_CHANGE(); + } + } + } + bool nl_close_brace = false; + + // Handle the cases where the brace is part of a function call or definition + if (is_func_call_or_def(br_open)) + { + // Need to force a newline before the close brace, if not in a class body + if (!br_open->TestFlags(PCF_IN_CLASS)) + { + nl_close_brace = true; + } + // handle newlines after the open brace + Chunk *pc = br_open->GetNextNcNnl(); + newline_add_between(br_open, pc); + } + // Grab the matching brace close + Chunk *br_close = br_open->GetNextType(CT_BRACE_CLOSE, br_open->GetLevel()); + + if (br_close->IsNullChunk()) + { + return; + } + + if (!nl_close_brace) + { + /* + * If the open brace hits a CT_NEWLINE, CT_NL_CONT, CT_COMMENT_MULTI, or + * CT_COMMENT_CPP without hitting anything other than CT_COMMENT, then + * there should be a newline before the close brace. + */ + Chunk *pc = br_open->GetNext(); + + while (pc->Is(CT_COMMENT)) + { + pc = pc->GetNext(); + } + + if (pc->IsCommentOrNewline()) + { + nl_close_brace = true; + } + } + Chunk *prev = br_close->GetPrevNcNnlNet(); + + if (nl_close_brace) + { + newline_add_between(prev, br_close); + } + else + { + newline_del_between(prev, br_close); + } +} // newlines_brace_pair + + +static void newline_case(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + // printf("%s case (%s) on line %d col %d\n", + // __func__, c_chunk_names[start->GetType()], + // start->GetOrigLine(), start->GetOrigCol()); + + // Scan backwards until a '{' or ';' or ':'. Abort if a multi-newline is found + Chunk *prev = start; + + do + { + prev = prev->GetPrevNc(); + + if ( prev->IsNotNullChunk() + && prev->IsNewline() + && prev->GetNlCount() > 1) + { + return; + } + } while ( prev->IsNot(CT_BRACE_OPEN) + && prev->IsNot(CT_BRACE_CLOSE) + && prev->IsNot(CT_SEMICOLON) + && prev->IsNot(CT_CASE_COLON)); + + if (prev->IsNullChunk()) + { + return; + } + Chunk *pc = newline_add_between(prev, start); + + if (pc == nullptr) + { + return; + } + + // Only add an extra line after a semicolon or brace close + if ( prev->Is(CT_SEMICOLON) + || prev->Is(CT_BRACE_CLOSE)) + { + if ( pc->IsNewline() + && pc->GetNlCount() < 2) + { + double_newline(pc); + } + } +} // newline_case + + +static void newline_case_colon(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + // Scan forwards until a non-comment is found + Chunk *pc = start; + + do + { + pc = pc->GetNext(); + } while (pc->IsComment()); + + if ( pc->IsNotNullChunk() + && !pc->IsNewline()) + { + newline_add_before(pc); + } +} // newline_case_colon + + +static void newline_before_return(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + Chunk *pc = Chunk::NullChunkPtr; + + if (start != nullptr) + { + pc = start->GetPrev(); + } + Chunk *nl = pc; + + // Skip over single preceding newline + if (pc->IsNewline()) + { + // Do we already have a blank line? + if (nl->GetNlCount() > 1) + { + return; + } + pc = nl->GetPrev(); + } + + // Skip over preceding comments that are not a trailing comment, taking + // into account that comment blocks may span multiple lines. + // Trailing comments are considered part of the previous token, not the + // return statement. They are handled below. + while ( pc->IsComment() + && pc->GetParentType() != CT_COMMENT_END) + { + pc = pc->GetPrev(); + + if (!pc->IsNewline()) + { + return; + } + nl = pc; + pc = pc->GetPrev(); + } + pc = nl->GetPrev(); + + // Peek over trailing comment of previous token + if ( pc->IsComment() + && pc->GetParentType() == CT_COMMENT_END) + { + pc = pc->GetPrev(); + } + + // Don't add extra blanks after an opening brace or a case statement + if ( pc->IsNullChunk() + || ( pc->Is(CT_BRACE_OPEN) + || pc->Is(CT_VBRACE_OPEN) + || pc->Is(CT_CASE_COLON))) + { + return; + } + + if ( nl->IsNewline() + && nl->GetNlCount() < 2) + { + nl->SetNlCount(nl->GetNlCount() + 1); + MARK_CHANGE(); + LOG_FMT(LBLANK, "%s(%d): orig line is %zu, orig col is %zu, text is '%s', new line count is now %zu\n", + __func__, __LINE__, nl->GetOrigLine(), nl->GetOrigCol(), nl->Text(), nl->GetNlCount()); + } +} // newline_before_return + + +static void newline_after_return(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + Chunk *semi = start->GetNextType(CT_SEMICOLON, start->GetLevel()); + Chunk *after = semi->GetNextNcNnlNet(); + + // If we hit a brace or an 'else', then a newline isn't needed + if ( after->IsNullChunk() + || after->IsBraceClose() + || after->Is(CT_ELSE)) + { + return; + } + Chunk *pc; + + for (pc = semi->GetNext(); pc != after; pc = pc->GetNext()) + { + if (pc->Is(CT_NEWLINE)) + { + if (pc->GetNlCount() < 2) + { + double_newline(pc); + } + return; + } + } +} // newline_after_return + + +static void newline_iarf_pair(Chunk *before, Chunk *after, iarf_e av, bool check_nl_assign_leave_one_liners) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LNEWLINE, "%s(%d): ", __func__, __LINE__); + log_func_stack(LNEWLINE, "CallStack:"); + + if ( before == nullptr + || before == Chunk::NullChunkPtr + || after == nullptr + || after == Chunk::NullChunkPtr + || after->Is(CT_IGNORED)) + { + return; + } + + if (av & IARF_ADD) + { + if ( check_nl_assign_leave_one_liners + && options::nl_assign_leave_one_liners() + && after->TestFlags(PCF_ONE_LINER)) + { + log_rule_B("nl_assign_leave_one_liners"); + return; + } + Chunk *nl = newline_add_between(before, after); + LOG_FMT(LNEWLINE, "%s(%d): newline_add_between '%s' and '%s'\n", + __func__, __LINE__, before->Text(), after->Text()); + + if ( nl != nullptr + && av == IARF_FORCE + && nl->GetNlCount() > 1) + { + nl->SetNlCount(1); + } + } + else if (av & IARF_REMOVE) + { + LOG_FMT(LNEWLINE, "%s(%d): newline_remove_between '%s' and '%s'\n", + __func__, __LINE__, before->Text(), after->Text()); + newline_del_between(before, after); + } +} // newline_iarf_pair + + +void newline_iarf(Chunk *pc, iarf_e av) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LNFD, "%s(%d): ", __func__, __LINE__); + log_func_stack(LNFD, "CallStack:"); + Chunk *after = Chunk::NullChunkPtr; + + if (pc != nullptr) + { + after = pc->GetNextNnl(); + } + + if ( (pc != nullptr && pc->Is(CT_FPAREN_OPEN)) // Issue #2914 + && pc->GetParentType() == CT_FUNC_CALL + && after->Is(CT_COMMENT_CPP) + && options::donot_add_nl_before_cpp_comment()) + { + return; + } + newline_iarf_pair(pc, after, av); +} // newline_iarf + + +static void newline_func_multi_line(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LNFD, "%s(%d): called on %zu:%zu '%s' [%s/%s]\n", + __func__, __LINE__, start->GetOrigLine(), start->GetOrigCol(), + start->Text(), get_token_name(start->GetType()), get_token_name(start->GetParentType())); + + bool add_start; + bool add_args; + bool add_end; + + if ( start->GetParentType() == CT_FUNC_DEF + || start->GetParentType() == CT_FUNC_CLASS_DEF) + { + log_rule_B("nl_func_def_start_multi_line"); + add_start = options::nl_func_def_start_multi_line(); + log_rule_B("nl_func_def_args_multi_line"); + add_args = options::nl_func_def_args_multi_line(); + log_rule_B("nl_func_def_end_multi_line"); + add_end = options::nl_func_def_end_multi_line(); + } + else if ( start->GetParentType() == CT_FUNC_CALL + || start->GetParentType() == CT_FUNC_CALL_USER) + { + log_rule_B("nl_func_call_start_multi_line"); + add_start = options::nl_func_call_start_multi_line(); + log_rule_B("nl_func_call_args_multi_line"); + add_args = options::nl_func_call_args_multi_line(); + log_rule_B("nl_func_call_end_multi_line"); + add_end = options::nl_func_call_end_multi_line(); + } + else + { + log_rule_B("nl_func_decl_start_multi_line"); + add_start = options::nl_func_decl_start_multi_line(); + log_rule_B("nl_func_decl_args_multi_line"); + add_args = options::nl_func_decl_args_multi_line(); + log_rule_B("nl_func_decl_end_multi_line"); + add_end = options::nl_func_decl_end_multi_line(); + } + + if ( !add_start + && !add_args + && !add_end) + { + return; + } + Chunk *pc = start->GetNextNcNnl(); + + while ( pc->IsNotNullChunk() + && pc->GetLevel() > start->GetLevel()) + { + pc = pc->GetNextNcNnl(); + } + + if ( pc->Is(CT_FPAREN_CLOSE) + && start->IsNewlineBetween(pc)) + { + Chunk *start_next = start->GetNextNcNnl(); + bool has_leading_closure = ( start_next->GetParentType() == CT_OC_BLOCK_EXPR + || start_next->GetParentType() == CT_CPP_LAMBDA + || start_next->Is(CT_BRACE_OPEN)); + + Chunk *prev_end = pc->GetPrevNcNnl(); + bool has_trailing_closure = ( prev_end->GetParentType() == CT_OC_BLOCK_EXPR + || prev_end->GetParentType() == CT_CPP_LAMBDA + || prev_end->Is(CT_BRACE_OPEN)); + + if ( add_start + && !start->GetNext()->IsNewline()) + { + log_rule_B("nl_func_call_args_multi_line_ignore_closures"); + + if (options::nl_func_call_args_multi_line_ignore_closures()) + { + if ( !has_leading_closure + && !has_trailing_closure) + { + newline_iarf(start, IARF_ADD); + } + } + else + { + newline_iarf(start, IARF_ADD); + } + } + + if ( add_end + && !pc->GetPrev()->IsNewline()) + { + log_rule_B("nl_func_call_args_multi_line_ignore_closures"); + + if (options::nl_func_call_args_multi_line_ignore_closures()) + { + if ( !has_leading_closure + && !has_trailing_closure) + { + newline_iarf(pc->GetPrev(), IARF_ADD); + } + } + else + { + newline_iarf(pc->GetPrev(), IARF_ADD); + } + } + + if (add_args) + { + // process the function in reverse and leave the first comma if the option to leave trailing closure + // is on. nl_func_call_args_multi_line_ignore_trailing_closure + for (pc = start->GetNextNcNnl(); + pc->IsNotNullChunk() && pc->GetLevel() > start->GetLevel(); + pc = pc->GetNextNcNnl()) + { + if ( pc->Is(CT_COMMA) + && (pc->GetLevel() == (start->GetLevel() + 1))) + { + Chunk *tmp = pc->GetNext(); + + if (tmp->IsComment()) + { + pc = tmp; + } + + if (!pc->GetNext()->IsNewline()) + { + log_rule_B("nl_func_call_args_multi_line_ignore_closures"); + + if (options::nl_func_call_args_multi_line_ignore_closures()) + { + Chunk *prev_comma = pc->GetPrevNcNnl(); + Chunk *after_comma = pc->GetNextNcNnl(); + + if (!( ( prev_comma->GetParentType() == CT_OC_BLOCK_EXPR + || prev_comma->GetParentType() == CT_CPP_LAMBDA + || prev_comma->Is(CT_BRACE_OPEN)) + || ( after_comma->GetParentType() == CT_OC_BLOCK_EXPR + || after_comma->GetParentType() == CT_CPP_LAMBDA + || after_comma->Is(CT_BRACE_OPEN)))) + { + newline_iarf(pc, IARF_ADD); + } + } + else + { + newline_iarf(pc, IARF_ADD); + } + } + } + } + } + } +} // newline_func_multi_line + + +static void newline_template(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LNFD, "%s(%d): called on %zu:%zu '%s' [%s/%s]\n", + __func__, __LINE__, start->GetOrigLine(), start->GetOrigCol(), + start->Text(), get_token_name(start->GetType()), get_token_name(start->GetParentType())); + + log_rule_B("nl_template_start"); + bool add_start = options::nl_template_start(); + + log_rule_B("nl_template_args"); + bool add_args = options::nl_template_args(); + + log_rule_B("nl_template_end"); + bool add_end = options::nl_template_end(); + + if ( !add_start + && !add_args + && !add_end) + { + return; + } + Chunk *pc = start->GetNextNcNnl(); + + while ( pc->IsNotNullChunk() + && pc->GetLevel() > start->GetLevel()) + { + pc = pc->GetNextNcNnl(); + } + + if (pc->Is(CT_ANGLE_CLOSE)) + { + if (add_start) + { + newline_iarf(start, IARF_ADD); + } + + if (add_end) + { + newline_iarf(pc->GetPrev(), IARF_ADD); + } + + if (add_args) + { + Chunk *pc_1; + + for (pc_1 = start->GetNextNcNnl(); + pc_1->IsNotNullChunk() && pc_1->GetLevel() > start->GetLevel(); + pc_1 = pc_1->GetNextNcNnl()) + { + if ( pc_1->Is(CT_COMMA) + && (pc_1->GetLevel() == (start->GetLevel() + 1))) + { + Chunk *tmp = pc_1->GetNext(); + + if (tmp->IsComment()) + { + pc_1 = tmp; + } + + if (!pc_1->GetNext()->IsNewline()) + { + newline_iarf(pc_1, IARF_ADD); + } + } + } + } + } +} // newline_template + + +static void newline_func_def_or_call(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LNFD, "%s(%d): called on start->Text() is '%s', orig line is %zu, orig col is %zu, [%s/%s]\n", + __func__, __LINE__, start->Text(), start->GetOrigLine(), start->GetOrigCol(), + get_token_name(start->GetType()), get_token_name(start->GetParentType())); + + bool is_def = (start->GetParentType() == CT_FUNC_DEF) + || start->GetParentType() == CT_FUNC_CLASS_DEF; + bool is_call = (start->GetParentType() == CT_FUNC_CALL) + || start->GetParentType() == CT_FUNC_CALL_USER; + + LOG_FMT(LNFD, "%s(%d): is_def is %s, is_call is %s\n", + __func__, __LINE__, is_def ? "TRUE" : "FALSE", is_call ? "TRUE" : "FALSE"); + + if (is_call) + { + log_rule_B("nl_func_call_paren"); + iarf_e atmp = options::nl_func_call_paren(); + + if (atmp != IARF_IGNORE) + { + Chunk *prev = start->GetPrevNcNnlNi(); // Issue #2279 + + if (prev->IsNotNullChunk()) + { + newline_iarf(prev, atmp); + } + } + Chunk *pc = start->GetNextNcNnl(); + + if (pc->IsString(")")) + { + log_rule_B("nl_func_call_paren_empty"); + atmp = options::nl_func_call_paren_empty(); + + if (atmp != IARF_IGNORE) + { + Chunk *prev = start->GetPrevNcNnlNi(); // Issue #2279 + + if (prev->IsNotNullChunk()) + { + newline_iarf(prev, atmp); + } + } + log_rule_B("nl_func_call_empty"); + atmp = options::nl_func_call_empty(); + + if (atmp != IARF_IGNORE) + { + newline_iarf(start, atmp); + } + return; + } + } + else + { + log_rule_B("nl_func_def_paren"); + log_rule_B("nl_func_paren"); + iarf_e atmp = is_def ? options::nl_func_def_paren() + : options::nl_func_paren(); + LOG_FMT(LSPACE, "%s(%d): atmp is %s\n", + __func__, __LINE__, + (atmp == IARF_IGNORE) ? "IGNORE" : + (atmp == IARF_ADD) ? "ADD" : + (atmp == IARF_REMOVE) ? "REMOVE" : "FORCE"); + + if (atmp != IARF_IGNORE) + { + Chunk *prev = start->GetPrevNcNnlNi(); // Issue #2279 + + if (prev->IsNotNullChunk()) + { + newline_iarf(prev, atmp); + } + } + // Handle break newlines type and function + Chunk *prev = start->GetPrevNcNnlNi(); // Issue #2279 + prev = skip_template_prev(prev); + // Don't split up a function variable + prev = prev->IsParenClose() ? Chunk::NullChunkPtr : prev->GetPrevNcNnlNi(); // Issue #2279 + + log_rule_B("nl_func_class_scope"); + + if ( prev->Is(CT_DC_MEMBER) + && (options::nl_func_class_scope() != IARF_IGNORE)) + { + newline_iarf(prev->GetPrevNcNnlNi(), options::nl_func_class_scope()); // Issue #2279 + } + + if (prev->IsNot(CT_ACCESS_COLON)) + { + Chunk *tmp; + + if (prev->Is(CT_OPERATOR)) + { + tmp = prev; + prev = prev->GetPrevNcNnlNi(); // Issue #2279 + } + else + { + tmp = start; + } + + if (prev->Is(CT_DC_MEMBER)) + { + log_rule_B("nl_func_scope_name"); + + if ( options::nl_func_scope_name() != IARF_IGNORE + && !start->TestFlags(PCF_IN_DECLTYPE)) + { + newline_iarf(prev, options::nl_func_scope_name()); + } + } + const Chunk *tmp_next = prev->GetNextNcNnl(); + + if (tmp_next->IsNot(CT_FUNC_CLASS_DEF)) + { + Chunk *closing = tmp->GetClosingParen(); + Chunk *brace = closing->GetNextNcNnl(); + iarf_e a; // Issue #2561 + + if ( tmp->GetParentType() == CT_FUNC_PROTO + || tmp->GetParentType() == CT_FUNC_CLASS_PROTO) + { + // proto + log_rule_B("nl_func_proto_type_name"); + a = options::nl_func_proto_type_name(); + } + else + { + // def + + log_rule_B("nl_func_leave_one_liners"); + + if ( options::nl_func_leave_one_liners() + && ( brace == nullptr + || brace->TestFlags(PCF_ONE_LINER))) // Issue #1511 and #3274 + { + a = IARF_IGNORE; + } + else + { + log_rule_B("nl_func_type_name"); + a = options::nl_func_type_name(); + } + } + log_rule_B("nl_func_type_name_class"); + + if ( tmp->TestFlags(PCF_IN_CLASS) + && (options::nl_func_type_name_class() != IARF_IGNORE)) + { + a = options::nl_func_type_name_class(); + } + + if ( (a != IARF_IGNORE) + && prev->IsNotNullChunk()) + { + LOG_FMT(LNFD, "%s(%d): prev->Text() '%s', orig line is %zu, orig col is %zu, [%s/%s]\n", + __func__, __LINE__, prev->Text(), prev->GetOrigLine(), prev->GetOrigCol(), + get_token_name(prev->GetType()), + get_token_name(prev->GetParentType())); + + if (prev->Is(CT_DESTRUCTOR)) + { + prev = prev->GetPrevNcNnlNi(); // Issue #2279 + } + + /* + * If we are on a '::', step back two tokens + * TODO: do we also need to check for '.' ? + */ + while (prev->Is(CT_DC_MEMBER)) + { + prev = prev->GetPrevNcNnlNi(); // Issue #2279 + prev = skip_template_prev(prev); + prev = prev->GetPrevNcNnlNi(); // Issue #2279 + } + + if ( !prev->IsBraceClose() + && prev->IsNot(CT_BRACE_OPEN) + && prev->IsNot(CT_SEMICOLON) + && prev->IsNot(CT_ACCESS_COLON) + // #1008: if we landed on an operator check that it is having + // a type before it, in order to not apply nl_func_type_name + // on conversion operators as they don't have a normal + // return type syntax + && (tmp_next->IsNot(CT_OPERATOR) ? true : prev->IsTypeDefinition())) + { + newline_iarf(prev, a); + } + } + } + } + Chunk *pc = start->GetNextNcNnl(); + + if (pc->IsString(")")) + { + log_rule_B("nl_func_def_empty"); + log_rule_B("nl_func_decl_empty"); + atmp = is_def ? options::nl_func_def_empty() + : options::nl_func_decl_empty(); + + if (atmp != IARF_IGNORE) + { + newline_iarf(start, atmp); + } + log_rule_B("nl_func_def_paren_empty"); + log_rule_B("nl_func_paren_empty"); + atmp = is_def ? options::nl_func_def_paren_empty() + : options::nl_func_paren_empty(); + + if (atmp != IARF_IGNORE) + { + prev = start->GetPrevNcNnlNi(); // Issue #2279 + + if (prev->IsNotNullChunk()) + { + newline_iarf(prev, atmp); + } + } + return; + } + } + // Now scan for commas + size_t comma_count = 0; + Chunk *tmp; + Chunk *pc; + + for (pc = start->GetNextNcNnl(); + pc->IsNotNullChunk() && pc->GetLevel() > start->GetLevel(); + pc = pc->GetNextNcNnl()) + { + if ( pc->Is(CT_COMMA) + && (pc->GetLevel() == (start->GetLevel() + 1))) + { + comma_count++; + tmp = pc->GetNext(); + + if (tmp->IsComment()) + { + pc = tmp; + } + + if (is_def) + { + log_rule_B("nl_func_def_args"); + newline_iarf(pc, options::nl_func_def_args()); + } + else if (is_call) + { + // Issue #2604 + log_rule_B("nl_func_call_args"); + newline_iarf(pc, options::nl_func_call_args()); + } + else // start->GetParentType() == CT_FUNC_DECL + { + log_rule_B("nl_func_decl_args"); + newline_iarf(pc, options::nl_func_decl_args()); + } + } + } + + log_rule_B("nl_func_def_start"); + log_rule_B("nl_func_decl_start"); + iarf_e as = is_def ? options::nl_func_def_start() : options::nl_func_decl_start(); + + log_rule_B("nl_func_def_end"); + log_rule_B("nl_func_decl_end"); + iarf_e ae = is_def ? options::nl_func_def_end() : options::nl_func_decl_end(); + + if (comma_count == 0) + { + iarf_e atmp; + log_rule_B("nl_func_def_start_single"); + log_rule_B("nl_func_decl_start_single"); + atmp = is_def ? options::nl_func_def_start_single() : + options::nl_func_decl_start_single(); + + if (atmp != IARF_IGNORE) + { + as = atmp; + } + log_rule_B("nl_func_def_end_single"); + log_rule_B("nl_func_decl_end_single"); + atmp = is_def ? options::nl_func_def_end_single() : + options::nl_func_decl_end_single(); + + if (atmp != IARF_IGNORE) + { + ae = atmp; + } + } + + if (!is_call) + { + newline_iarf(start, as); + } + + // and fix up the close parenthesis + if (pc->Is(CT_FPAREN_CLOSE)) + { + Chunk *prev = pc->GetPrevNnl(); + + if ( prev->IsNot(CT_FPAREN_OPEN) + && !is_call) + { + newline_iarf(prev, ae); + } + newline_func_multi_line(start); + } +} // newline_func_def_or_call + + +static void newline_oc_msg(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + Chunk *sq_c = start->GetClosingParen(); + + if (sq_c->IsNullChunk()) + { + return; + } + log_rule_B("nl_oc_msg_leave_one_liner"); + + if (options::nl_oc_msg_leave_one_liner()) + { + return; + } + bool should_nl_msg = false; + + // Get count of parameters + size_t parameter_count = 0; + + for (Chunk *pc = start->GetNextNcNnl(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + if (pc->GetLevel() <= start->GetLevel()) + { + break; + } + + if (pc->Is(CT_OC_COLON) && pc->GetLevel() - 1 == start->GetLevel()) + { + parameter_count++; + } + } + + size_t min_params = options::nl_oc_msg_args_min_params(); + + if ( parameter_count >= min_params + && min_params != 0) + { + should_nl_msg = true; + } + // Get length of longest line + size_t longest_line = 0; + + for (Chunk *pc = start->GetNextNcNnl(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + if (pc->GetLevel() <= start->GetLevel()) + { + break; + } + + if (pc->GetOrigColEnd() > longest_line) + { + longest_line = pc->GetOrigColEnd(); + } + } + + size_t max_code_width = options::nl_oc_msg_args_max_code_width(); + + if ( longest_line > max_code_width + && max_code_width != 0) + { + should_nl_msg = true; + } + + // If both nl_oc_msg_args_min_params and nl_oc_msg_args_max_code_width are disabled + // we should newline all messages. + if ( max_code_width == 0 + && min_params == 0) + { + should_nl_msg = true; + } + + if (!should_nl_msg) + { + return; + } + + for (Chunk *pc = start->GetNextNcNnl(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + if (pc->GetLevel() <= start->GetLevel()) + { + break; + } + + if (pc->Is(CT_OC_MSG_NAME) && pc->GetLevel() - 1 == start->GetLevel()) + { + newline_add_before(pc); + } + } +} // newline_oc_msg + + +static bool one_liner_nl_ok(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LNL1LINE, "%s(%d): check type is %s, parent is %s, flag is %s, orig line is %zu, orig col is %zu\n", + __func__, __LINE__, get_token_name(pc->GetType()), get_token_name(pc->GetParentType()), + pcf_flags_str(pc->GetFlags()).c_str(), pc->GetOrigLine(), pc->GetOrigCol()); + + if (!pc->TestFlags(PCF_ONE_LINER)) + { + LOG_FMT(LNL1LINE, "%s(%d): true (not 1-liner), a new line may be added\n", __func__, __LINE__); + return(true); + } + // Step back to find the opening brace + Chunk *br_open = pc; + + if (br_open->IsBraceClose()) + { + br_open = br_open->GetPrevType(br_open->Is(CT_BRACE_CLOSE) ? CT_BRACE_OPEN : CT_VBRACE_OPEN, + br_open->GetLevel(), E_Scope::ALL); + } + else + { + while ( br_open->IsNotNullChunk() + && br_open->TestFlags(PCF_ONE_LINER) + && !br_open->IsBraceOpen() + && !br_open->IsBraceClose()) + { + br_open = br_open->GetPrev(); + } + } + pc = br_open; + + if ( pc->IsNotNullChunk() + && pc->TestFlags(PCF_ONE_LINER) + && ( pc->IsBraceOpen() + || pc->IsBraceClose())) + { + log_rule_B("nl_class_leave_one_liners"); + + if ( options::nl_class_leave_one_liners() + && pc->TestFlags(PCF_IN_CLASS)) + { + LOG_FMT(LNL1LINE, "%s(%d): false (class)\n", __func__, __LINE__); + return(false); + } + log_rule_B("nl_assign_leave_one_liners"); + + if ( options::nl_assign_leave_one_liners() + && pc->GetParentType() == CT_ASSIGN) + { + LOG_FMT(LNL1LINE, "%s(%d): false (assign)\n", __func__, __LINE__); + return(false); + } + log_rule_B("nl_enum_leave_one_liners"); + + if ( options::nl_enum_leave_one_liners() + && pc->GetParentType() == CT_ENUM) + { + LOG_FMT(LNL1LINE, "%s(%d): false (enum)\n", __func__, __LINE__); + return(false); + } + log_rule_B("nl_getset_leave_one_liners"); + + if ( options::nl_getset_leave_one_liners() + && pc->GetParentType() == CT_GETSET) + { + LOG_FMT(LNL1LINE, "%s(%d): false (get/set), a new line may NOT be added\n", __func__, __LINE__); + return(false); + } + // Issue #UT-98 + log_rule_B("nl_cs_property_leave_one_liners"); + + if ( options::nl_cs_property_leave_one_liners() + && pc->GetParentType() == CT_CS_PROPERTY) + { + LOG_FMT(LNL1LINE, "%s(%d): false (c# property), a new line may NOT be added\n", __func__, __LINE__); + return(false); + } + log_rule_B("nl_func_leave_one_liners"); + + if ( options::nl_func_leave_one_liners() + && ( pc->GetParentType() == CT_FUNC_DEF + || pc->GetParentType() == CT_FUNC_CLASS_DEF)) + { + LOG_FMT(LNL1LINE, "%s(%d): false (func def)\n", __func__, __LINE__); + return(false); + } + log_rule_B("nl_func_leave_one_liners"); + + if ( options::nl_func_leave_one_liners() + && pc->GetParentType() == CT_OC_MSG_DECL) + { + LOG_FMT(LNL1LINE, "%s(%d): false (method def)\n", __func__, __LINE__); + return(false); + } + log_rule_B("nl_cpp_lambda_leave_one_liners"); + + if ( options::nl_cpp_lambda_leave_one_liners() + && ((pc->GetParentType() == CT_CPP_LAMBDA))) + { + LOG_FMT(LNL1LINE, "%s(%d): false (lambda)\n", __func__, __LINE__); + return(false); + } + log_rule_B("nl_oc_msg_leave_one_liner"); + + if ( options::nl_oc_msg_leave_one_liner() + && pc->TestFlags(PCF_IN_OC_MSG)) + { + LOG_FMT(LNL1LINE, "%s(%d): false (message)\n", __func__, __LINE__); + return(false); + } + log_rule_B("nl_if_leave_one_liners"); + + if ( options::nl_if_leave_one_liners() + && ( pc->GetParentType() == CT_IF + || pc->GetParentType() == CT_ELSEIF + || pc->GetParentType() == CT_ELSE)) + { + LOG_FMT(LNL1LINE, "%s(%d): false (if/else)\n", __func__, __LINE__); + return(false); + } + log_rule_B("nl_while_leave_one_liners"); + + if ( options::nl_while_leave_one_liners() + && pc->GetParentType() == CT_WHILE) + { + LOG_FMT(LNL1LINE, "%s(%d): false (while)\n", __func__, __LINE__); + return(false); + } + log_rule_B("nl_do_leave_one_liners"); + + if ( options::nl_do_leave_one_liners() + && pc->GetParentType() == CT_DO) + { + LOG_FMT(LNL1LINE, "%s(%d): false (do)\n", __func__, __LINE__); + return(false); + } + log_rule_B("nl_for_leave_one_liners"); + + if ( options::nl_for_leave_one_liners() + && pc->GetParentType() == CT_FOR) + { + LOG_FMT(LNL1LINE, "%s(%d): false (for)\n", __func__, __LINE__); + return(false); + } + log_rule_B("nl_namespace_two_to_one_liner - 2"); + + if ( options::nl_namespace_two_to_one_liner() + && pc->GetParentType() == CT_NAMESPACE) + { + LOG_FMT(LNL1LINE, "%s(%d): false (namespace)\n", __func__, __LINE__); + return(false); + } + } + LOG_FMT(LNL1LINE, "%s(%d): true, a new line may be added\n", __func__, __LINE__); + return(true); +} // one_liner_nl_ok + + +void undo_one_liner(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + if ( pc != nullptr + && pc->TestFlags(PCF_ONE_LINER)) + { + LOG_FMT(LNL1LINE, "%s(%d): pc->Text() '%s', orig line is %zu, orig col is %zu", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + pc->ResetFlagBits(PCF_ONE_LINER); + + // scan backward + LOG_FMT(LNL1LINE, "%s(%d): scan backward\n", __func__, __LINE__); + Chunk *tmp = pc; + + while ((tmp = tmp->GetPrev())->IsNotNullChunk()) + { + if (!tmp->TestFlags(PCF_ONE_LINER)) + { + LOG_FMT(LNL1LINE, "%s(%d): tmp->Text() '%s', orig line is %zu, orig col is %zu, --> break\n", + __func__, __LINE__, tmp->Text(), tmp->GetOrigLine(), tmp->GetOrigCol()); + break; + } + LOG_FMT(LNL1LINE, "%s(%d): clear for tmp->Text() '%s', orig line is %zu, orig col is %zu", + __func__, __LINE__, tmp->Text(), tmp->GetOrigLine(), tmp->GetOrigCol()); + tmp->ResetFlagBits(PCF_ONE_LINER); + } + // scan forward + LOG_FMT(LNL1LINE, "%s(%d): scan forward\n", __func__, __LINE__); + tmp = pc; + LOG_FMT(LNL1LINE, "%s(%d): - \n", __func__, __LINE__); + + while ((tmp = tmp->GetNext())->IsNotNullChunk()) + { + if (!tmp->TestFlags(PCF_ONE_LINER)) + { + LOG_FMT(LNL1LINE, "%s(%d): tmp->Text() '%s', orig line is %zu, orig col is %zu, --> break\n", + __func__, __LINE__, tmp->Text(), tmp->GetOrigLine(), tmp->GetOrigCol()); + break; + } + LOG_FMT(LNL1LINE, "%s(%d): clear for tmp->Text() '%s', orig line is %zu, orig col is %zu", + __func__, __LINE__, tmp->Text(), tmp->GetOrigLine(), tmp->GetOrigCol()); + tmp->ResetFlagBits(PCF_ONE_LINER); + } + LOG_FMT(LNL1LINE, "\n"); + } +} // undo_one_liner + + +static void nl_create_one_liner(Chunk *vbrace_open) +{ + LOG_FUNC_ENTRY(); + + // See if we get a newline between the next text and the vbrace_close + Chunk *tmp = vbrace_open->GetNextNcNnl(); + Chunk *first = tmp; + + if ( first->IsNullChunk() + || get_token_pattern_class(first->GetType()) != pattern_class_e::NONE) + { + return; + } + size_t nl_total = 0; + + while (tmp->IsNot(CT_VBRACE_CLOSE)) + { + if (tmp->IsNewline()) + { + nl_total += tmp->GetNlCount(); + + if (nl_total > 1) + { + return; + } + } + tmp = tmp->GetNext(); + } + + if ( tmp->IsNotNullChunk() + && first->IsNotNullChunk()) + { + newline_del_between(vbrace_open, first); + } +} // nl_create_one_liner + + +static void nl_create_list_liner(Chunk *brace_open) +{ + LOG_FUNC_ENTRY(); + + // See if we get a newline between the next text and the vbrace_close + if (brace_open == nullptr) + { + return; + } + Chunk *closing = brace_open->GetNextType(CT_BRACE_CLOSE, brace_open->GetLevel()); + Chunk *tmp = brace_open; + + do + { + if (tmp->Is(CT_COMMA)) + { + return; + } + tmp = tmp->GetNext(); + } while (tmp != closing); + + newline_del_between(brace_open, closing); +} // nl_create_list_liner + + +void newlines_remove_newlines() +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LBLANK, "%s(%d):\n", __func__, __LINE__); + Chunk *pc = Chunk::GetHead(); + + if (!pc->IsNewline()) + { + pc = pc->GetNextNl(); + } + Chunk *next; + Chunk *prev; + + while (pc->IsNotNullChunk()) + { + // Remove all newlines not in preproc + if (!pc->TestFlags(PCF_IN_PREPROC)) + { + next = pc->GetNext(); + prev = pc->GetPrev(); + newline_iarf(pc, IARF_REMOVE); + + if (next == Chunk::GetHead()) + { + pc = next; + continue; + } + else if ( prev->IsNotNullChunk() + && !prev->GetNext()->IsNewline()) + { + pc = prev; + } + } + pc = pc->GetNextNl(); + } +} // newlines_remove_newlines + + +void newlines_remove_disallowed() +{ + LOG_FUNC_ENTRY(); + + Chunk *pc = Chunk::GetHead(); + Chunk *next; + + while ((pc = pc->GetNextNl())->IsNotNullChunk()) + { + LOG_FMT(LBLANKD, "%s(%d): orig line is %zu, orig col is %zu, <Newline>, nl is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->GetNlCount()); + + next = pc->GetNext(); + + if ( next->IsNotNullChunk() + && !next->Is(CT_NEWLINE) + && !can_increase_nl(pc)) + { + LOG_FMT(LBLANKD, "%s(%d): force to 1 orig line is %zu, orig col is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + + if (pc->GetNlCount() != 1) + { + pc->SetNlCount(1); + MARK_CHANGE(); + } + } + } +} // newlines_remove_disallowed + + +void newlines_cleanup_angles() +{ + // Issue #1167 + LOG_FUNC_ENTRY(); + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + char copy[1000]; + LOG_FMT(LBLANK, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->ElidedText(copy)); + + if (pc->Is(CT_ANGLE_OPEN)) + { + newline_template(pc); + } + } +} // newlines_cleanup_angles + + +void newlines_cleanup_braces(bool first) +{ +//prot_the_line(__func__, __LINE__, 15, 4); + LOG_FUNC_ENTRY(); + + // Get the first token that's not an empty line: + Chunk *pc = Chunk::GetHead(); + + if (pc->IsNewline()) + { + pc = pc->GetNextNcNnl(); + } + + for ( ; pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { +//prot_the_line(__func__, __LINE__, 15, 4); + char copy[1000]; + LOG_FMT(LBLANK, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->ElidedText(copy)); + + if ( pc->Is(CT_IF) + || pc->Is(CT_CONSTEXPR)) + { + log_rule_B("nl_if_brace"); + newlines_if_for_while_switch(pc, options::nl_if_brace()); + } + else if (pc->Is(CT_ELSEIF)) + { + log_rule_B("nl_elseif_brace"); + iarf_e arg = options::nl_elseif_brace(); + log_rule_B("nl_if_brace"); + newlines_if_for_while_switch( + pc, (arg != IARF_IGNORE) ? arg : options::nl_if_brace()); + } + else if (pc->Is(CT_FOR)) + { + log_rule_B("nl_for_brace"); + newlines_if_for_while_switch(pc, options::nl_for_brace()); + } + else if (pc->Is(CT_CATCH)) + { + log_rule_B("nl_oc_brace_catch"); + + if ( language_is_set(LANG_OC) + && (pc->GetStr()[0] == '@') + && (options::nl_oc_brace_catch() != IARF_IGNORE)) + { + newlines_cuddle_uncuddle(pc, options::nl_oc_brace_catch()); + } + else + { + log_rule_B("nl_brace_catch"); + newlines_cuddle_uncuddle(pc, options::nl_brace_catch()); + } + Chunk *next = pc->GetNextNcNnl(); + + if (next->Is(CT_BRACE_OPEN)) + { + log_rule_B("nl_oc_catch_brace"); + + if ( language_is_set(LANG_OC) + && (options::nl_oc_catch_brace() != IARF_IGNORE)) + { + log_rule_B("nl_oc_catch_brace"); + newlines_do_else(pc, options::nl_oc_catch_brace()); + } + else + { + log_rule_B("nl_catch_brace"); + newlines_do_else(pc, options::nl_catch_brace()); + } + } + else + { + log_rule_B("nl_oc_catch_brace"); + + if ( language_is_set(LANG_OC) + && (options::nl_oc_catch_brace() != IARF_IGNORE)) + { + newlines_if_for_while_switch(pc, options::nl_oc_catch_brace()); + } + else + { + log_rule_B("nl_catch_brace"); + newlines_if_for_while_switch(pc, options::nl_catch_brace()); + } + } + } + else if (pc->Is(CT_WHILE)) + { + log_rule_B("nl_while_brace"); + newlines_if_for_while_switch(pc, options::nl_while_brace()); + } + else if (pc->Is(CT_USING_STMT)) + { + log_rule_B("nl_using_brace"); + newlines_if_for_while_switch(pc, options::nl_using_brace()); + } + else if (pc->Is(CT_D_SCOPE_IF)) + { + log_rule_B("nl_scope_brace"); + newlines_if_for_while_switch(pc, options::nl_scope_brace()); + } + else if (pc->Is(CT_UNITTEST)) + { + log_rule_B("nl_unittest_brace"); + newlines_do_else(pc, options::nl_unittest_brace()); + } + else if (pc->Is(CT_D_VERSION_IF)) + { + log_rule_B("nl_version_brace"); + newlines_if_for_while_switch(pc, options::nl_version_brace()); + } + else if (pc->Is(CT_SWITCH)) + { + log_rule_B("nl_switch_brace"); + newlines_if_for_while_switch(pc, options::nl_switch_brace()); + } + else if (pc->Is(CT_SYNCHRONIZED)) + { + log_rule_B("nl_synchronized_brace"); + newlines_if_for_while_switch(pc, options::nl_synchronized_brace()); + } + else if (pc->Is(CT_DO)) + { + log_rule_B("nl_do_brace"); + newlines_do_else(pc, options::nl_do_brace()); + } + else if (pc->Is(CT_ELSE)) + { + log_rule_B("nl_brace_else"); + newlines_cuddle_uncuddle(pc, options::nl_brace_else()); + Chunk *next = pc->GetNextNcNnl(); + + if (next->Is(CT_ELSEIF)) + { + log_rule_B("nl_else_if"); + newline_iarf_pair(pc, next, options::nl_else_if()); + } + log_rule_B("nl_else_brace"); + newlines_do_else(pc, options::nl_else_brace()); + } + else if (pc->Is(CT_TRY)) + { + log_rule_B("nl_try_brace"); + newlines_do_else(pc, options::nl_try_brace()); + // Issue #1734 + Chunk *po = pc->GetNextNcNnl(); + flag_parens(po, PCF_IN_TRY_BLOCK, po->GetType(), CT_NONE, false); + } + else if (pc->Is(CT_GETSET)) + { + log_rule_B("nl_getset_brace"); + newlines_do_else(pc, options::nl_getset_brace()); + } + else if (pc->Is(CT_FINALLY)) + { + log_rule_B("nl_brace_finally"); + newlines_cuddle_uncuddle(pc, options::nl_brace_finally()); + log_rule_B("nl_finally_brace"); + newlines_do_else(pc, options::nl_finally_brace()); + } + else if (pc->Is(CT_WHILE_OF_DO)) + { + log_rule_B("nl_brace_while"); + newlines_cuddle_uncuddle(pc, options::nl_brace_while()); + } + else if (pc->Is(CT_BRACE_OPEN)) + { + switch (pc->GetParentType()) + { + case CT_DOUBLE_BRACE: + { + log_rule_B("nl_paren_dbrace_open"); + + if (options::nl_paren_dbrace_open() != IARF_IGNORE) + { + Chunk *prev = pc->GetPrevNcNnlNi(E_Scope::PREPROC); // Issue #2279 + + if (prev->IsParenClose()) + { + log_rule_B("nl_paren_dbrace_open"); + newline_iarf_pair(prev, pc, options::nl_paren_dbrace_open()); + } + } + break; + } + + case CT_ENUM: + { + log_rule_B("nl_enum_own_lines"); + + if (options::nl_enum_own_lines() != IARF_IGNORE) + { + newlines_enum_entries(pc, options::nl_enum_own_lines()); + } + log_rule_B("nl_ds_struct_enum_cmt"); + + if (options::nl_ds_struct_enum_cmt()) + { + newlines_double_space_struct_enum_union(pc); + } + break; + } + + case CT_STRUCT: + case CT_UNION: + { + log_rule_B("nl_ds_struct_enum_cmt"); + + if (options::nl_ds_struct_enum_cmt()) + { + newlines_double_space_struct_enum_union(pc); + } + break; + } + + case CT_CLASS: + { + if (pc->GetLevel() == pc->GetBraceLevel()) + { + log_rule_B("nl_class_brace"); + log_ruleNL("nl_class_brace", pc->GetPrevNnl()); + newlines_do_else(pc->GetPrevNnl(), options::nl_class_brace()); + } + break; + } + + case CT_OC_CLASS: + { + if (pc->GetLevel() == pc->GetBraceLevel()) + { + // Request #126 + // introduce two new options + // look back if we have a @interface or a @implementation + for (Chunk *tmp = pc->GetPrev(); tmp->IsNotNullChunk(); tmp = tmp->GetPrev()) + { + LOG_FMT(LBLANK, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, tmp->GetOrigLine(), tmp->GetOrigCol(), tmp->Text()); + + if ( tmp->Is(CT_OC_INTF) + || tmp->Is(CT_OC_IMPL)) + { + LOG_FMT(LBLANK, "%s(%d): orig line is %zu, orig col is %zu, may be remove/force newline before {\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + + if (tmp->Is(CT_OC_INTF)) + { + log_rule_B("nl_oc_interface_brace"); + newlines_do_else(pc->GetPrevNnl(), options::nl_oc_interface_brace()); + } + else + { + log_rule_B("nl_oc_implementation_brace"); + newlines_do_else(pc->GetPrevNnl(), options::nl_oc_implementation_brace()); + } + break; + } + } + } + break; + } + + case CT_BRACED_INIT_LIST: + { + // Issue #1052 + log_rule_B("nl_create_list_one_liner"); + + if (options::nl_create_list_one_liner()) + { + nl_create_list_liner(pc); + break; + } + Chunk *prev = pc->GetPrevNnl(); + + if ( prev->IsNotNullChunk() + && ( prev->GetType() == CT_TYPE + || prev->GetType() == CT_WORD + || prev->GetType() == CT_ASSIGN // Issue #2957 + || prev->GetParentType() == CT_TEMPLATE + || prev->GetParentType() == CT_DECLTYPE)) + { + log_rule_B("nl_type_brace_init_lst"); + newline_iarf_pair(prev, pc, options::nl_type_brace_init_lst(), true); + } + break; + } + + case CT_OC_BLOCK_EXPR: + { + // issue # 477 + log_rule_B("nl_oc_block_brace"); + newline_iarf_pair(pc->GetPrev(), pc, options::nl_oc_block_brace()); + break; + } + + case CT_FUNC_CLASS_DEF: // Issue #2343 + { + if (!one_liner_nl_ok(pc)) + { + LOG_FMT(LNL1LINE, "a new line may NOT be added\n"); + // no change - preserve one liner body + } + else + { + log_rule_B("nl_before_opening_brace_func_class_def"); + + if (options::nl_before_opening_brace_func_class_def() != IARF_IGNORE) + { + newline_iarf_pair(pc->GetPrev(), pc, options::nl_before_opening_brace_func_class_def()); + } + } + } + + default: + { + break; + } + } // switch + + log_rule_B("nl_brace_brace"); + + if (options::nl_brace_brace() != IARF_IGNORE) + { + Chunk *next = pc->GetNextNc(E_Scope::PREPROC); + + if (next->Is(CT_BRACE_OPEN)) + { + newline_iarf_pair(pc, next, options::nl_brace_brace()); + } + } + Chunk *next = pc->GetNextNnl(); + + if (next->IsNullChunk()) + { + // do nothing + } + else if (next->Is(CT_BRACE_CLOSE)) + { + // TODO: add an option to split open empty statements? { }; + } + else if (next->Is(CT_BRACE_OPEN)) + { + // already handled + } + else + { + next = pc->GetNextNcNnl(); + + // Handle unnamed temporary direct-list-initialization + if (pc->GetParentType() == CT_BRACED_INIT_LIST) + { + log_rule_B("nl_type_brace_init_lst_open"); + newline_iarf_pair(pc, pc->GetNextNnl(), + options::nl_type_brace_init_lst_open(), true); + } + // Handle nl_after_brace_open + else if ( ( pc->GetParentType() == CT_CPP_LAMBDA + || pc->GetLevel() == pc->GetBraceLevel()) + && options::nl_after_brace_open()) + { + log_rule_B("nl_after_brace_open"); + + if (!one_liner_nl_ok(pc)) + { + LOG_FMT(LNL1LINE, "a new line may NOT be added (nl_after_brace_open)\n"); + // no change - preserve one liner body + } + else if ( pc->TestFlags(PCF_IN_ARRAY_ASSIGN) + || pc->TestFlags(PCF_IN_PREPROC)) + { + // no change - don't break up array assignments or preprocessors + } + else + { + // Step back from next to the first non-newline item + Chunk *tmp = next->GetPrev(); + + while (tmp != pc) + { + if (tmp->IsComment()) + { + log_rule_B("nl_after_brace_open_cmt"); + + if ( !options::nl_after_brace_open_cmt() + && tmp->IsNot(CT_COMMENT_MULTI)) + { + break; + } + } + tmp = tmp->GetPrev(); + } + // Add the newline + newline_iarf(tmp, IARF_ADD); + } + } + } + // braced-init-list is more like a function call with arguments, + // than curly braces that determine a structure of a source code, + // so, don't add a newline before a closing brace. Issue #1405. + log_rule_B("nl_type_brace_init_lst_open"); + log_rule_B("nl_type_brace_init_lst_close"); + + if (!( pc->GetParentType() == CT_BRACED_INIT_LIST + && options::nl_type_brace_init_lst_open() == IARF_IGNORE + && options::nl_type_brace_init_lst_close() == IARF_IGNORE)) + { + newlines_brace_pair(pc); + } + + // Handle nl_before_brace_open + if ( pc->Is(CT_BRACE_OPEN) + && pc->GetLevel() == pc->GetBraceLevel() + && options::nl_before_brace_open()) + { + log_rule_B("nl_before_brace_open"); + + if (!one_liner_nl_ok(pc)) + { + LOG_FMT(LNL1LINE, "a new line may NOT be added (nl_before_brace_open)\n"); + // no change - preserve one liner body + } + else if ( pc->TestFlags(PCF_IN_PREPROC) + || pc->TestFlags(PCF_IN_ARRAY_ASSIGN)) + { + // no change - don't break up array assignments or preprocessors + } + else + { + // Step back to previous non-newline item + Chunk *tmp = pc->GetPrev(); + + if (!tmp->Is(CT_NEWLINE)) + { + newline_iarf(tmp, IARF_ADD); + } + } + } + } + else if (pc->Is(CT_BRACE_CLOSE)) + { + // newline between a close brace and x + log_rule_B("nl_brace_brace"); + + if (options::nl_brace_brace() != IARF_IGNORE) + { + Chunk *next = pc->GetNextNc(E_Scope::PREPROC); + + if (next->Is(CT_BRACE_CLOSE)) + { + log_rule_B("nl_brace_brace"); + newline_iarf_pair(pc, next, options::nl_brace_brace()); + } + } + log_rule_B("nl_brace_square"); + + if (options::nl_brace_square() != IARF_IGNORE) + { + Chunk *next = pc->GetNextNc(E_Scope::PREPROC); + + if (next->Is(CT_SQUARE_CLOSE)) + { + log_rule_B("nl_brace_square"); + newline_iarf_pair(pc, next, options::nl_brace_square()); + } + } + log_rule_B("nl_brace_fparen"); + + if (options::nl_brace_fparen() != IARF_IGNORE) + { + Chunk *next = pc->GetNextNc(E_Scope::PREPROC); + + log_rule_B("nl_brace_fparen"); + + if ( next->Is(CT_NEWLINE) + && (options::nl_brace_fparen() == IARF_REMOVE)) + { + next = next->GetNextNc(E_Scope::PREPROC); // Issue #1000 + } + + if (next->Is(CT_FPAREN_CLOSE)) + { + log_rule_B("nl_brace_fparen"); + newline_iarf_pair(pc, next, options::nl_brace_fparen()); + } + } + // newline before a close brace + log_rule_B("nl_type_brace_init_lst_close"); + + if ( pc->GetParentType() == CT_BRACED_INIT_LIST + && options::nl_type_brace_init_lst_close() != IARF_IGNORE) + { + // Handle unnamed temporary direct-list-initialization + newline_iarf_pair(pc->GetPrevNnl(), pc, + options::nl_type_brace_init_lst_close(), true); + } + // blanks before a close brace + log_rule_B("eat_blanks_before_close_brace"); + + if (options::eat_blanks_before_close_brace()) + { + // Limit the newlines before the close brace to 1 + Chunk *prev = pc->GetPrev(); + + if (prev->IsNewline()) + { + log_rule_B("nl_inside_namespace"); + log_rule_B("nl_inside_empty_func"); + + if ( options::nl_inside_empty_func() > 0 + && pc->GetPrevNnl()->Is(CT_BRACE_OPEN) + && ( pc->GetParentType() == CT_FUNC_CLASS_DEF + || pc->GetParentType() == CT_FUNC_DEF)) + { + blank_line_set(prev, options::nl_inside_empty_func); + } + else if ( options::nl_inside_namespace() > 0 + && pc->GetParentType() == CT_NAMESPACE) + { + blank_line_set(prev, options::nl_inside_namespace); + } + else if (prev->GetNlCount() != 1) + { + prev->SetNlCount(1); + LOG_FMT(LBLANKD, "%s(%d): eat_blanks_before_close_brace %zu\n", + __func__, __LINE__, prev->GetOrigLine()); + MARK_CHANGE(); + } + } + } + else if ( options::nl_ds_struct_enum_close_brace() + && ( pc->GetParentType() == CT_ENUM + || pc->GetParentType() == CT_STRUCT + || pc->GetParentType() == CT_UNION)) + { + log_rule_B("nl_ds_struct_enum_close_brace"); + + if (!pc->TestFlags(PCF_ONE_LINER)) + { + // Make sure the brace is preceded by two newlines + Chunk *prev = pc->GetPrev(); + + if (!prev->IsNewline()) + { + prev = newline_add_before(pc); + } + + if (prev->GetNlCount() < 2) + { + double_newline(prev); + } + } + } + // Force a newline after a close brace + log_rule_B("nl_brace_struct_var"); + + if ( (options::nl_brace_struct_var() != IARF_IGNORE) + && ( pc->GetParentType() == CT_STRUCT + || pc->GetParentType() == CT_ENUM + || pc->GetParentType() == CT_UNION)) + { + Chunk *next = pc->GetNextNcNnl(E_Scope::PREPROC); + + if ( next->IsNot(CT_SEMICOLON) + && next->IsNot(CT_COMMA)) + { + log_rule_B("nl_brace_struct_var"); + newline_iarf(pc, options::nl_brace_struct_var()); + } + } + else if ( pc->GetParentType() != CT_OC_AT + && pc->GetParentType() != CT_BRACED_INIT_LIST + && ( options::nl_after_brace_close() + || pc->GetParentType() == CT_FUNC_CLASS_DEF + || pc->GetParentType() == CT_FUNC_DEF + || pc->GetParentType() == CT_OC_MSG_DECL)) + { + log_rule_B("nl_after_brace_close"); + Chunk *next = pc->GetNext(); + + if ( next->IsNot(CT_SEMICOLON) + && next->IsNot(CT_COMMA) + && next->IsNot(CT_SPAREN_CLOSE) // Issue #664 + && next->IsNot(CT_SQUARE_CLOSE) + && next->IsNot(CT_FPAREN_CLOSE) + && next->IsNot(CT_PAREN_CLOSE) + && next->IsNot(CT_WHILE_OF_DO) + && next->IsNot(CT_VBRACE_CLOSE) // Issue #666 + && ( next->IsNot(CT_BRACE_CLOSE) + || !next->TestFlags(PCF_ONE_LINER)) // #1258 + && !pc->TestFlags(PCF_IN_ARRAY_ASSIGN) + && !pc->TestFlags(PCF_IN_TYPEDEF) + && !next->IsCommentOrNewline() + && next->IsNotNullChunk()) + { + // #1258 + // dont add newline between two consecutive braces closes, if the second is a part of one liner. + newline_end_newline(pc); + } + } + else if (pc->GetParentType() == CT_NAMESPACE) + { + log_rule_B("nl_after_namespace"); + + if (options::nl_after_namespace() > 0) + { + Chunk *next = pc->GetNextNcNnl(E_Scope::PREPROC); + + if (next->IsNotNullChunk()) + { + newline_add_before(next); + // newline_iarf(next, IARF_ADD); + } + } + } + } + else if (pc->Is(CT_VBRACE_OPEN)) + { + log_rule_B("nl_after_vbrace_open"); + log_rule_B("nl_after_vbrace_open_empty"); + + if ( options::nl_after_vbrace_open() + || options::nl_after_vbrace_open_empty()) + { + Chunk *next = pc->GetNext(E_Scope::PREPROC); + bool add_it; + + if (next->IsSemicolon()) + { + log_rule_B("nl_after_vbrace_open_empty"); + add_it = options::nl_after_vbrace_open_empty(); + } + else + { + log_rule_B("nl_after_vbrace_open"); + add_it = ( options::nl_after_vbrace_open() + && next->IsNot(CT_VBRACE_CLOSE) + && !next->IsCommentOrNewline()); + } + + if (add_it) + { + newline_iarf(pc, IARF_ADD); + } + } + log_rule_B("nl_create_if_one_liner"); + log_rule_B("nl_create_for_one_liner"); + log_rule_B("nl_create_while_one_liner"); + + if ( ( ( pc->GetParentType() == CT_IF + || pc->GetParentType() == CT_ELSEIF + || pc->GetParentType() == CT_ELSE) + && options::nl_create_if_one_liner()) + || ( pc->GetParentType() == CT_FOR + && options::nl_create_for_one_liner()) + || ( pc->GetParentType() == CT_WHILE + && options::nl_create_while_one_liner())) + { + nl_create_one_liner(pc); + } + log_rule_B("nl_split_if_one_liner"); + log_rule_B("nl_split_for_one_liner"); + log_rule_B("nl_split_while_one_liner"); + + if ( ( ( pc->GetParentType() == CT_IF + || pc->GetParentType() == CT_ELSEIF + || pc->GetParentType() == CT_ELSE) + && options::nl_split_if_one_liner()) + || ( pc->GetParentType() == CT_FOR + && options::nl_split_for_one_liner()) + || ( pc->GetParentType() == CT_WHILE + && options::nl_split_while_one_liner())) + { + if (pc->TestFlags(PCF_ONE_LINER)) + { + // split one-liner + Chunk *end = pc->GetNext()->GetNextType(CT_SEMICOLON)->GetNext(); + // Scan for clear flag + LOG_FMT(LNEWLINE, "(%d) ", __LINE__); + LOG_FMT(LNEWLINE, "\n"); + + for (Chunk *temp = pc; temp != end; temp = temp->GetNext()) + { + LOG_FMT(LNEWLINE, "%s(%d): Text() is '%s', type is %s, level is %zu\n", + __func__, __LINE__, temp->Text(), get_token_name(temp->GetType()), temp->GetLevel()); + // produces much more log output. Use it only debugging purpose + //log_pcf_flags(LNEWLINE, temp->GetFlags()); + temp->ResetFlagBits(PCF_ONE_LINER); + } + + // split + newline_add_between(pc, pc->GetNext()); + } + } + } + else if (pc->Is(CT_VBRACE_CLOSE)) + { + log_rule_B("nl_after_vbrace_close"); + + if (options::nl_after_vbrace_close()) + { + if (!pc->GetNextNc()->IsNewline()) + { + newline_iarf(pc, IARF_ADD); + } + } + } + else if ( pc->Is(CT_SQUARE_OPEN) + && pc->GetParentType() == CT_OC_MSG) + { + log_rule_B("nl_oc_msg_args"); + + if (options::nl_oc_msg_args()) + { + newline_oc_msg(pc); + } + } + else if (pc->Is(CT_STRUCT)) + { + log_rule_B("nl_struct_brace"); + newlines_struct_union(pc, options::nl_struct_brace(), true); + } + else if (pc->Is(CT_UNION)) + { + log_rule_B("nl_union_brace"); + newlines_struct_union(pc, options::nl_union_brace(), true); + } + else if (pc->Is(CT_ENUM)) + { + newlines_enum(pc); + } + else if (pc->Is(CT_CASE)) + { + // Note: 'default' also maps to CT_CASE + log_rule_B("nl_before_case"); + + if (options::nl_before_case()) + { + newline_case(pc); + } + } + else if (pc->Is(CT_THROW)) + { + Chunk *prev = pc->GetPrev(); + + if ( prev->Is(CT_PAREN_CLOSE) + || prev->Is(CT_FPAREN_CLOSE)) // Issue #1122 + { + log_rule_B("nl_before_throw"); + newline_iarf(pc->GetPrevNcNnlNi(), options::nl_before_throw()); // Issue #2279 + } + } + else if ( pc->Is(CT_QUALIFIER) + && !strcmp(pc->Text(), "throws")) + { + Chunk *prev = pc->GetPrev(); + + if ( prev->Is(CT_PAREN_CLOSE) + || prev->Is(CT_FPAREN_CLOSE)) // Issue #1122 + { + log_rule_B("nl_before_throw"); + newline_iarf(pc->GetPrevNcNnlNi(), options::nl_before_throw()); // Issue #2279 + } + } + else if (pc->Is(CT_CASE_COLON)) + { + Chunk *next = pc->GetNextNnl(); + + log_rule_B("nl_case_colon_brace"); + + if ( next->Is(CT_BRACE_OPEN) + && options::nl_case_colon_brace() != IARF_IGNORE) + { + newline_iarf(pc, options::nl_case_colon_brace()); + } + else if (options::nl_after_case()) + { + log_rule_B("nl_after_case"); + newline_case_colon(pc); + } + } + else if (pc->Is(CT_SPAREN_CLOSE)) + { + Chunk *next = pc->GetNextNcNnl(); + + if (next->Is(CT_BRACE_OPEN)) + { + /* + * TODO: this could be used to control newlines between the + * the if/while/for/switch close parenthesis and the open brace, but + * that is currently handled elsewhere. + */ + } + } + else if (pc->Is(CT_RETURN)) + { + log_rule_B("nl_before_return"); + + if (options::nl_before_return()) + { + newline_before_return(pc); + } + log_rule_B("nl_after_return"); + + if (options::nl_after_return()) + { + newline_after_return(pc); + } + } + else if (pc->Is(CT_SEMICOLON)) + { + log_rule_B("nl_after_semicolon"); + log_rule_NL("nl_after_semicolon"); + + if ( !pc->TestFlags(PCF_IN_SPAREN) + && !pc->TestFlags(PCF_IN_PREPROC) + && options::nl_after_semicolon()) + { + Chunk *next = pc->GetNext(); + + while (next->Is(CT_VBRACE_CLOSE)) + { + next = next->GetNext(); + } + + if ( next->IsNotNullChunk() + && !next->IsCommentOrNewline()) + { + if (one_liner_nl_ok(next)) + { + LOG_FMT(LNL1LINE, "%s(%d): a new line may be added\n", __func__, __LINE__); + newline_iarf(pc, IARF_ADD); + } + else + { + LOG_FMT(LNL1LINE, "%s(%d): a new line may NOT be added\n", __func__, __LINE__); + } + } + } + else if (pc->GetParentType() == CT_CLASS) + { + log_rule_B("nl_after_class"); + + if (options::nl_after_class() > 0) + { + /* + * If there is already a "class" comment, then don't add a newline if + * one exists after the comment. or else this will interfere with the + * mod_add_long_class_closebrace_comment option. + */ + iarf_e mode = IARF_ADD; + Chunk *next = pc->GetNext(); + + if (next->IsComment()) + { + pc = next; + next = pc->GetNext(); + + if (next->IsNewline()) + { + mode = IARF_IGNORE; + } + } + newline_iarf(pc, mode); + } + } + } + else if (pc->Is(CT_FPAREN_OPEN)) + { + log_rule_B("nl_func_decl_start"); + log_rule_B("nl_func_def_start"); + log_rule_B("nl_func_decl_start_single"); + log_rule_B("nl_func_def_start_single"); + log_rule_B("nl_func_decl_start_multi_line"); + log_rule_B("nl_func_def_start_multi_line"); + log_rule_B("nl_func_decl_args"); + log_rule_B("nl_func_def_args"); + log_rule_B("nl_func_decl_args_multi_line"); + log_rule_B("nl_func_def_args_multi_line"); + log_rule_B("nl_func_decl_end"); + log_rule_B("nl_func_def_end"); + log_rule_B("nl_func_decl_end_single"); + log_rule_B("nl_func_def_end_single"); + log_rule_B("nl_func_decl_end_multi_line"); + log_rule_B("nl_func_def_end_multi_line"); + log_rule_B("nl_func_decl_empty"); + log_rule_B("nl_func_def_empty"); + log_rule_B("nl_func_type_name"); + log_rule_B("nl_func_type_name_class"); + log_rule_B("nl_func_class_scope"); + log_rule_B("nl_func_scope_name"); + log_rule_B("nl_func_proto_type_name"); + log_rule_B("nl_func_paren"); + log_rule_B("nl_func_def_paren"); + log_rule_B("nl_func_def_paren_empty"); + log_rule_B("nl_func_paren_empty"); + + if ( ( pc->GetParentType() == CT_FUNC_DEF + || pc->GetParentType() == CT_FUNC_PROTO + || pc->GetParentType() == CT_FUNC_CLASS_DEF + || pc->GetParentType() == CT_FUNC_CLASS_PROTO + || pc->GetParentType() == CT_OPERATOR) + && ( options::nl_func_decl_start() != IARF_IGNORE + || options::nl_func_def_start() != IARF_IGNORE + || options::nl_func_decl_start_single() != IARF_IGNORE + || options::nl_func_def_start_single() != IARF_IGNORE + || options::nl_func_decl_start_multi_line() + || options::nl_func_def_start_multi_line() + || options::nl_func_decl_args() != IARF_IGNORE + || options::nl_func_def_args() != IARF_IGNORE + || options::nl_func_decl_args_multi_line() + || options::nl_func_def_args_multi_line() + || options::nl_func_decl_end() != IARF_IGNORE + || options::nl_func_def_end() != IARF_IGNORE + || options::nl_func_decl_end_single() != IARF_IGNORE + || options::nl_func_def_end_single() != IARF_IGNORE + || options::nl_func_decl_end_multi_line() + || options::nl_func_def_end_multi_line() + || options::nl_func_decl_empty() != IARF_IGNORE + || options::nl_func_def_empty() != IARF_IGNORE + || options::nl_func_type_name() != IARF_IGNORE + || options::nl_func_type_name_class() != IARF_IGNORE + || options::nl_func_class_scope() != IARF_IGNORE + || options::nl_func_scope_name() != IARF_IGNORE + || options::nl_func_proto_type_name() != IARF_IGNORE + || options::nl_func_paren() != IARF_IGNORE + || options::nl_func_def_paren() != IARF_IGNORE + || options::nl_func_def_paren_empty() != IARF_IGNORE + || options::nl_func_paren_empty() != IARF_IGNORE)) + { + newline_func_def_or_call(pc); + } + else if ( ( pc->GetParentType() == CT_FUNC_CALL + || pc->GetParentType() == CT_FUNC_CALL_USER) + && ( (options::nl_func_call_start_multi_line()) + || (options::nl_func_call_args_multi_line()) + || (options::nl_func_call_end_multi_line()) + || (options::nl_func_call_start() != IARF_IGNORE) // Issue #2020 + || (options::nl_func_call_args() != IARF_IGNORE) // Issue #2604 + || (options::nl_func_call_paren() != IARF_IGNORE) + || (options::nl_func_call_paren_empty() != IARF_IGNORE) + || (options::nl_func_call_empty() != IARF_IGNORE))) + { + log_rule_B("nl_func_call_start_multi_line"); + log_rule_B("nl_func_call_args_multi_line"); + log_rule_B("nl_func_call_end_multi_line"); + log_rule_B("nl_func_call_start"); + log_rule_B("nl_func_call_args"); + log_rule_B("nl_func_call_paren"); + log_rule_B("nl_func_call_paren_empty"); + log_rule_B("nl_func_call_empty"); + + if (options::nl_func_call_start() != IARF_IGNORE) + { + newline_iarf(pc, options::nl_func_call_start()); + } + // note that newline_func_def_or_call() calls newline_func_multi_line() + newline_func_def_or_call(pc); + } + else if ( first + && (options::nl_remove_extra_newlines() == 1)) + { + log_rule_B("nl_remove_extra_newlines"); + newline_iarf(pc, IARF_REMOVE); + } + } + else if (pc->Is(CT_FPAREN_CLOSE)) // Issue #2758 + { + if ( ( pc->GetParentType() == CT_FUNC_CALL + || pc->GetParentType() == CT_FUNC_CALL_USER) + && options::nl_func_call_end() != IARF_IGNORE) + { + log_rule_B("nl_func_call_end"); + newline_iarf(pc->GetPrev(), options::nl_func_call_end()); + } + } + else if (pc->Is(CT_ANGLE_CLOSE)) + { + if (pc->GetParentType() == CT_TEMPLATE) + { + Chunk *next = pc->GetNextNcNnl(); + + if ( next->IsNotNullChunk() + && next->GetLevel() == next->GetBraceLevel()) + { + Chunk *tmp = pc->GetPrevType(CT_ANGLE_OPEN, pc->GetLevel())->GetPrevNcNnlNi(); // Issue #2279 + + if (tmp->Is(CT_TEMPLATE)) + { + if (next->Is(CT_USING)) + { + newline_iarf(pc, options::nl_template_using()); + log_rule_B("nl_template_using"); + } + else if (next->GetParentType() == CT_FUNC_DEF) // function definition + { + iarf_e const action = + newline_template_option( + pc, + options::nl_template_func_def_special(), + options::nl_template_func_def(), + options::nl_template_func()); + log_rule_B("nl_template_func_def_special"); + log_rule_B("nl_template_func_def"); + log_rule_B("nl_template_func"); + newline_iarf(pc, action); + } + else if (next->GetParentType() == CT_FUNC_PROTO) // function declaration + { + iarf_e const action = + newline_template_option( + pc, + options::nl_template_func_decl_special(), + options::nl_template_func_decl(), + options::nl_template_func()); + log_rule_B("nl_template_func_decl_special"); + log_rule_B("nl_template_func_decl"); + log_rule_B("nl_template_func"); + newline_iarf(pc, action); + } + else if ( next->Is(CT_TYPE) + || next->Is(CT_QUALIFIER)) // variable + { + newline_iarf(pc, options::nl_template_var()); + log_rule_B("nl_template_var"); + } + else if (next->TestFlags(PCF_INCOMPLETE)) // class declaration + { + iarf_e const action = + newline_template_option( + pc, + options::nl_template_class_decl_special(), + options::nl_template_class_decl(), + options::nl_template_class()); + log_rule_B("nl_template_class_decl_special"); + log_rule_B("nl_template_class_decl"); + log_rule_B("nl_template_class"); + newline_iarf(pc, action); + } + else // class definition + { + iarf_e const action = + newline_template_option( + pc, + options::nl_template_class_def_special(), + options::nl_template_class_def(), + options::nl_template_class()); + log_rule_B("nl_template_class_def_special"); + log_rule_B("nl_template_class_def"); + log_rule_B("nl_template_class"); + newline_iarf(pc, action); + } + } + } + } + } + else if ( pc->Is(CT_NAMESPACE) + && pc->GetParentType() != CT_USING) + { + // Issue #2387 + Chunk *next = pc->GetNextNcNnl(); + + if (next->IsNotNullChunk()) + { + next = next->GetNextNcNnl(); + + if (!next->Is(CT_ASSIGN)) + { + // Issue #1235 + // Issue #2186 + Chunk *braceOpen = pc->GetNextType(CT_BRACE_OPEN, pc->GetLevel()); + + if (braceOpen->IsNullChunk()) + { + // fatal error + LOG_FMT(LERR, "%s(%d): Missing BRACE_OPEN after namespace\n orig line is %zu, orig col is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + exit(EXIT_FAILURE); + } + LOG_FMT(LNEWLINE, "%s(%d): braceOpen orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, braceOpen->GetOrigLine(), braceOpen->GetOrigCol(), braceOpen->Text()); + // produces much more log output. Use it only debugging purpose + //log_pcf_flags(LNEWLINE, braceOpen->GetFlags()); + newlines_namespace(pc); + } + } + } + else if (pc->Is(CT_SQUARE_OPEN)) + { + if ( pc->GetParentType() == CT_ASSIGN + && !pc->TestFlags(PCF_ONE_LINER)) + { + Chunk *tmp = pc->GetPrevNcNnlNi(); // Issue #2279 + newline_iarf(tmp, options::nl_assign_square()); + log_rule_B("nl_assign_square"); + + iarf_e arg = options::nl_after_square_assign(); + log_rule_B("nl_after_square_assign"); + + if (options::nl_assign_square() & IARF_ADD) + { + log_rule_B("nl_assign_square"); + arg = IARF_ADD; + } + newline_iarf(pc, arg); + + /* + * if there is a newline after the open, then force a newline + * before the close + */ + tmp = pc->GetNextNc(); + + if (tmp->IsNewline()) + { + tmp = pc->GetNextType(CT_SQUARE_CLOSE, pc->GetLevel()); + + if (tmp->IsNotNullChunk()) + { + newline_add_before(tmp); + } + } + } + } + else if (pc->Is(CT_ACCESS)) + { + // Make sure there is a newline before an access spec + if (options::nl_before_access_spec() > 0) + { + log_rule_B("nl_before_access_spec"); + Chunk *prev = pc->GetPrev(); + + if (!prev->IsNewline()) + { + newline_add_before(pc); + } + } + } + else if (pc->Is(CT_ACCESS_COLON)) + { + // Make sure there is a newline after an access spec + if (options::nl_after_access_spec() > 0) + { + log_rule_B("nl_after_access_spec"); + Chunk *next = pc->GetNext(); + + if (!next->IsNewline()) + { + newline_add_before(next); + } + } + } + else if (pc->Is(CT_PP_DEFINE)) + { + if (options::nl_multi_line_define()) + { + log_rule_B("nl_multi_line_define"); + nl_handle_define(pc); + } + } + else if ( first + && (options::nl_remove_extra_newlines() == 1) + && !pc->TestFlags(PCF_IN_PREPROC)) + { + log_rule_B("nl_remove_extra_newlines"); + log_rule_NL("nl_remove_extra_newlines"); + newline_iarf(pc, IARF_REMOVE); + } + else if ( pc->Is(CT_MEMBER) + && ( language_is_set(LANG_JAVA) + || language_is_set(LANG_CPP))) // Issue #2574 + { + // Issue #1124 + if (pc->GetParentType() != CT_FUNC_DEF) + { + newline_iarf(pc->GetPrevNnl(), options::nl_before_member()); + log_rule_B("nl_before_member"); + newline_iarf(pc, options::nl_after_member()); + log_rule_B("nl_after_member"); + } + } + else + { + // ignore it + } + } + +//prot_the_line(__func__, __LINE__, 15, 4); + newline_var_def_blk(Chunk::GetHead()); +//prot_the_line(__func__, __LINE__, 15, 4); +} // newlines_cleanup_braces + + +static void nl_handle_define(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + Chunk *nl = pc; + Chunk *ref = Chunk::NullChunkPtr; + + while ((nl = nl->GetNext())->IsNotNullChunk()) + { + if (nl->Is(CT_NEWLINE)) + { + return; + } + + if ( nl->Is(CT_MACRO) + || ( nl->Is(CT_FPAREN_CLOSE) + && nl->GetParentType() == CT_MACRO_FUNC)) + { + ref = nl; + } + + if (nl->Is(CT_NL_CONT)) + { + if (ref->IsNotNullChunk()) + { + newline_add_after(ref); + } + return; + } + } +} // nl_handle_define + + +void newline_after_multiline_comment() +{ + LOG_FUNC_ENTRY(); + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if (pc->IsNot(CT_COMMENT_MULTI)) + { + continue; + } + Chunk *tmp = pc; + + while ( ((tmp = tmp->GetNext())->IsNotNullChunk()) + && !tmp->IsNewline()) + { + if (!tmp->IsComment()) + { + newline_add_before(tmp); + break; + } + } + } +} // newline_after_multiline_comment + + +void newline_after_label_colon() +{ + LOG_FUNC_ENTRY(); + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if (pc->IsNot(CT_LABEL_COLON)) + { + continue; + } + newline_add_after(pc); + } +} // newline_after_label_colon + + +static bool is_class_one_liner(Chunk *pc) +{ + if ( ( pc->Is(CT_FUNC_CLASS_DEF) + || pc->Is(CT_FUNC_DEF)) + && pc->TestFlags(PCF_IN_CLASS)) + { + // Find opening brace + pc = pc->GetNextType(CT_BRACE_OPEN, pc->GetLevel()); + return( pc->IsNotNullChunk() + && pc->TestFlags(PCF_ONE_LINER)); + } + return(false); +} // is_class_one_liner + + +void newlines_insert_blank_lines() +{ + LOG_FUNC_ENTRY(); + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + //LOG_FMT(LNEWLINE, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + // __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + if (pc->Is(CT_IF)) + { + newlines_if_for_while_switch_pre_blank_lines(pc, options::nl_before_if()); + log_rule_B("nl_before_if"); + newlines_if_for_while_switch_post_blank_lines(pc, options::nl_after_if()); + log_rule_B("nl_after_if"); + } + else if (pc->Is(CT_FOR)) + { + newlines_if_for_while_switch_pre_blank_lines(pc, options::nl_before_for()); + log_rule_B("nl_before_for"); + newlines_if_for_while_switch_post_blank_lines(pc, options::nl_after_for()); + log_rule_B("nl_after_for"); + } + else if (pc->Is(CT_WHILE)) + { + newlines_if_for_while_switch_pre_blank_lines(pc, options::nl_before_while()); + log_rule_B("nl_before_while"); + newlines_if_for_while_switch_post_blank_lines(pc, options::nl_after_while()); + log_rule_B("nl_after_while"); + } + else if (pc->Is(CT_SWITCH)) + { + newlines_if_for_while_switch_pre_blank_lines(pc, options::nl_before_switch()); + log_rule_B("nl_before_switch"); + newlines_if_for_while_switch_post_blank_lines(pc, options::nl_after_switch()); + log_rule_B("nl_after_switch"); + } + else if (pc->Is(CT_SYNCHRONIZED)) + { + newlines_if_for_while_switch_pre_blank_lines(pc, options::nl_before_synchronized()); + log_rule_B("nl_before_synchronized"); + newlines_if_for_while_switch_post_blank_lines(pc, options::nl_after_synchronized()); + log_rule_B("nl_after_synchronized"); + } + else if (pc->Is(CT_DO)) + { + newlines_if_for_while_switch_pre_blank_lines(pc, options::nl_before_do()); + log_rule_B("nl_before_do"); + newlines_if_for_while_switch_post_blank_lines(pc, options::nl_after_do()); + log_rule_B("nl_after_do"); + } + else if (pc->Is(CT_OC_INTF)) + { + newlines_if_for_while_switch_pre_blank_lines(pc, options::nl_oc_before_interface()); + log_rule_B("nl_oc_before_interface"); + } + else if (pc->Is(CT_OC_END)) + { + newlines_if_for_while_switch_pre_blank_lines(pc, options::nl_oc_before_end()); + log_rule_B("nl_oc_before_end"); + } + else if (pc->Is(CT_OC_IMPL)) + { + newlines_if_for_while_switch_pre_blank_lines(pc, options::nl_oc_before_implementation()); + log_rule_B("nl_oc_before_implementation"); + } + else if ( pc->Is(CT_FUNC_CLASS_DEF) + || pc->Is(CT_FUNC_DEF) + || pc->Is(CT_FUNC_CLASS_PROTO) + || pc->Is(CT_FUNC_PROTO)) + { + if ( options::nl_class_leave_one_liner_groups() + && is_class_one_liner(pc)) + { + log_rule_B("nl_class_leave_one_liner_groups"); + newlines_func_pre_blank_lines(pc, CT_FUNC_PROTO); + } + else + { + newlines_func_pre_blank_lines(pc, pc->GetType()); + } + } + else + { + // ignore it + //LOG_FMT(LNEWLINE, "%s(%d): ignore it\n", __func__, __LINE__); + } + } +} // newlines_insert_blank_lines + + +void newlines_functions_remove_extra_blank_lines() +{ + LOG_FUNC_ENTRY(); + + const size_t nl_max_blank_in_func = options::nl_max_blank_in_func(); + + log_rule_B("nl_max_blank_in_func"); + + if (nl_max_blank_in_func == 0) + { + LOG_FMT(LNEWLINE, "%s(%d): nl_max_blank_in_func is zero\n", __func__, __LINE__); + return; + } + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + LOG_FMT(LNEWLINE, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + + if ( pc->IsNot(CT_BRACE_OPEN) + || ( pc->GetParentType() != CT_FUNC_DEF + && pc->GetParentType() != CT_CPP_LAMBDA)) + { + continue; + } + const size_t startMoveLevel = pc->GetLevel(); + + while (pc->IsNotNullChunk()) + { + if ( pc->Is(CT_BRACE_CLOSE) + && pc->GetLevel() == startMoveLevel) + { + break; + } + + // delete newlines + if ( !pc->Is(CT_COMMENT_MULTI) // Issue #2195 + && pc->GetNlCount() > nl_max_blank_in_func) + { + LOG_FMT(LNEWLINE, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + pc->SetNlCount(nl_max_blank_in_func); + MARK_CHANGE(); + remove_next_newlines(pc); + } + else + { + pc = pc->GetNext(); + } + } + } +} // newlines_functions_remove_extra_blank_lines + + +void newlines_squeeze_ifdef() +{ + LOG_FUNC_ENTRY(); + + Chunk *pc; + + for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + if ( pc->Is(CT_PREPROC) + && ( pc->GetLevel() > 0 + || options::nl_squeeze_ifdef_top_level())) + { + log_rule_B("nl_squeeze_ifdef_top_level"); + Chunk *ppr = pc->GetNext(); + + if ( ppr->Is(CT_PP_IF) + || ppr->Is(CT_PP_ELSE) + || ppr->Is(CT_PP_ENDIF)) + { + Chunk *pnl = Chunk::NullChunkPtr; + Chunk *nnl = ppr->GetNextNl(); + + if ( ppr->Is(CT_PP_ELSE) + || ppr->Is(CT_PP_ENDIF)) + { + pnl = pc->GetPrevNl(); + } + Chunk *tmp1; + Chunk *tmp2; + + if (nnl->IsNotNullChunk()) + { + if (pnl->IsNotNullChunk()) + { + if (pnl->GetNlCount() > 1) + { + pnl->SetNlCount(1); + MARK_CHANGE(); + + tmp1 = pnl->GetPrevNnl(); + tmp2 = nnl->GetPrevNnl(); + + LOG_FMT(LNEWLINE, "%s(%d): moved from after line %zu to after %zu\n", + __func__, __LINE__, tmp1->GetOrigLine(), tmp2->GetOrigLine()); + } + } + + if ( ppr->Is(CT_PP_IF) + || ppr->Is(CT_PP_ELSE)) + { + if (nnl->GetNlCount() > 1) + { + tmp1 = nnl->GetPrevNnl(); + LOG_FMT(LNEWLINE, "%s(%d): trimmed newlines after line %zu from %zu\n", + __func__, __LINE__, tmp1->GetOrigLine(), nnl->GetNlCount()); + nnl->SetNlCount(1); + MARK_CHANGE(); + } + } + } + } + } + } +} // newlines_squeeze_ifdef + + +void newlines_squeeze_paren_close() +{ + LOG_FUNC_ENTRY(); + + Chunk *pc; + + for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + Chunk *next; + Chunk *prev; + + if (pc->Is(CT_NEWLINE)) + { + prev = pc->GetPrev(); + } + else + { + prev = pc; + } + next = pc->GetNext(); + + if ( next->IsNotNullChunk() + && prev->IsNotNullChunk() + && next->IsParenClose() + && prev->IsParenClose()) + { + Chunk *prev_op = prev->GetOpeningParen(); + Chunk *next_op = next->GetOpeningParen(); + bool flag = true; + + Chunk *tmp = prev; + + while (tmp->IsParenClose()) + { + tmp = tmp->GetPrev(); + } + + if (tmp->IsNot(CT_NEWLINE)) + { + flag = false; + } + + if (flag) + { + if (next_op->IsOnSameLine(prev_op)) + { + if (pc->Is(CT_NEWLINE)) + { + pc = next; + } + newline_del_between(prev, next); + } + else + { + newline_add_between(prev, next); + } + } + } + } +} // newlines_squeeze_paren_close + + +void newlines_eat_start_end() +{ + LOG_FUNC_ENTRY(); + + Chunk *pc; + + // Process newlines at the start of the file + if ( cpd.frag_cols == 0 + && ( (options::nl_start_of_file() & IARF_REMOVE) + || ( (options::nl_start_of_file() & IARF_ADD) + && (options::nl_start_of_file_min() > 0)))) + { + log_rule_B("nl_start_of_file"); + log_rule_B("nl_start_of_file_min"); + pc = Chunk::GetHead(); + + if (pc->IsNotNullChunk()) + { + if (pc->Is(CT_NEWLINE)) + { + if (options::nl_start_of_file() == IARF_REMOVE) + { + log_rule_B("nl_start_of_file"); + LOG_FMT(LBLANKD, "%s(%d): eat_blanks_start_of_file %zu\n", + __func__, __LINE__, pc->GetOrigLine()); + Chunk::Delete(pc); + MARK_CHANGE(); + } + else if ( options::nl_start_of_file() == IARF_FORCE + || (pc->GetNlCount() < options::nl_start_of_file_min())) + { + log_rule_B("nl_start_of_file"); + LOG_FMT(LBLANKD, "%s(%d): set_blanks_start_of_file %zu\n", + __func__, __LINE__, pc->GetOrigLine()); + pc->SetNlCount(options::nl_start_of_file_min()); + log_rule_B("nl_start_of_file_min"); + MARK_CHANGE(); + } + } + else if ( (options::nl_start_of_file() & IARF_ADD) + && (options::nl_start_of_file_min() > 0)) + { + log_rule_B("nl_start_of_file"); + log_rule_B("nl_start_of_file_min"); + Chunk chunk; + chunk.SetType(CT_NEWLINE); + chunk.SetOrigLine(pc->GetOrigLine()); + chunk.SetOrigCol(pc->GetOrigCol()); + chunk.SetPpLevel(pc->GetPpLevel()); + chunk.SetNlCount(options::nl_start_of_file_min()); + log_rule_B("nl_start_of_file_min"); + chunk.CopyAndAddBefore(pc); + LOG_FMT(LNEWLINE, "%s(%d): %zu:%zu add newline before '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + MARK_CHANGE(); + } + } + } + + // Process newlines at the end of the file + if ( cpd.frag_cols == 0 + && ( (options::nl_end_of_file() & IARF_REMOVE) + || ( (options::nl_end_of_file() & IARF_ADD) + && (options::nl_end_of_file_min() > 0)))) + { + log_rule_B("nl_end_of_file"); + log_rule_B("nl_end_of_file_min"); + pc = Chunk::GetTail(); + + if (pc->IsNotNullChunk()) + { + if (pc->Is(CT_NEWLINE)) + { + if (options::nl_end_of_file() == IARF_REMOVE) + { + log_rule_B("nl_end_of_file"); + LOG_FMT(LBLANKD, "%s(%d): eat_blanks_end_of_file %zu\n", + __func__, __LINE__, pc->GetOrigLine()); + Chunk::Delete(pc); + MARK_CHANGE(); + } + else if ( options::nl_end_of_file() == IARF_FORCE + || (pc->GetNlCount() < options::nl_end_of_file_min())) + { + log_rule_B("nl_end_of_file"); + log_rule_B("nl_end_of_file_min"); + + if (pc->GetNlCount() != options::nl_end_of_file_min()) + { + log_rule_B("nl_end_of_file_min"); + LOG_FMT(LBLANKD, "%s(%d): set_blanks_end_of_file %zu\n", + __func__, __LINE__, pc->GetOrigLine()); + pc->SetNlCount(options::nl_end_of_file_min()); + log_rule_B("nl_end_of_file_min"); + MARK_CHANGE(); + } + } + } + else if ( (options::nl_end_of_file() & IARF_ADD) + && (options::nl_end_of_file_min() > 0)) + { + log_rule_B("nl_end_of_file"); + log_rule_B("nl_end_of_file_min"); + Chunk chunk; + chunk.SetType(CT_NEWLINE); + chunk.SetOrigLine(pc->GetOrigLine()); + chunk.SetOrigCol(pc->GetOrigCol()); + chunk.SetPpLevel(pc->GetPpLevel()); + chunk.SetNlCount(options::nl_end_of_file_min()); + log_rule_B("nl_end_of_file_min"); + chunk.CopyAndAddBefore(Chunk::NullChunkPtr); + LOG_FMT(LNEWLINE, "%s(%d): %zu:%zu add newline after '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + MARK_CHANGE(); + } + } + } +} // newlines_eat_start_end + + +void newlines_chunk_pos(E_Token chunk_type, token_pos_e mode) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LNEWLINE, "%s(%d): mode is %s\n", + __func__, __LINE__, to_string(mode)); + + if ( !(mode & (TP_JOIN | TP_LEAD | TP_TRAIL)) + && chunk_type != CT_COMMA) + { + return; + } + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + char copy[1000]; + LOG_FMT(LNEWLINE, "%s(%d): pc orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->ElidedText(copy)); + // produces much more log output. Use it only debugging purpose + //log_pcf_flags(LNEWLINE, pc->GetFlags()); + + if (pc->Is(chunk_type)) + { + token_pos_e mode_local; + + if (chunk_type == CT_COMMA) + { + LOG_FMT(LNEWLINE, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + // produces much more log output. Use it only debugging purpose + //log_pcf_flags(LNEWLINE, pc->GetFlags()); + + if (pc->TestFlags(PCF_IN_CONST_ARGS)) // Issue #2250 + { + continue; + } + + /* + * for chunk_type == CT_COMMA + * we get 'mode' from options::pos_comma() + * BUT we must take care of options::pos_class_comma() + * TODO and options::pos_constr_comma() + */ + if (pc->TestFlags(PCF_IN_CLASS_BASE)) + { + // change mode + log_rule_B("pos_class_comma"); + mode_local = options::pos_class_comma(); + } + else if (pc->TestFlags(PCF_IN_ENUM)) + { + log_rule_B("pos_enum_comma"); + mode_local = options::pos_enum_comma(); + } + else + { + mode_local = mode; + } + LOG_FMT(LNEWLINE, "%s(%d): mode_local is %s\n", + __func__, __LINE__, to_string(mode_local)); + } + else + { + mode_local = mode; + } + Chunk *prev = pc->GetPrevNc(); + Chunk *next = pc->GetNextNc(); + + LOG_FMT(LNEWLINE, "%s(%d): mode_local is %s\n", + __func__, __LINE__, to_string(mode_local)); + + LOG_FMT(LNEWLINE, "%s(%d): prev orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, prev->GetOrigLine(), prev->GetOrigCol(), prev->Text()); + LOG_FMT(LNEWLINE, "%s(%d): next orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, next->GetOrigLine(), next->GetOrigCol(), next->Text()); + size_t nl_flag = ((prev->IsNewline() ? 1 : 0) | + (next->IsNewline() ? 2 : 0)); + LOG_FMT(LNEWLINE, "%s(%d): nl_flag is %zu\n", + __func__, __LINE__, nl_flag); + + if (mode_local & TP_JOIN) + { + if (nl_flag & 1) + { + // remove newline if not preceded by a comment + Chunk *prev2 = prev->GetPrev(); + + if ( prev2->IsNotNullChunk() + && !(prev2->IsComment())) + { + remove_next_newlines(prev2); + } + } + + if (nl_flag & 2) + { + // remove newline if not followed by a comment or by '{' + Chunk *next2 = next->GetNext(); + + if ( next2->IsNotNullChunk() + && !next2->IsComment() + && !next2->Is(CT_BRACE_OPEN)) + { + remove_next_newlines(pc); + } + } + continue; + } + + if ( ( nl_flag == 0 + && !(mode_local & (TP_FORCE | TP_BREAK))) + || ( nl_flag == 3 + && !(mode_local & TP_FORCE))) + { + // No newlines and not adding any or both and not forcing + continue; + } + + if ( ( (mode_local & TP_LEAD) + && nl_flag == 1) + || ( (mode_local & TP_TRAIL) + && nl_flag == 2)) + { + // Already a newline before (lead) or after (trail) + continue; + } + + // If there were no newlines, we need to add one + if (nl_flag == 0) + { + if (mode_local & TP_LEAD) + { + newline_add_before(pc); + } + else + { + newline_add_after(pc); + } + continue; + } + + // If there were both newlines, we need to remove one + if (nl_flag == 3) + { + if (mode_local & TP_LEAD) + { + remove_next_newlines(pc); + } + else + { + remove_next_newlines(pc->GetPrevNcNnlNi()); // Issue #2279 + } + continue; + } + + // we need to move the newline + if (mode_local & TP_LEAD) + { + Chunk *next2 = next->GetNext(); + + if ( next2->Is(CT_PREPROC) + || ( chunk_type == CT_ASSIGN + && next2->Is(CT_BRACE_OPEN))) + { + continue; + } + + if (next->GetNlCount() == 1) + { + if ( prev != nullptr + && !prev->TestFlags(PCF_IN_PREPROC)) + { + // move the CT_BOOL to after the newline + pc->MoveAfter(next); + } + } + } + else + { + LOG_FMT(LNEWLINE, "%s(%d): prev orig line is %zu, orig col is %zu, Text() is '%s', new line count is %zu\n", + __func__, __LINE__, prev->GetOrigLine(), prev->GetOrigCol(), prev->Text(), prev->GetNlCount()); + + if (prev->GetNlCount() == 1) + { + // Back up to the next non-comment item + prev = prev->GetPrevNc(); + LOG_FMT(LNEWLINE, "%s(%d): prev orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, prev->GetOrigLine(), prev->GetOrigCol(), prev->Text()); + + if ( prev->IsNotNullChunk() + && !prev->IsNewline() + && !prev->TestFlags(PCF_IN_PREPROC) + && !prev->TestFlags(PCF_IN_OC_MSG)) + { + pc->MoveAfter(prev); + } + } + } + } + } +} // newlines_chunk_pos + + +void newlines_class_colon_pos(E_Token tok) +{ + LOG_FUNC_ENTRY(); + + token_pos_e tpc; + token_pos_e pcc; + iarf_e anc; + iarf_e ncia; + + if (tok == CT_CLASS_COLON) + { + tpc = options::pos_class_colon(); + log_rule_B("pos_class_colon"); + anc = options::nl_class_colon(); + log_rule_B("nl_class_colon"); + ncia = options::nl_class_init_args(); + log_rule_B("nl_class_init_args"); + pcc = options::pos_class_comma(); + log_rule_B("pos_class_comma"); + } + else // tok == CT_CONSTR_COLON + { + tpc = options::pos_constr_colon(); + log_rule_B("pos_constr_colon"); + anc = options::nl_constr_colon(); + log_rule_B("nl_constr_colon"); + ncia = options::nl_constr_init_args(); + log_rule_B("nl_constr_init_args"); + pcc = options::pos_constr_comma(); + log_rule_B("pos_constr_comma"); + } + Chunk *ccolon = nullptr; + size_t acv_span = options::align_constr_value_span(); + + log_rule_B("align_constr_value_span"); + bool with_acv = (acv_span > 0) && language_is_set(LANG_CPP); + AlignStack constructorValue; // ABC_Member(abc_value) + + if (with_acv) + { + int acv_thresh = options::align_constr_value_thresh(); + log_rule_B("align_constr_value_thresh"); + size_t acv_gap = options::align_constr_value_gap(); + log_rule_B("align_constr_value_gap"); + constructorValue.Start(acv_span, acv_thresh); + constructorValue.m_gap = acv_gap; + constructorValue.m_right_align = !options::align_on_tabstop(); + log_rule_B("align_on_tabstop"); + } + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + if ( ccolon == nullptr + && pc->IsNot(tok)) + { + continue; + } + Chunk *prev; + Chunk *next; + + if (pc->Is(tok)) + { + LOG_FMT(LBLANKD, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + ccolon = pc; + prev = pc->GetPrevNc(); + next = pc->GetNextNc(); + + if (pc->Is(CT_CONSTR_COLON)) + { + LOG_FMT(LBLANKD, "%s(%d): pc orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + Chunk *paren_vor_value = pc->GetNextType(CT_FPAREN_OPEN, pc->GetLevel()); + + if ( with_acv + && paren_vor_value->IsNotNullChunk()) + { + LOG_FMT(LBLANKD, "%s(%d): paren_vor_value orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, paren_vor_value->GetOrigLine(), paren_vor_value->GetOrigCol(), + paren_vor_value->Text(), get_token_name(paren_vor_value->GetType())); + constructorValue.NewLines(paren_vor_value->GetNlCount()); + constructorValue.Add(paren_vor_value); + } + } + + if ( !prev->IsNewline() + && !next->IsNewline() + && (anc & IARF_ADD)) // nl_class_colon, nl_constr_colon: 1 + + { + newline_add_after(pc); + prev = pc->GetPrevNc(); + next = pc->GetNextNc(); + } + + if (anc == IARF_REMOVE) // nl_class_colon, nl_constr_colon: 2 + { + if ( prev->IsNewline() + && prev->SafeToDeleteNl()) + { + Chunk::Delete(prev); + MARK_CHANGE(); + prev = pc->GetPrevNc(); + } + + if ( next->IsNewline() + && next->SafeToDeleteNl()) + { + Chunk::Delete(next); + MARK_CHANGE(); + next = pc->GetNextNc(); + } + } + + if (tpc & TP_TRAIL) // pos_class_colon, pos_constr_colon: 4 + { + if ( prev->IsNewline() + && prev->GetNlCount() == 1 + && prev->SafeToDeleteNl()) + { + pc->Swap(prev); + } + } + else if (tpc & TP_LEAD) // pos_class_colon, pos_constr_colon: 3 + { + if ( next->IsNewline() + && next->GetNlCount() == 1 + && next->SafeToDeleteNl()) + { + pc->Swap(next); + } + } + } + else + { + // (pc->GetType() != tok) + if ( pc->Is(CT_BRACE_OPEN) + || pc->Is(CT_SEMICOLON)) + { + ccolon = nullptr; + + if (with_acv) + { + constructorValue.End(); + } + continue; + } + + if ( pc->Is(CT_COMMA) + && pc->GetLevel() == ccolon->GetLevel()) + { + LOG_FMT(LBLANKD, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + Chunk *paren_vor_value = pc->GetNextType(CT_FPAREN_OPEN, pc->GetLevel()); + + if ( with_acv + && paren_vor_value->IsNotNullChunk()) + { + LOG_FMT(LBLANKD, "%s(%d): paren_vor_value orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, paren_vor_value->GetOrigLine(), paren_vor_value->GetOrigCol(), + paren_vor_value->Text(), get_token_name(paren_vor_value->GetType())); + constructorValue.NewLines(paren_vor_value->GetNlCount()); + constructorValue.Add(paren_vor_value); + } + + if (ncia & IARF_ADD) // nl_class_init_args, nl_constr_init_args: + { + if (pcc & TP_TRAIL) // pos_class_comma, pos_constr_comma + { + if (ncia == IARF_FORCE) // nl_class_init_args, nl_constr_init_args: 5 + { + Chunk *after = pc->GetNext(); // Issue #2759 + + if (after->IsNot(CT_COMMENT_CPP)) + { + newline_force_after(pc); + } + } + else + { + // (ncia == IARF_ADD) // nl_class_init_args, nl_constr_init_args: 8 + newline_add_after(pc); + } + prev = pc->GetPrevNc(); + + if ( prev->IsNewline() + && prev->SafeToDeleteNl()) + { + Chunk::Delete(prev); + MARK_CHANGE(); + } + } + else if (pcc & TP_LEAD) // pos_class_comma, pos_constr_comma + { + if (ncia == IARF_FORCE) // nl_class_init_args, nl_constr_init_args: 7 + { + newline_force_before(pc); + } + else + { + // (ncia == IARF_ADD) // nl_class_init_args, nl_constr_init_args: 9 + newline_add_before(pc); + } + next = pc->GetNextNc(); + + if ( next->IsNewline() + && next->SafeToDeleteNl()) + { + Chunk::Delete(next); + MARK_CHANGE(); + } + } + } + else if (ncia == IARF_REMOVE) // nl_class_init_args, nl_constr_init_args: 6 + { + next = pc->GetNext(); + + if ( next->IsNewline() + && next->SafeToDeleteNl()) + { + // comma is after + Chunk::Delete(next); + MARK_CHANGE(); + } + else + { + prev = pc->GetPrev(); + + if ( prev->IsNewline() + && prev->SafeToDeleteNl()) + { + // comma is before + Chunk::Delete(prev); + MARK_CHANGE(); + } + } + } + } + } + } +} // newlines_class_colon_pos + + +static void blank_line_max(Chunk *pc, Option<unsigned> &opt) +{ + LOG_FUNC_ENTRY(); + + if (pc == nullptr) + { + return; + } + const auto optval = opt(); + + if ( (optval > 0) + && (pc->GetNlCount() > optval)) + { + LOG_FMT(LBLANKD, "%s(%d): do_blank_lines: %s max line %zu\n", + __func__, __LINE__, opt.name(), pc->GetOrigLine()); + pc->SetNlCount(optval); + MARK_CHANGE(); + } +} // blank_line_max + + +iarf_e newline_template_option(Chunk *pc, iarf_e special, iarf_e base, iarf_e fallback) +{ + Chunk *const prev = pc->GetPrevNcNnl(); + + if ( prev->Is(CT_ANGLE_OPEN) + && special != IARF_IGNORE) + { + return(special); + } + else if (base != IARF_IGNORE) + { + return(base); + } + else + { + return(fallback); + } +} // newline_template_option + + +bool is_func_proto_group(Chunk *pc, E_Token one_liner_type) +{ + if ( pc != nullptr + && options::nl_class_leave_one_liner_groups() + && ( pc->Is(one_liner_type) + || pc->GetParentType() == one_liner_type) + && pc->TestFlags(PCF_IN_CLASS)) + { + log_rule_B("nl_class_leave_one_liner_groups"); + + if (pc->Is(CT_BRACE_CLOSE)) + { + return(pc->TestFlags(PCF_ONE_LINER)); + } + else + { + // Find opening brace + pc = pc->GetNextType(CT_BRACE_OPEN, pc->GetLevel()); + return( pc->IsNotNullChunk() + && pc->TestFlags(PCF_ONE_LINER)); + } + } + return(false); +} // is_func_proto_group + + +void do_blank_lines() +{ + LOG_FUNC_ENTRY(); + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if (pc->Is(CT_NEWLINE)) + { + LOG_FMT(LBLANKD, "%s(%d): orig line is %zu, orig col is %zu, <Newline>, nl is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->GetNlCount()); + } + else + { + char copy[1000]; + LOG_FMT(LBLANKD, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->ElidedText(copy), get_token_name(pc->GetType())); + } + LOG_FMT(LBLANK, "%s(%d): new line count is %zu\n", + __func__, __LINE__, pc->GetNlCount()); + + if (pc->IsNot(CT_NEWLINE)) + { + continue; + } + Chunk *prev = pc->GetPrevNc(); + + if (prev->IsNotNullChunk()) + { + LOG_FMT(LBLANK, "%s(%d): prev orig line is %zu, prev->Text() '%s', prev->GetType() is %s\n", + __func__, __LINE__, pc->GetOrigLine(), + prev->Text(), get_token_name(prev->GetType())); + + if (prev->Is(CT_IGNORED)) + { + continue; + } + } + Chunk *next = pc->GetNext(); + Chunk *pcmt = pc->GetPrev(); + + bool line_added = false; + + /* + * If this is the first or the last token, pretend that there is an extra + * line. It will be removed at the end. + */ + if ( pc == Chunk::GetHead() + || next->IsNullChunk()) + { + line_added = true; + pc->SetNlCount(pc->GetNlCount() + 1); + LOG_FMT(LBLANK, "%s(%d): orig line is %zu, orig col is %zu, text is '%s', new line count is now %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), pc->GetNlCount()); + } + + // Limit consecutive newlines + if ( (options::nl_max() > 0) + && (pc->GetNlCount() > options::nl_max())) + { + log_rule_B("nl_max"); + blank_line_max(pc, options::nl_max); + } + + if (!can_increase_nl(pc)) + { + LOG_FMT(LBLANKD, "%s(%d): force to 1 orig line is %zu, orig col is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + + if (pc->GetNlCount() != 1) + { + pc->SetNlCount(1); + MARK_CHANGE(); + } + continue; + } + + // Control blanks before multi-line comments + if ( (options::nl_before_block_comment() > pc->GetNlCount()) + && next->Is(CT_COMMENT_MULTI)) + { + log_rule_B("nl_before_block_comment"); + + // Don't add blanks after an open brace or a case statement + if ( ( prev->IsNullChunk() + || ( prev->IsNot(CT_BRACE_OPEN) + && prev->IsNot(CT_VBRACE_OPEN) + && prev->IsNot(CT_CASE_COLON))) + && pcmt->IsNot(CT_COMMENT_MULTI)) // Issue #2383 + { + blank_line_set(pc, options::nl_before_block_comment); + log_rule_B("nl_before_block_comment"); + } + } + + // Control blanks before single line C comments + if ( (options::nl_before_c_comment() > pc->GetNlCount()) + && next->Is(CT_COMMENT)) + { + log_rule_B("nl_before_c_comment"); + + // Don't add blanks after an open brace, a case stamement, or a comment + if ( ( prev->IsNullChunk() + || ( prev->IsNot(CT_BRACE_OPEN) + && prev->IsNot(CT_VBRACE_OPEN) + && prev->IsNot(CT_CASE_COLON))) + && pcmt->IsNot(CT_COMMENT)) // Issue #2383 + { + blank_line_set(pc, options::nl_before_c_comment); + log_rule_B("nl_before_c_comment"); + } + } + + // Control blanks before CPP comments + if ( (options::nl_before_cpp_comment() > pc->GetNlCount()) + && next->Is(CT_COMMENT_CPP)) + { + log_rule_B("nl_before_cpp_comment"); + + // Don't add blanks after an open brace or a case statement + if ( ( prev->IsNullChunk() + || ( prev->IsNot(CT_BRACE_OPEN) + && prev->IsNot(CT_VBRACE_OPEN) + && prev->IsNot(CT_CASE_COLON))) + && pcmt->IsNot(CT_COMMENT_CPP)) // Issue #2383 + { + blank_line_set(pc, options::nl_before_cpp_comment); + log_rule_B("nl_before_cpp_comment"); + } + } + + // Control blanks before a class/struct + if ( ( prev->Is(CT_SEMICOLON) + || prev->Is(CT_BRACE_CLOSE)) + && ( prev->GetParentType() == CT_CLASS + || prev->GetParentType() == CT_STRUCT)) + { + E_Token parent_type = prev->GetParentType(); + Chunk *start = prev->GetPrevType(parent_type, prev->GetLevel()); + Chunk *tmp = start; + + // Is this a class/struct template? + if (tmp->GetParentType() == CT_TEMPLATE) + { + tmp = tmp->GetPrevType(CT_TEMPLATE, prev->GetLevel()); + tmp = tmp->GetPrevNc(); + } + else + { + tmp = tmp->GetPrevNc(); + + while ( tmp->Is(CT_NEWLINE) + && tmp->GetPrev()->IsComment()) + { + tmp = tmp->GetPrev()->GetPrevNc(); + } + + if (tmp->Is(CT_FRIEND)) + { + // Account for a friend declaration + tmp = tmp->GetPrevNc(); + } + } + + while ( tmp->Is(CT_NEWLINE) + && tmp->GetPrev()->IsComment()) + { + tmp = tmp->GetPrev()->GetPrevNc(); + } + + if ( tmp->IsNotNullChunk() + && !start->TestFlags(PCF_INCOMPLETE)) + { + if (parent_type == CT_CLASS && options::nl_before_class() > tmp->GetNlCount()) + { + log_rule_B("nl_before_class"); + blank_line_set(tmp, options::nl_before_class); + } + else if (parent_type == CT_STRUCT && options::nl_before_struct() > tmp->GetNlCount()) + { + log_rule_B("nl_before_struct"); + blank_line_set(tmp, options::nl_before_struct); + } + } + } + + if ( prev->Is(CT_BRACE_CLOSE) + && prev->GetParentType() == CT_NAMESPACE) + { + // Control blanks before a namespace + Chunk *tmp = prev->GetPrevType(CT_NAMESPACE, prev->GetLevel()); + tmp = tmp->GetPrevNc(); + + while ( tmp->Is(CT_NEWLINE) + && tmp->GetPrev()->IsComment()) + { + tmp = tmp->GetPrev()->GetPrevNc(); + } + + if ( tmp->IsNotNullChunk() + && options::nl_before_namespace() > tmp->GetNlCount()) + { + log_rule_B("nl_before_namespace"); + blank_line_set(tmp, options::nl_before_namespace); + } + + // Add blanks after namespace + if (options::nl_after_namespace() > pc->GetNlCount()) + { + log_rule_B("nl_after_namespace"); + blank_line_set(pc, options::nl_after_namespace); + } + } + + // Control blanks inside empty function body + if ( prev->Is(CT_BRACE_OPEN) + && next->Is(CT_BRACE_CLOSE) + && ( prev->GetParentType() == CT_FUNC_DEF + || prev->GetParentType() == CT_FUNC_CLASS_DEF) + && options::nl_inside_empty_func() > pc->GetNlCount() + && prev->TestFlags(PCF_EMPTY_BODY)) + { + blank_line_set(pc, options::nl_inside_empty_func); + log_rule_B("nl_inside_empty_func"); + } + + // Control blanks after an access spec + if ( (options::nl_after_access_spec() > 0) + && (options::nl_after_access_spec() != pc->GetNlCount()) + && prev->Is(CT_ACCESS_COLON)) + { + log_rule_B("nl_after_access_spec"); + + // Don't add blanks before a closing brace + if ( next->IsNullChunk() + || !next->IsBraceClose()) + { + log_rule_B("nl_after_access_spec"); + blank_line_set(pc, options::nl_after_access_spec); + } + } + + // Add blanks after function bodies + if ( prev->Is(CT_BRACE_CLOSE) + && ( prev->GetParentType() == CT_FUNC_DEF + || prev->GetParentType() == CT_FUNC_CLASS_DEF + || prev->GetParentType() == CT_OC_MSG_DECL + || prev->GetParentType() == CT_ASSIGN)) + { + if (prev->TestFlags(PCF_ONE_LINER)) + { + if (options::nl_after_func_body_one_liner() > pc->GetNlCount()) + { + log_rule_B("nl_after_func_body_one_liner"); + blank_line_set(pc, options::nl_after_func_body_one_liner); + } + } + else + { + if ( prev->TestFlags(PCF_IN_CLASS) + && (options::nl_after_func_body_class() > 0)) + { + log_rule_B("nl_after_func_body_class"); + + if (options::nl_after_func_body_class() != pc->GetNlCount()) + { + log_rule_B("nl_after_func_body_class"); + blank_line_set(pc, options::nl_after_func_body_class); + } + } + else if (options::nl_after_func_body() > 0) + { + log_rule_B("nl_after_func_body"); + + // Issue #1734 + if (!(pc->GetPrev()->TestFlags(PCF_IN_TRY_BLOCK))) + { + if (options::nl_after_func_body() != pc->GetNlCount()) + { + log_rule_B("nl_after_func_body"); + blank_line_set(pc, options::nl_after_func_body); + } + } + } + } + } + + // Add blanks after function prototypes + if ( ( prev->Is(CT_SEMICOLON) + && prev->GetParentType() == CT_FUNC_PROTO) + || is_func_proto_group(prev, CT_FUNC_DEF)) + { + if (options::nl_after_func_proto() > pc->GetNlCount()) + { + log_rule_B("nl_after_func_proto"); + pc->SetNlCount(options::nl_after_func_proto()); + MARK_CHANGE(); + } + + if ( (options::nl_after_func_proto_group() > pc->GetNlCount()) + && next->IsNotNullChunk() + && next->GetParentType() != CT_FUNC_PROTO + && !is_func_proto_group(next, CT_FUNC_DEF)) + { + log_rule_B("nl_after_func_proto_group"); + blank_line_set(pc, options::nl_after_func_proto_group); + } + } + + // Issue #411: Add blanks after function class prototypes + if ( ( prev->Is(CT_SEMICOLON) + && prev->GetParentType() == CT_FUNC_CLASS_PROTO) + || is_func_proto_group(prev, CT_FUNC_CLASS_DEF)) + { + if (options::nl_after_func_class_proto() > pc->GetNlCount()) + { + log_rule_B("nl_after_func_class_proto"); + pc->SetNlCount(options::nl_after_func_class_proto()); + MARK_CHANGE(); + } + + if ( (options::nl_after_func_class_proto_group() > pc->GetNlCount()) + && next->IsNot(CT_FUNC_CLASS_PROTO) + && next->GetParentType() != CT_FUNC_CLASS_PROTO + && !is_func_proto_group(next, CT_FUNC_CLASS_DEF)) + { + log_rule_B("nl_after_func_class_proto_group"); + blank_line_set(pc, options::nl_after_func_class_proto_group); + } + } + + // Add blanks after struct/enum/union/class + if ( ( prev->Is(CT_SEMICOLON) + || prev->Is(CT_BRACE_CLOSE)) + && ( prev->GetParentType() == CT_STRUCT + || prev->GetParentType() == CT_ENUM + || prev->GetParentType() == CT_UNION + || prev->GetParentType() == CT_CLASS)) + { + auto &opt = (prev->GetParentType() == CT_CLASS + ? options::nl_after_class + : options::nl_after_struct); + log_rule_B("nl_after_class"); + log_rule_B("nl_after_struct"); + + if (opt() > pc->GetNlCount()) + { + // Issue #1702 + // look back if we have a variable + Chunk *tmp = pc; + bool is_var_def = false; + bool is_fwd_decl = false; + + while ((tmp = tmp->GetPrev())->IsNotNullChunk()) + { + if (tmp->GetLevel() > pc->GetLevel()) + { + continue; + } + LOG_FMT(LBLANK, "%s(%d): %zu:%zu token is '%s'\n", + __func__, __LINE__, tmp->GetOrigLine(), tmp->GetOrigCol(), tmp->Text()); + + if (tmp->TestFlags(PCF_VAR_DEF)) + { + is_var_def = true; + break; + } + + if (tmp->Is(prev->GetParentType())) + { + is_fwd_decl = tmp->TestFlags(PCF_INCOMPLETE); + break; + } + } + LOG_FMT(LBLANK, "%s(%d): var_def = %s, fwd_decl = %s\n", + __func__, __LINE__, + is_var_def ? "yes" : "no", + is_fwd_decl ? "yes" : "no"); + + if ( !is_var_def + && !is_fwd_decl) + { + blank_line_set(pc, opt); + } + } + } + + // Change blanks between a function comment and body + if ( (options::nl_comment_func_def() != 0) + && pcmt->Is(CT_COMMENT_MULTI) + && pcmt->GetParentType() == CT_COMMENT_WHOLE + && next->IsNotNullChunk() + && ( next->GetParentType() == CT_FUNC_DEF + || next->GetParentType() == CT_FUNC_CLASS_DEF)) + { + log_rule_B("nl_comment_func_def"); + + if (options::nl_comment_func_def() != pc->GetNlCount()) + { + log_rule_B("nl_comment_func_def"); + blank_line_set(pc, options::nl_comment_func_def); + } + } + + // Change blanks after a try-catch-finally block + if ( (options::nl_after_try_catch_finally() != 0) + && (options::nl_after_try_catch_finally() != pc->GetNlCount()) + && prev->IsNotNullChunk() + && next->IsNotNullChunk()) + { + log_rule_B("nl_after_try_catch_finally"); + + if ( prev->Is(CT_BRACE_CLOSE) + && ( prev->GetParentType() == CT_CATCH + || prev->GetParentType() == CT_FINALLY)) + { + if ( next->IsNot(CT_BRACE_CLOSE) + && next->IsNot(CT_CATCH) + && next->IsNot(CT_FINALLY)) + { + blank_line_set(pc, options::nl_after_try_catch_finally); + log_rule_B("nl_after_try_catch_finally"); + } + } + } + + // Change blanks after a try-catch-finally block + if ( (options::nl_between_get_set() != 0) + && (options::nl_between_get_set() != pc->GetNlCount()) + && prev->IsNotNullChunk() + && next->IsNotNullChunk()) + { + log_rule_B("nl_between_get_set"); + + if ( prev->GetParentType() == CT_GETSET + && next->IsNot(CT_BRACE_CLOSE) + && ( prev->Is(CT_BRACE_CLOSE) + || prev->Is(CT_SEMICOLON))) + { + blank_line_set(pc, options::nl_between_get_set); + log_rule_B("nl_between_get_set"); + } + } + + // Change blanks after a try-catch-finally block + if ( (options::nl_around_cs_property() != 0) + && (options::nl_around_cs_property() != pc->GetNlCount()) + && prev->IsNotNullChunk() + && next->IsNotNullChunk()) + { + log_rule_B("nl_around_cs_property"); + + if ( prev->Is(CT_BRACE_CLOSE) + && prev->GetParentType() == CT_CS_PROPERTY + && next->IsNot(CT_BRACE_CLOSE)) + { + blank_line_set(pc, options::nl_around_cs_property); + log_rule_B("nl_around_cs_property"); + } + else if ( next->GetParentType() == CT_CS_PROPERTY + && next->TestFlags(PCF_STMT_START)) + { + blank_line_set(pc, options::nl_around_cs_property); + log_rule_B("nl_around_cs_property"); + } + } + + // Control blanks before an access spec + if ( (options::nl_before_access_spec() > 0) + && (options::nl_before_access_spec() != pc->GetNlCount()) + && next->Is(CT_ACCESS)) + { + log_rule_B("nl_before_access_spec"); + + // Don't add blanks after an open brace + if ( prev->IsNullChunk() + || ( prev->IsNot(CT_BRACE_OPEN) + && prev->IsNot(CT_VBRACE_OPEN))) + { + log_rule_B("nl_before_access_spec"); + blank_line_set(pc, options::nl_before_access_spec); + } + } + + // Change blanks inside namespace braces + if ( (options::nl_inside_namespace() != 0) + && (options::nl_inside_namespace() != pc->GetNlCount()) + && ( ( prev->Is(CT_BRACE_OPEN) + && prev->GetParentType() == CT_NAMESPACE) + || ( next->Is(CT_BRACE_CLOSE) + && next->GetParentType() == CT_NAMESPACE))) + { + log_rule_B("nl_inside_namespace"); + blank_line_set(pc, options::nl_inside_namespace); + } + + // Control blanks before a whole-file #ifdef + if ( options::nl_before_whole_file_ifdef() != 0 + && options::nl_before_whole_file_ifdef() != pc->GetNlCount() + && next->Is(CT_PREPROC) + && next->GetParentType() == CT_PP_IF + && ifdef_over_whole_file() + && next->TestFlags(PCF_WF_IF)) + { + log_rule_B("nl_before_whole_file_ifdef"); + blank_line_set(pc, options::nl_before_whole_file_ifdef); + } + + // Control blanks after a whole-file #ifdef + if ( options::nl_after_whole_file_ifdef() != 0 + && options::nl_after_whole_file_ifdef() != pc->GetNlCount()) + { + Chunk *pp_start = prev->GetPpStart(); + + if ( pp_start->IsNotNullChunk() + && pp_start->GetParentType() == CT_PP_IF + && ifdef_over_whole_file() + && pp_start->TestFlags(PCF_WF_IF)) + { + log_rule_B("nl_after_whole_file_ifdef"); + blank_line_set(pc, options::nl_after_whole_file_ifdef); + } + } + + // Control blanks before a whole-file #endif + if ( options::nl_before_whole_file_endif() != 0 + && options::nl_before_whole_file_endif() != pc->GetNlCount() + && next->Is(CT_PREPROC) + && next->GetParentType() == CT_PP_ENDIF + && ifdef_over_whole_file() + && next->TestFlags(PCF_WF_ENDIF)) + { + log_rule_B("nl_before_whole_file_endif"); + blank_line_set(pc, options::nl_before_whole_file_endif); + } + + // Control blanks after a whole-file #endif + if ( options::nl_after_whole_file_endif() != 0 + && options::nl_after_whole_file_endif() != pc->GetNlCount()) + { + Chunk *pp_start = prev->GetPpStart(); + + if ( pp_start->IsNotNullChunk() + && pp_start->GetParentType() == CT_PP_ENDIF + && ifdef_over_whole_file() + && pp_start->TestFlags(PCF_WF_ENDIF)) + { + log_rule_B("nl_after_whole_file_endif"); + blank_line_set(pc, options::nl_after_whole_file_endif); + } + } + + if ( line_added + && pc->GetNlCount() > 1) + { + pc->SetNlCount(pc->GetNlCount() - 1); + LOG_FMT(LBLANK, "%s(%d): orig line is %zu, orig col is %zu, text is '%s', new line count is now %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), pc->GetNlCount()); + } + LOG_FMT(LBLANK, "%s(%d): orig line is %zu, orig col is %zu, text is '%s', end new line count is now %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), pc->GetNlCount()); + } +} // do_blank_lines + + +void newlines_cleanup_dup() +{ + LOG_FUNC_ENTRY(); + + Chunk *pc = Chunk::GetHead(); + Chunk *next = pc; + + while (pc->IsNotNullChunk()) + { + next = next->GetNext(); + + if ( pc->Is(CT_NEWLINE) + && next->Is(CT_NEWLINE)) + { + next->SetNlCount(max(pc->GetNlCount(), next->GetNlCount())); + Chunk::Delete(pc); + MARK_CHANGE(); + } + pc = next; + } +} // newlines_cleanup_dup + + +static void newlines_enum_entries(Chunk *open_brace, iarf_e av) +{ + LOG_FUNC_ENTRY(); + + Chunk *pc = Chunk::NullChunkPtr; + + if (open_brace != nullptr) + { + pc = open_brace; + } + + while ( (pc = pc->GetNextNc())->IsNotNullChunk() + && pc->GetLevel() > open_brace->GetLevel()) + { + if ( (pc->GetLevel() != (open_brace->GetLevel() + 1)) + || pc->IsNot(CT_COMMA) + || ( pc->Is(CT_COMMA) + && pc->GetNext()->IsNotNullChunk() + && ( pc->GetNext()->GetType() == CT_COMMENT_CPP + || pc->GetNext()->GetType() == CT_COMMENT))) + { + continue; + } + newline_iarf(pc, av); + } + newline_iarf(open_brace, av); +} // newlines_enum_entries + + +static void newlines_double_space_struct_enum_union(Chunk *open_brace) +{ + LOG_FUNC_ENTRY(); + + Chunk *pc = Chunk::NullChunkPtr; + + if (open_brace != nullptr) + { + pc = open_brace; + } + + while ( (pc = pc->GetNextNc())->IsNotNullChunk() + && pc->GetLevel() > open_brace->GetLevel()) + { + if ( pc->GetLevel() != (open_brace->GetLevel() + 1) + || pc->IsNot(CT_NEWLINE)) + { + continue; + } + /* + * If the newline is NOT after a comment or a brace open and + * it is before a comment, then make sure that the newline is + * at least doubled + */ + Chunk *prev = pc->GetPrev(); + + if ( !prev->IsComment() + && prev->IsNot(CT_BRACE_OPEN) + && pc->GetNext()->IsComment()) + { + if (pc->GetNlCount() < 2) + { + double_newline(pc); + } + } + } +} // newlines_double_space_struct_enum_union + + +void annotations_newlines() +{ + LOG_FUNC_ENTRY(); + + Chunk *next; + Chunk *prev; + Chunk *ae; // last token of the annotation + Chunk *pc = Chunk::GetHead(); + + while ( (pc = pc->GetNextType(CT_ANNOTATION))->IsNotNullChunk() + && (next = pc->GetNextNnl())->IsNotNullChunk()) + { + // find the end of this annotation + if (next->IsParenOpen()) + { + // TODO: control newline between annotation and '(' ? + ae = next->GetClosingParen(); + } + else + { + ae = pc; + } + + if (ae->IsNullChunk()) + { + break; + } + LOG_FMT(LANNOT, "%s(%d): orig line is %zu, orig col is %zu, annotation is '%s', end @ orig line %zu, orig col %zu, is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), + ae->GetOrigLine(), ae->GetOrigCol(), ae->Text()); + + prev = ae->GetPrev(); // Issue #1845 + LOG_FMT(LANNOT, "%s(%d): prev orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, prev->GetOrigLine(), prev->GetOrigCol(), prev->Text()); + next = ae->GetNextNnl(); + + if (next->Is(CT_ANNOTATION)) + { + LOG_FMT(LANNOT, "%s(%d): -- nl_between_annotation\n", + __func__, __LINE__); + newline_iarf(ae, options::nl_between_annotation()); + log_rule_B("nl_between_annotation"); + } + + if (next->Is(CT_NEWLINE)) + { + if (next->Is(CT_ANNOTATION)) + { + LOG_FMT(LANNOT, "%s(%d): -- nl_after_annotation\n", + __func__, __LINE__); + newline_iarf(ae, options::nl_after_annotation()); + log_rule_B("nl_after_annotation"); + } + } + } +} // annotations_newlines + + +bool newlines_between(Chunk *pc_start, Chunk *pc_end, size_t &newlines, E_Scope scope) +{ + if ( pc_start == nullptr + || pc_end == nullptr) + { + return(false); + } + newlines = 0; + + Chunk *it = pc_start; + + for ( ; it->IsNotNullChunk() && it != pc_end; it = it->GetNext(scope)) + { + newlines += it->GetNlCount(); + } + + // newline count is valid if search stopped on expected chunk + return(it == pc_end); +} // newlines_between diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/newlines.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/newlines.h new file mode 100644 index 00000000..f75d6ad5 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/newlines.h @@ -0,0 +1,206 @@ +/** + * @file newlines.h + * prototypes for newlines.c + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef NEWLINES_H_INCLUDED +#define NEWLINES_H_INCLUDED + +#include "chunk.h" + +/** + * Double the newline, if allowed. + */ +void double_newline(Chunk *nl); + +/** + * Remove all extra newlines. + * Modify line breaks as needed. + */ +void newlines_remove_newlines(); + + +/** + * Remove all newlines that fail the checks performed by the can_increase_nl() function + */ +void newlines_remove_disallowed(); + + +/** Step through all chunks, altering newlines inside parens of if/for/while/do as needed. + * Handles the style options: nl_multi_line_sparen_open, nl_multi_line_sparen_close, nl_before_if_closing_paren + */ +void newlines_sparens(); + +//! Step through all chunks. +void newlines_cleanup_braces(bool first); + + +void newlines_cleanup_angles(); + + +//! Handle insertion/removal of blank lines before if/for/while/do and functions +void newlines_insert_blank_lines(); + + +/** + * Handle removal of extra blank lines in functions + * x <= 0: do nothing, x > 0: allow max x-1 blank lines + */ +void newlines_functions_remove_extra_blank_lines(); + + +void newlines_squeeze_ifdef(); + +/** + * In case of consecutive closing parens, which follow a newline, + * the closing paren are altered to different lines, as per the respective opening parens. + * In the given example, first 2 opening paren are in same line, hence the respective closing paren are put in the same line. + * input: + * func1(func2( + * func3( + * func4( + * ) + * ) + * ) + * ); + * output: + * func1(func2( + * func3( + * func4( + * ) + * ) + * )); + */ +void newlines_squeeze_paren_close(); + + +//! removes unnecessary newlines at start and end of a file +void newlines_eat_start_end(); + + +/** + * Searches for a chunk of type chunk_type and moves them, if needed. + * Will not move tokens that are on their own line or have other than + * exactly 1 newline before (UO_pos_comma == TRAIL) or after (UO_pos_comma == LEAD). + * We can't remove a newline if it is right before a preprocessor. + */ +void newlines_chunk_pos(E_Token chunk_type, uncrustify::token_pos_e mode); + + +/** + * Searches for CT_CLASS_COLON and moves them, if needed. + * Also breaks up the args + */ +void newlines_class_colon_pos(E_Token tok); + + +void newlines_cleanup_dup(); + + +void annotations_newlines(); + + +void newline_after_multiline_comment(); + + +//! Handle insertion of blank lines after label colons +void newline_after_label_colon(); + + +/** + * Scans for newline tokens and changes the nl_count. + * A newline token has a minimum nl_count of 1. + * Note that a blank line is actually 2 newlines, unless the newline is the + * first chunk. + * So, most comparisons have +1 below. + */ +void do_blank_lines(); + + +/** + * Clears the PCF_ONE_LINER flag on the current line. + * Done right before inserting a newline. + */ +void undo_one_liner(Chunk *pc); + + +/** + * Does a simple Ignore, Add, Remove, or Force after the given chunk + * + * @param pc The chunk + * @param av The IARF value + */ +void newline_iarf(Chunk *pc, uncrustify::iarf_e av); + + +/** + * Add a newline before the chunk if there isn't already a newline present. + * Virtual braces are skipped, as they do not contribute to the output. + */ +Chunk *newline_add_before(Chunk *pc); + + +/** + * Add a newline after the chunk if there isn't already a newline present. + * Virtual braces are skipped, as they do not contribute to the output. + */ +Chunk *newline_force_before(Chunk *pc); + + +Chunk *newline_add_after(Chunk *pc); + + +Chunk *newline_force_after(Chunk *pc); + + +/** + * Removes any CT_NEWLINE or CT_NL_CONT between start and end. + * Start must be before end on the chunk list. + * If the 'PCF_IN_PREPROC' status differs between two tags, we can't remove + * the newline. + * + * @param start The starting chunk (if it is a newline, it will be removed!) + * @param end The ending chunk (will not be removed, even if it is a newline) + * + * @return true/false - removed something + */ +void newline_del_between(Chunk *start, Chunk *end); + + +/** + * Add a newline between two tokens. + * If there is already a newline between then, nothing is done. + * Otherwise a newline is inserted. + * + * If end is CT_BRACE_OPEN and a comment and newline follow, then + * the brace open is moved instead of inserting a newline. + * + * In this situation: + * if (...) { //comment + * + * you get: + * if (...) //comment + * { + */ +Chunk *newline_add_between(Chunk *start, Chunk *end); + + +/** + * Counts newlines between two chunk elements + * + * @param pc_start chunk from which the counting of newlines will start + * @param pc_end chunk at which the counting of newlines will end + * @param newlines reference in which the amount of newlines will be written to + * (will be initialized with 0) + * @param scope specifies region chunks should/should not be considered. + * + * @return false if pc_start or pc_end are nullptr or if pc_end is not reached + * @return true if above cases are not met + */ +bool newlines_between(Chunk *pc_start, Chunk *pc_end, size_t &newlines, E_Scope scope = E_Scope::ALL); + + +#endif /* NEWLINES_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/option.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/option.cpp new file mode 100644 index 00000000..ea29d065 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/option.cpp @@ -0,0 +1,1324 @@ +/** + * @file option.cpp + * Parses the options from the config file. + * + * @author Ben Gardner + * @author Guy Maurel October 2015, 2021 + * @author Matthew Woehlke since version 0.67 + * @license GPL v2+ + */ + +#include "option.h" + +#include "keywords.h" +#include "uncrustify.h" +#include "uncrustify_version.h" + +#include <fstream> +#include <unordered_map> + +#include <cctype> // to get std::tolower +#include <cstdarg> // to get va_start, va_end + + +namespace uncrustify +{ + +namespace +{ + +static const char *DOC_TEXT_END = u8R"___( +# Meaning of the settings: +# Ignore - do not do any changes +# Add - makes sure there is 1 or more space/brace/newline/etc +# Force - makes sure there is exactly 1 space/brace/newline/etc, +# behaves like Add in some contexts +# Remove - removes space/brace/newline/etc +# +# +# - Token(s) can be treated as specific type(s) with the 'set' option: +# `set tokenType tokenString [tokenString...]` +# +# Example: +# `set BOOL __AND__ __OR__` +# +# tokenTypes are defined in src/token_enum.h, use them without the +# 'CT_' prefix: 'CT_BOOL' => 'BOOL' +# +# +# - Token(s) can be treated as type(s) with the 'type' option. +# `type tokenString [tokenString...]` +# +# Example: +# `type int c_uint_8 Rectangle` +# +# This can also be achieved with `set TYPE int c_uint_8 Rectangle` +# +# +# To embed whitespace in tokenStrings use the '\' escape character, or quote +# the tokenStrings. These quotes are supported: "'` +# +# +# - Support for the auto detection of languages through the file ending can be +# added using the 'file_ext' command. +# `file_ext langType langString [langString..]` +# +# Example: +# `file_ext CPP .ch .cxx .cpp.in` +# +# langTypes are defined in uncrusify_types.h in the lang_flag_e enum, use +# them without the 'LANG_' prefix: 'LANG_CPP' => 'CPP' +# +# +# - Custom macro-based indentation can be set up using 'macro-open', +# 'macro-else' and 'macro-close'. +# `(macro-open | macro-else | macro-close) tokenString` +# +# Example: +# `macro-open BEGIN_TEMPLATE_MESSAGE_MAP` +# `macro-open BEGIN_MESSAGE_MAP` +# `macro-close END_MESSAGE_MAP` +# +# +)___"; + + +std::vector<OptionGroup> option_groups; +std::unordered_map<std::string, GenericOption *> option_map; + +#define LOG_CONFIG(...) \ + log_config(); LOG_FMT(LNOTE, __VA_ARGS__); + + +//----------------------------------------------------------------------------- +constexpr int option_level(int major, int minor, int patch = 0) +{ + return((major << 20) | (minor << 10) | (patch << 0)); +} + + +//----------------------------------------------------------------------------- +void log_config() +{ + // Print the name of the configuration file only once + static bool config_name_logged = false; + + if (!config_name_logged) + { + LOG_FMT(LNOTE, "log_config: the configuration file is: %s\n", + cpd.filename.c_str()); + config_name_logged = true; + } +} + + +//----------------------------------------------------------------------------- +// This identity function exists so that all Option<T>::str can simply call +// to_string(m_val); this function will be used by Option<string> +std::string to_string(const std::string &in) +{ + return(in); +} + +using std::to_string; + + +//----------------------------------------------------------------------------- +std::string to_lower(const char *in, std::string::size_type size = 0) +{ + std::string out; + + if (size > 0) + { + out.reserve(size); + } + + while (*in) + { + out += static_cast<char>(std::tolower(*in)); + ++in; + } + return(out); +} + + +//----------------------------------------------------------------------------- +std::string to_lower(const std::string &in) +{ + return(to_lower(in.data(), in.size())); +} + + +//----------------------------------------------------------------------------- +bool is_arg_sep(int ch) +{ + return( isspace(ch) + || ch == ',' + || ch == '='); +} + + +//----------------------------------------------------------------------------- +bool is_varg_sep(int ch) +{ + return(ch == '.'); +} + + +//----------------------------------------------------------------------------- +std::vector<std::string> split_args(std::string in, const char *filename, + bool (*is_sep)(int)) +{ + std::vector<std::string> out; + std::string::size_type n = 0; + std::string::size_type k = in.size(); + + // Parse input string + while (n < k) + { + // Skip leading space + while ( n < k + && is_sep(in[n])) + { + ++n; + } + + // Detect comments or trailing space + if ( n >= k + || in[n] == '#') + { + break; + } + + // Detect and extract quoted string + if (const auto *quote = strchr("\'\"`", in[n])) + { + const auto start = ++n; + + for ((void)n; in[n] != *quote; ++n) + { + if ( n < k + && in[n] == '\\') + { + in.erase(n, 1); + --k; + } + + if (n >= k) + { + OptionWarning w{ filename }; + w("found unterminated quoted-string"); + return{}; + } + } + + out.push_back(in.substr(start, n - start)); + + if ( ++n < k + && !is_sep(in[n])) + { + OptionWarning w{ filename }; + w("unexpected text following quoted-string"); + return{}; + } + continue; + } + // Extract anything else + const auto start = n; + + for ((void)n; + ( n < k + && !is_sep(in[n])); + ++n) + { + if (in[n] == '\\') + { + in.erase(n, 1); + --k; + } + + if (n >= k) + { + OptionWarning w{ filename }; + w("found unterminated quoted-string"); + return{}; + } + } + + out.push_back(in.substr(start, n - start)); + } + return(out); +} // split_args + + +//----------------------------------------------------------------------------- +bool is_path_relative(const std::string &path) +{ + assert(!path.empty()); + +#ifdef WIN32 + // Check for partition labels as indication for an absolute path + // 'X:\path\to\file' style absolute disk path + if ( path.size() > 1 + && isalpha(path[0]) + && path[1] == ':') + { + return(false); + } + + // Check for double backslashes as indication for a network path + // '\\server\path\to\file style' absolute UNC path + if ( path.size() > 1 + && path[0] == '\\' + && path[1] == '\\') + { + return(false); + } +#endif + + // Check for a slash as indication for a filename with leading path + // '/path/to/file' style absolute path + return(path[0] != '/'); +} + + +//----------------------------------------------------------------------------- +void print_description(FILE *pfile, std::string description, + const char *eol_marker) +{ + // Descriptions always start with a '\n', so skip the first character + for (std::string::size_type start = 1, length = description.length(); + ( start != std::string::npos + && start < length); + ++start) + { + // Check for empty line so we can squelch trailing whitespace + if (description[start] == '\n') + { + fprintf(pfile, "#%s", eol_marker); + } + else + { + const auto end = description.find('\n', start); + fprintf(pfile, "# %s%s", + description.substr(start, end - start).c_str(), eol_marker); + start = end; + } + } +} + + +//----------------------------------------------------------------------------- +bool process_option_line_compat_0_68(const std::string &cmd, + const std::vector<std::string> &args, + const char *filename) +{ + if (cmd == "sp_cpp_lambda_paren") + { + OptionWarning w{ filename, OptionWarning::MINOR }; + w("option '%s' is deprecated; use '%s' instead", + cmd.c_str(), options::sp_cpp_lambda_square_paren.name()); + + UNUSED(options::sp_cpp_lambda_square_paren.read(args[1].c_str())); + return(true); + } + return(false); +} // process_option_line_compat_0_68 + + +bool process_option_line_compat_0_70(const std::string &cmd, const char *filename) +{ + if (cmd == "sp_word_brace") // Issue #2428 + { + OptionWarning w{ filename, OptionWarning::MINOR }; + w("option '%s' is deprecated; did you want to use '%s' instead?", + cmd.c_str(), options::sp_type_brace_init_lst.name()); + + //UNUSED(options::sp_type_brace_init_lst.read(args[1].c_str())); + return(true); + } + return(false); +} // process_option_line_compat_0_70 + + +bool process_option_line_compat_0_73(const std::string &cmd, const char *filename) +{ + if (cmd == "indent_sing_line_comments") // Issue #3249 + { + OptionWarning w{ filename, OptionWarning::MINOR }; + w("option '%s' is deprecated; did you want to use '%s' instead?", + cmd.c_str(), options::indent_single_line_comments_before.name()); + + //UNUSED(options::indent_single_line_comments_before.read(args[1].c_str())); + return(true); + } + + if (cmd == "sp_before_tr_emb_cmt") // Issue #3339 + { + OptionWarning w{ filename, OptionWarning::MINOR }; + w("option '%s' is deprecated; did you want to use '%s' instead?", + cmd.c_str(), options::sp_before_tr_cmt.name()); + + //UNUSED(options::sp_before_tr_cmt.read(args[1].c_str())); + return(true); + } + + if (cmd == "sp_num_before_tr_emb_cmt") // Issue #3339 + { + OptionWarning w{ filename, OptionWarning::MINOR }; + w("option '%s' is deprecated; did you want to use '%s' instead?", + cmd.c_str(), options::sp_num_before_tr_cmt.name()); + + //UNUSED(options::sp_num_before_tr_cmt.read(args[1].c_str())); + return(true); + } + return(false); +} // process_option_line_compat_0_73 + + +bool process_option_line_compat_0_74(const std::string &cmd, const char *filename) +{ + if (cmd == "sp_type_question") // PR #3638 + { + OptionWarning w{ filename, OptionWarning::MINOR }; + w("option '%s' is deprecated; did you want to use '%s' instead?", + cmd.c_str(), options::sp_before_ptr_star.name()); + + return(true); + } + return(false); +} // process_option_line_compat_0_74 + + +bool process_option_line_compat_0_75(const std::string &cmd, const char *filename) +{ + if (cmd == "pp_space") + { + OptionWarning w{ filename, OptionWarning::MINOR }; + w("option '%s' is deprecated; it has been replaced by '%s'.", + cmd.c_str(), options::pp_space_after.name()); + + return(true); + } + + if (cmd == "pp_space_before") + { + OptionWarning w{ filename, OptionWarning::MINOR }; + w("option '%s' is deprecated; it was a temporary option used\n" + "during the development of version 0.76. Use '%s' and '%s' instead.", + cmd.c_str(), options::pp_indent.name(), options::pp_indent_count.name()); + + return(true); + } + return(false); +} // process_option_line_compat_0_75 + + +bool process_option_line_compat_0_76(const std::string &cmd, const std::vector<std::string> &args, const char *filename) +{ + if (cmd == "nl_func_var_def_blk") + { + OptionWarning w{ filename, OptionWarning::MINOR }; + w("option '%s' is deprecated; it has been replaced by '%s'.\n" + "You can also use '%s' for additional functionality", + cmd.c_str(), options::nl_var_def_blk_end_func_top.name(), + options::nl_var_def_blk_end.name()); + + UNUSED(options::nl_var_def_blk_end_func_top.read(args[1].c_str())); + return(true); + } + return(false); +} // process_option_line_compat_0_76 + +} // namespace + +/////////////////////////////////////////////////////////////////////////////// + +//BEGIN Option<T> and helpers + + +//----------------------------------------------------------------------------- +OptionWarning::OptionWarning(const char *filename, Severity severity) +{ + UNUSED(severity); + + if (cpd.line_number != 0) + { + fprintf(stderr, "%s:%u: ", filename, cpd.line_number); + } + else + { + fprintf(stderr, "%s: ", filename); + } +} + + +//----------------------------------------------------------------------------- +OptionWarning::OptionWarning(const GenericOption *opt, Severity severity) +{ + UNUSED(severity); + + fprintf(stderr, "Option<%s>: at %s:%d: ", to_string(opt->type()), + cpd.filename.c_str(), cpd.line_number); +} + + +//----------------------------------------------------------------------------- +OptionWarning::~OptionWarning() +{ + fprintf(stderr, "\n"); + log_flush(true); +} + + +//----------------------------------------------------------------------------- +void OptionWarning::operator()(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + + +//----------------------------------------------------------------------------- +void GenericOption::warnUnexpectedValue(const char *actual) const +{ + OptionWarning w{ this }; + + auto values = possibleValues(); + + if (values[1] == nullptr) + { + w("Expected %s ", *values); + } + else + { + w("Expected one of "); + + while (*values) + { + w("'%s'", *values); + + if (*(++values)) + { + w(", "); + } + } + } + w(", for '%s'; got '%s'", name(), actual); +} + + +//----------------------------------------------------------------------------- +void GenericOption::warnIncompatibleReference(const GenericOption *ref) const +{ + OptionWarning w{ this }; + + w("%s references option %s with incompatible type %s", + name(), ref->name(), to_string(ref->type())); +} + + +//----------------------------------------------------------------------------- +template<typename T> +bool read_enum(const char *in, Option<T> &out) +{ + assert(in); + + if (convert_string(in, out.m_val)) + { + return(true); + } + + if (const auto *const opt = find_option(in)) + { + if (opt->type() != out.type()) + { + out.warnIncompatibleReference(opt); + return(false); + } + auto &topt = *static_cast<const Option<T> *>(opt); + out.m_val = topt(); + return(true); + } + out.warnUnexpectedValue(in); + return(false); +} + + +//----------------------------------------------------------------------------- +template<typename T> +bool read_number(const char *in, Option<T> &out) +{ + assert(in); + + char *c; + const auto val = std::strtol(in, &c, 10); + + if ( *c == 0 + && out.validate(val)) + { + out.m_val = static_cast<T>(val); + return(true); + } + bool invert = false; + + if (strchr("-", in[0])) + { + invert = true; + ++in; + } + + if (const auto *const opt = find_option(in)) + { + LOG_CONFIG("%s(%d): line_number is %d, option(%s) %s, ref(%s) %s\n", + __func__, __LINE__, cpd.line_number, + to_string(out.type()), out.name(), + to_string(opt->type()), opt->name()); + + long tval; + + if (opt->type() == OT_NUM) + { + auto &sopt = *static_cast<const Option<signed> *>(opt); + tval = static_cast<long>(sopt()); + } + else if (opt->type() == OT_UNUM) + { + auto &uopt = *static_cast<const Option<unsigned> *>(opt); + tval = static_cast<long>(uopt()); + } + else + { + out.warnIncompatibleReference(opt); + return(false); + } + const auto rval = (invert ? -tval : tval); + + if (out.validate(rval)) + { + out.m_val = static_cast<T>(rval); + return(true); + } + return(false); + } + out.warnUnexpectedValue(in); + return(false); +} // read_number + + +//----------------------------------------------------------------------------- +template<typename T> +void Option<T>::reset() +{ + m_val = m_default; +} + + +//----------------------------------------------------------------------------- +template<typename T> +std::string Option<T>::str() const +{ + return(to_string(m_val)); +} + + +//----------------------------------------------------------------------------- +template<typename T> +std::string Option<T>::defaultStr() const +{ + return(m_default != T{} ? to_string(m_default) : std::string{}); +} + +// Explicit instantiations +template class Option<bool>; +template class Option<iarf_e>; +template class Option<line_end_e>; +template class Option<token_pos_e>; +template class Option<signed>; +template class Option<unsigned>; +template class Option<std::string>; + +//END Option<T> and helpers + +/////////////////////////////////////////////////////////////////////////////// + +//BEGIN Option<bool> + + +//----------------------------------------------------------------------------- +template<> +option_type_e Option<bool>::type() const +{ + return(OT_BOOL); +} + + +//----------------------------------------------------------------------------- +template<> +const char *const *Option<bool>::possibleValues() const +{ + static char const *values[] = { "true", "false", nullptr }; + + return(values); +} + + +//----------------------------------------------------------------------------- +template<> +bool Option<bool>::read(const char *in) +{ + assert(in); + + if (convert_string(in, m_val)) + { + return(true); + } + bool invert = false; + + if (strchr("~!-", in[0])) + { + invert = true; + ++in; + } + + if (const auto *const opt = find_option(in)) + { + if (opt->type() != OT_BOOL) + { + warnIncompatibleReference(opt); + return(false); + } + auto &bopt = *static_cast<const Option<bool> *>(opt); + m_val = (invert ? !bopt() : bopt()); + return(true); + } + warnUnexpectedValue(in); + return(false); +} + +//END Option<bool> + +/////////////////////////////////////////////////////////////////////////////// + +//BEGIN Option<iarf_e> + + +//----------------------------------------------------------------------------- +template<> +option_type_e Option<iarf_e>::type() const +{ + return(OT_IARF); +} + + +//----------------------------------------------------------------------------- +template<> +const char *const *Option<iarf_e>::possibleValues() const +{ + return(iarf_values); +} + + +//----------------------------------------------------------------------------- +template<> +bool Option<iarf_e>::read(const char *in) +{ + return(read_enum(in, *this)); +} + +//END Option<iarf_e> + +/////////////////////////////////////////////////////////////////////////////// + +//BEGIN Option<line_end_e> + + +//----------------------------------------------------------------------------- +template<> +option_type_e Option<line_end_e>::type() const +{ + return(OT_LINEEND); +} + + +//----------------------------------------------------------------------------- +template<> +const char *const *Option<line_end_e>::possibleValues() const +{ + return(line_end_values); +} + + +//----------------------------------------------------------------------------- +template<> +bool Option<line_end_e>::read(const char *in) +{ + return(read_enum(in, *this)); +} + +//END Option<line_end_e> + +/////////////////////////////////////////////////////////////////////////////// + +//BEGIN Option<token_pos_e> + + +//----------------------------------------------------------------------------- +template<> +option_type_e Option<token_pos_e>::type() const +{ + return(OT_TOKENPOS); +} + + +//----------------------------------------------------------------------------- +template<> +const char *const *Option<token_pos_e>::possibleValues() const +{ + return(token_pos_values); +} + + +//----------------------------------------------------------------------------- +template<> +bool Option<token_pos_e>::read(const char *in) +{ + return(read_enum(in, *this)); +} + +//END Option<token_pos_e> + +/////////////////////////////////////////////////////////////////////////////// + +//BEGIN Option<signed> + + +//----------------------------------------------------------------------------- +template<> +option_type_e Option<signed>::type() const +{ + return(OT_NUM); +} + + +//----------------------------------------------------------------------------- +template<> +const char *const *Option<signed>::possibleValues() const +{ + static char const *values[] = { "number", nullptr }; + + return(values); +} + + +//----------------------------------------------------------------------------- +template<> +bool Option<signed>::read(const char *in) +{ + return(read_number(in, *this)); +} + +//END Option<signed> + +/////////////////////////////////////////////////////////////////////////////// + +//BEGIN Option<unsigned> + + +//----------------------------------------------------------------------------- +template<> +option_type_e Option<unsigned>::type() const +{ + return(OT_UNUM); +} + + +//----------------------------------------------------------------------------- +template<> +const char *const *Option<unsigned>::possibleValues() const +{ + static char const *values[] = { "unsigned number", nullptr }; + + return(values); +} + + +//----------------------------------------------------------------------------- +template<> +bool Option<unsigned>::read(const char *in) +{ + return(read_number(in, *this)); +} + +//END Option<unsigned> + +/////////////////////////////////////////////////////////////////////////////// + +//BEGIN Option<string> + + +//----------------------------------------------------------------------------- +template<> +option_type_e Option<std::string>::type() const +{ + return(OT_STRING); +} + + +//----------------------------------------------------------------------------- +template<> +const char *const *Option<std::string>::possibleValues() const +{ + static char const *values[] = { "string", nullptr }; + + return(values); +} + + +//----------------------------------------------------------------------------- +template<> +bool Option<std::string>::read(const char *in) +{ + m_val = in; + return(true); +} + +//END Option<string> + +/////////////////////////////////////////////////////////////////////////////// + +//BEGIN global functions for options + + +//----------------------------------------------------------------------------- +void begin_option_group(const char *description) +{ + auto g = OptionGroup{ description, {} }; + + option_groups.push_back(g); +} + + +//----------------------------------------------------------------------------- +void register_option(GenericOption *option) +{ + assert(!option_groups.empty()); + + option_groups.back().options.push_back(option); + option_map.emplace(option->name(), option); +} + + +//----------------------------------------------------------------------------- +uncrustify::GenericOption *find_option(const char *name) +{ + const auto iter = option_map.find(to_lower(name)); + + if (iter != option_map.end()) + { + return(iter->second); + } + return(nullptr); +} + + +//----------------------------------------------------------------------------- +OptionGroup *get_option_group(size_t i) +{ + if (i >= option_groups.size()) + { + return(nullptr); + } + return(&option_groups[i]); +} + + +//----------------------------------------------------------------------------- +size_t get_option_count() +{ + return(option_map.size()); +} + + +//----------------------------------------------------------------------------- +void process_option_line(const std::string &config_line, const char *filename, + int &compat_level) +{ + // Split line into arguments, and punt if no arguments are present + auto args = split_args(config_line, filename, is_arg_sep); + + if (args.empty()) + { + return; + } + // Check for necessary arguments + const auto &cmd = to_lower(args.front()); + + if ( cmd == "set" + || cmd == "file_ext") + { + if (args.size() < 3) + { + OptionWarning w{ filename }; + w("%s requires at least three arguments", cmd.c_str()); + return; + } + } + else + { + if (args.size() < 2) + { + OptionWarning w{ filename }; + w("%s requires at least two arguments", cmd.c_str()); + return; + } + } + + if (cmd == "type") + { + for (size_t i = 1; i < args.size(); ++i) + { + add_keyword(args[i], CT_TYPE); + } + } + else if (cmd == "macro-open") + { + add_keyword(args[1], CT_MACRO_OPEN); + } + else if (cmd == "macro-close") + { + add_keyword(args[1], CT_MACRO_CLOSE); + } + else if (cmd == "macro-else") + { + add_keyword(args[1], CT_MACRO_ELSE); + } + else if (cmd == "set") + { + const auto token = find_token_name(args[1].c_str()); + + if (token != CT_NONE) + { + LOG_FMT(LNOTE, "%s:%d set '%s':", + filename, cpd.line_number, args[1].c_str()); + + for (size_t i = 2; i < args.size(); ++i) + { + LOG_FMT(LNOTE, " '%s'", args[i].c_str()); + add_keyword(args[i], token); + } + + LOG_FMT(LNOTE, "\n"); + } + else + { + OptionWarning w{ filename }; + w("%s: unknown type '%s'", cmd.c_str(), args[1].c_str()); + } + } +#ifndef EMSCRIPTEN + else if (cmd == "include") + { + auto this_line_number = cpd.line_number; + const auto &include_path = args[1]; + + if (include_path.empty()) + { + OptionWarning w{ filename }; + w("include: path cannot be empty"); + } + else if (is_path_relative(include_path)) + { + // include is a relative path to the current config file + unc_text ut = std::string{ filename }; + ut.resize(static_cast<unsigned>(path_dirname_len(filename))); + ut.append(include_path); + UNUSED(load_option_file(ut.c_str(), compat_level)); + } + else + { + // include is an absolute path + UNUSED(load_option_file(include_path.c_str(), compat_level)); + } + cpd.line_number = this_line_number; + } +#endif + else if (cmd == "file_ext") + { + auto *const lang_arg = args[1].c_str(); + + for (size_t i = 2; i < args.size(); ++i) + { + auto *const lang_name = extension_add(args[i].c_str(), lang_arg); + + if (lang_name) + { + LOG_FMT(LNOTE, "%s:%d file_ext '%s' => '%s'\n", + filename, cpd.line_number, args[i].c_str(), lang_name); + } + else + { + OptionWarning w{ filename }; + w("file_ext: unknown language '%s'", lang_arg); + break; + } + } + } + else if (cmd == "using") + { + auto vargs = split_args(args[1], filename, is_varg_sep); + + if (vargs.size() == 2) + { + compat_level = option_level(std::stoi(vargs[0]), std::stoi(vargs[1])); + } + else if (vargs.size() == 3) + { + compat_level = option_level(std::stoi(vargs[0]), + std::stoi(vargs[1]), + std::stoi(vargs[2])); + } + else + { + OptionWarning w{ filename }; + w("%s requires a version number in the form MAJOR.MINOR[.PATCH]", + cmd.c_str()); + } + } + else + { + // Must be a regular option = value + if (compat_level < option_level(0, 69)) + { + if (process_option_line_compat_0_68(cmd, args, filename)) + { + return; + } + } + + if (compat_level < option_level(0, 71)) + { + if (process_option_line_compat_0_70(cmd, filename)) + { + return; + } + } + + if (compat_level < option_level(0, 74)) + { + if (process_option_line_compat_0_73(cmd, filename)) + { + return; + } + } + + if (compat_level < option_level(0, 75)) + { + if (process_option_line_compat_0_74(cmd, filename)) + { + return; + } + } + + if (compat_level < option_level(0, 76)) + { + if (process_option_line_compat_0_75(cmd, filename)) + { + return; + } + } + + if (compat_level < option_level(0, 77)) + { + if (process_option_line_compat_0_76(cmd, args, filename)) + { + return; + } + } + const auto oi = option_map.find(cmd); + + if (oi == option_map.end()) + { + OptionWarning w{ filename }; + w("unknown option '%s'", args[0].c_str()); + } + else + { + UNUSED(oi->second->read(args[1].c_str())); + } + } +} // process_option_line + + +//----------------------------------------------------------------------------- +bool load_option_file(const char *filename, int compat_level) +{ + cpd.line_number = 0; + +#ifdef WIN32 + // "/dev/null" not understood by "fopen" in Windows + if (strcasecmp(filename, "/dev/null") == 0) + { + return(true); + } +#endif + + std::ifstream in; + in.open(filename, std::ifstream::in); + + if (!in.good()) + { + OptionWarning w{ filename }; + w("file could not be opened: %s (%d)\n", + strerror(errno), errno); + exit(EX_SOFTWARE); + } + // Read in the file line by line + std::string line; + + while (std::getline(in, line)) + { + // check all characters of the line + size_t howmany = line.length(); + int ch; + + for (size_t n = 0; n < howmany; n++) + { + ch = line[n]; + + // do not check characters in comment part of line + if ('#' == ch) + { + break; + } + + // ch >= 0 && ch <= 255 + if ( ch < 0 + || ch > 255) + { + // error + // related to PR #3298 + fprintf(stderr, "%s: line %u: Character at position %zu, is not printable.\n", filename, cpd.line_number + 1, n + 1); + exit(EX_SOFTWARE); + } + } + + ++cpd.line_number; + process_option_line(line, filename, compat_level); + } + return(true); +} // load_option_file + + +//----------------------------------------------------------------------------- +const char *get_eol_marker() +{ + static char eol[3] = { 0x0A, 0x00, 0x00 }; + + const auto &lines = cpd.newline.get(); + + for (size_t i = 0; i < lines.size(); ++i) + { + eol[i] = static_cast<char>(lines[i]); + } + + return(eol); +} + + +//----------------------------------------------------------------------------- +void save_option_file(FILE *pfile, bool with_doc, bool minimal) +{ + int non_default_values = 0; + const char *eol_marker = get_eol_marker(); + + fprintf(pfile, "# %s%s", UNCRUSTIFY_VERSION, eol_marker); + + // Print the options by group + for (auto &og : option_groups) + { + bool first = true; + + for (auto *option : og.options) + { + const auto val = option->str(); + + if (!option->isDefault()) + { + ++non_default_values; + } + else if (minimal) + { + continue; + } + //.................................................................... + + if (with_doc) + { + assert(option->description() != nullptr); + assert(*option->description() != 0); + + if (first) + { + fprintf(pfile, "%s#%s", eol_marker, eol_marker); + print_description(pfile, og.description, eol_marker); + fprintf(pfile, "#%s", eol_marker); + } + fprintf(pfile, "%s", eol_marker); + print_description(pfile, option->description(), eol_marker); + + const auto ds = option->defaultStr(); + + if (!ds.empty()) + { + fprintf(pfile, "#%s# Default: %s%s", + eol_marker, ds.c_str(), eol_marker); + } + } + first = false; + + const int name_len = static_cast<int>(strlen(option->name())); + const int pad = name_len < uncrustify::limits::MAX_OPTION_NAME_LEN + ? (uncrustify::limits::MAX_OPTION_NAME_LEN - name_len) + : 1; + + fprintf(pfile, "%s%*.s= ", option->name(), pad, " "); + + if (option->type() == OT_STRING) + { + fprintf(pfile, "\"%s\"", val.c_str()); + } + else + { + fprintf(pfile, "%s", val.c_str()); + } + + if (with_doc) + { + const int val_len = static_cast<int>(val.length()); + fprintf(pfile, "%*.s # ", 8 - val_len, " "); + + for (auto pv = option->possibleValues(); *pv; ++pv) + { + fprintf(pfile, "%s%s", *pv, pv[1] ? "/" : ""); + } + } + fputs(eol_marker, pfile); + } + } + + if (with_doc) + { + fprintf(pfile, "%s", DOC_TEXT_END); + } + print_custom_keywords(pfile); // Print custom keywords + print_extensions(pfile); // Print custom file extensions + + fprintf(pfile, "# option(s) with 'not default' value: %d%s#%s", + non_default_values, eol_marker, eol_marker); +} // save_option_file + +} // namespace uncrustify diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/option.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/option.h new file mode 100644 index 00000000..7b961940 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/option.h @@ -0,0 +1,365 @@ +/** + * @file option.h + * Enumerations and data types for options. + * + * @author Ben Gardner + * @author Guy Maurel since version 0.62 for uncrustify4Qt + * October 2015, 2016 + * @author Matthew Woehlke since version 0.67 + * @license GPL v2+ + */ +#ifndef OPTION_H_INCLUDED +#define OPTION_H_INCLUDED + +/* NOTE: + * This file is processed by make_option_enum.py, which parses any 'enum class' + * it finds, as well as the special macros UNC_OPTVAL_ALIAS and UNC_OPTVALS. + * + * The '// <PREFIX>' comment after an 'enum class' tells the script to generate + * aliases for the enum values using the prefix that is given in the '<>'s. + * Don't remove or alter these. + */ + +#include "enum_flags.h" + +#include <string> +#include <vector> + +#include <cassert> + +#ifdef IGNORE // WinBase.h +#undef IGNORE +#endif + +namespace uncrustify +{ + +template<typename T> class Option; + +//----------------------------------------------------------------------------- +// Option types +enum class option_type_e // <OT> +{ + // UNC_CONVERT_INTERNAL + BOOL, + IARF, + LINEEND, + TOKENPOS, + NUM, + UNUM, + STRING, +}; + +#if 0 // Fake enumeration for make_option_enum.py +enum class bool +{ + true, + false, +}; +#endif + +//----------------------------------------------------------------------------- +/// I/A/R/F values - these are bit fields +enum class iarf_e // <IARF> +{ + IGNORE = 0, //! option ignores a given feature + ADD = (1u << 0), //! option adds a given feature + REMOVE = (1u << 1), //! option removes a given feature + FORCE = (ADD | REMOVE), //! option forces the usage of a given feature + NOT_DEFINED = (1u << 2) //! for debugging +}; + +UNC_DECLARE_FLAGS(iarf_flags_t, iarf_e); +UNC_DECLARE_OPERATORS_FOR_FLAGS(iarf_flags_t); + +//----------------------------------------------------------------------------- +/// Line endings +enum class line_end_e // <LE> +{ + LF, //! "\n" typically used on Unix/Linux system + CRLF, //! "\r\n" typically used on Windows systems + CR, //! "\r" carriage return without newline + AUTO, //! keep last +}; +constexpr auto line_end_styles = static_cast<size_t>(line_end_e::AUTO); + +//----------------------------------------------------------------------------- +/// Token position - these are bit fields +enum class token_pos_e // <TP> +{ + IGNORE = 0, //! don't change it + BREAK = 1, //! add a newline before or after the if not present + FORCE = 2, //! force a newline on one side and not the other + LEAD = 4, //! at the start of a line or leading if wrapped line + TRAIL = 8, //! at the end of a line or trailing if wrapped line + JOIN = 16, //! remove newlines on both sides + LEAD_BREAK = (LEAD | BREAK), // 5 + LEAD_FORCE = (LEAD | FORCE), // 6 + TRAIL_BREAK = (TRAIL | BREAK), // 9 + TRAIL_FORCE = (TRAIL | FORCE), // 10 +}; + +UNC_DECLARE_FLAGS(token_pos_flags_t, token_pos_e); +UNC_DECLARE_OPERATORS_FOR_FLAGS(token_pos_flags_t); + +//----------------------------------------------------------------------------- +/// Abstract (untyped) interface for options +class GenericOption +{ +public: + GenericOption(const char *opt_name, const char *opt_desc) + : m_name{opt_name} + , m_desc{opt_desc} + {} + + virtual ~GenericOption() = default; + + virtual option_type_e type() const = 0; + const char *name() const { return(m_name); } + const char *description() const { return(m_desc); } + virtual const char *const *possibleValues() const = 0; + + virtual std::string defaultStr() const = 0; + virtual std::string minStr() const { return(std::string{}); } + virtual std::string maxStr() const { return(std::string{}); } + + virtual bool isDefault() const = 0; + + virtual void reset() = 0; + virtual bool read(const char *s) = 0; + virtual std::string str() const = 0; + +protected: + template<typename V> friend bool read_enum(const char *s, Option<V> &o); + template<typename V> friend bool read_number(const char *s, Option<V> &o); + + void warnUnexpectedValue(const char *actual) const; + void warnIncompatibleReference(const GenericOption *ref) const; + + const char *const m_name; + const char *const m_desc; +}; + +//----------------------------------------------------------------------------- +// Helper class for reporting problems with options +class OptionWarning +{ +public: + enum class /* UNC_NO_META */ Severity + { + OS_CRITICAL, + OS_MINOR, + }; + + constexpr static auto CRITICAL = Severity::OS_CRITICAL; + constexpr static auto MINOR = Severity::OS_MINOR; + + OptionWarning(const char *filename, Severity = CRITICAL); + OptionWarning(const GenericOption *, Severity = CRITICAL); + OptionWarning(const OptionWarning &) = delete; + ~OptionWarning(); + +#ifdef __GNUC__ + [[gnu::format(printf, 2, 3)]] +#endif + void operator()(const char *fmt, ...); +}; + +//----------------------------------------------------------------------------- +// Concrete (strongly typed) interface for options +template<typename T> +class Option : public GenericOption +{ +public: + Option(const char *opt_name, const char *opt_desc, T opt_val = T{}) + : GenericOption{opt_name, opt_desc} + , m_val{opt_val} + , m_default{opt_val} + {} + + option_type_e type() const override; + const char *const *possibleValues() const override; + + std::string defaultStr() const override; + + bool isDefault() const override { return(m_val == m_default); } + + //! resets option to its default value + //- currently only used by the emscripten interface + virtual void reset() override; + + bool read(const char *s) override; + std::string str() const override; + + T operator()() const { return(m_val); } + Option &operator=(T val) { m_val = val; return(*this); } + +protected: + template<typename V> friend bool read_enum(const char *s, Option<V> &o); + template<typename V> friend bool read_number(const char *s, Option<V> &o); + + virtual bool validate(long) { return(true); } + + T m_val = T{}; + T m_default = T{}; +}; + +//----------------------------------------------------------------------------- +// Concrete (strongly typed) interface for bounded numeric options +template<typename T, T min, T max> +class BoundedOption : public Option<T> +{ +public: + BoundedOption(const char *opt_name, const char *opt_desc, T opt_val = T{}) + : Option<T>{opt_name, opt_desc, opt_val} + { + assert( opt_val >= min + && opt_val <= max); + } + + std::string minStr() const override { return(std::to_string(min)); } + std::string maxStr() const override { return(std::to_string(max)); } + +protected: + bool validate(long val) override + { + if (val < static_cast<long>(min)) + { + OptionWarning w{ this }; + w("requested value %ld for option '%s' " + "is less than the minimum value %ld", + val, this->name(), static_cast<long>(min)); + return(false); + } + + if (val > static_cast<long>(max)) + { + OptionWarning w{ this }; + w("requested value %ld for option '%s' " + "is greater than the maximum value %ld", + val, this->name(), static_cast<long>(max)); + return(false); + } + return(true); + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +// Declaration of option types; implementations are in option.cpp +#define UNC_IMPLEMENT_OPTION(T) \ + template<> option_type_e Option<T>::type() const; \ + template<> const char *const *Option<T>::possibleValues() const; \ + template<> bool Option<T>::read(const char *s); \ + extern template class Option<T> + +UNC_IMPLEMENT_OPTION(bool); +UNC_IMPLEMENT_OPTION(iarf_e); +UNC_IMPLEMENT_OPTION(line_end_e); +UNC_IMPLEMENT_OPTION(token_pos_e); +UNC_IMPLEMENT_OPTION(signed); +UNC_IMPLEMENT_OPTION(unsigned); +UNC_IMPLEMENT_OPTION(std::string); + +// Additional mappings for option values +#define UNC_OPTVAL_ALIAS(...) \ + static_assert(true, "This is just a tag for make_option_enum.py") + +UNC_OPTVAL_ALIAS(bool, false, "0", "f", "n", "no"); +UNC_OPTVAL_ALIAS(bool, true, "1", "t", "y", "yes"); +UNC_OPTVAL_ALIAS(iarf_e, IGNORE, "i"); +UNC_OPTVAL_ALIAS(iarf_e, ADD, "a", "2", "t", "true", "y", "yes"); +UNC_OPTVAL_ALIAS(iarf_e, REMOVE, "r", "0", "f", "false", "n", "no"); +UNC_OPTVAL_ALIAS(iarf_e, FORCE, "f", "1"); + +// Possible values for options, by type +#define UNC_OPTVALS(e) extern const char *const e ## _values[] +UNC_OPTVALS(iarf); +UNC_OPTVALS(line_end); +UNC_OPTVALS(token_pos); + +extern bool convert_string(const char *, bool &); +extern bool convert_string(const char *, iarf_e &); +extern bool convert_string(const char *, line_end_e &); +extern bool convert_string(const char *, token_pos_e &); + +extern const char *to_string(bool); +extern const char *to_string(iarf_e); +extern const char *to_string(line_end_e); +extern const char *to_string(token_pos_e); +extern const char *to_string(option_type_e); + +struct OptionGroup +{ + const char *description; + std::vector<GenericOption *> options; +}; + + +/** + * @brief Defines a new group of uncrustify options. + * + * New options are always added to the most recently defined group. + */ +void begin_option_group(const char *description); + + +/** + * @brief Adds an uncrustify option to the global option registry. + * + * The option is added to the most recently defined option group. + */ +void register_option(GenericOption *); + + +GenericOption *find_option(const char *name); + + +//! Add all uncrustify options to the global option registry +void register_options(); + + +OptionGroup *get_option_group(size_t); + + +size_t get_option_count(); + + +/** + * processes a single line string to extract configuration settings + * increments cpd.line_number and cpd.error_count + * + * @param config_line single line string that will be processed + * @param filename for log messages, file from which the \p config_line + * param was extracted + * @param compat_level version of Uncrustify with which to be compatible + */ +void process_option_line(const std::string &config_line, const char *filename, int &compat_level); + + +bool load_option_file(const char *filename, int compat_level = 0); + + +/** + * save the used options into a text file + * + * @param pfile file to print into + * @param with_doc also print description + * @param minimal print only options with non default value + */ +void save_option_file(FILE *pfile, bool with_doc = false, bool minimal = false); + + +/** + * get the marker that was selected for the end of line via the config file + * + * @return "\n" if newlines was set to LE_LF in the config file + * @return "\r\n" if newlines was set to LE_CRLF in the config file + * @return "\r" if newlines was set to LE_CR in the config file + * @return "\n" if newlines was set to LE_AUTO in the config file + */ +const char *get_eol_marker(); + +} // namespace uncrustify + +#endif /* OPTION_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/option_enum.cpp.in b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/option_enum.cpp.in new file mode 100644 index 00000000..aeb976b2 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/option_enum.cpp.in @@ -0,0 +1,24 @@ +##BANNER## +#include "options.h" + +#include "base_types.h" +#include "logger.h" + +#include <cstdlib> + +#ifdef HAVE_STRINGS_H +#include <strings.h> // strcasecmp() +#endif + +#if defined(_MSC_VER) +#pragma warning(disable: 4809) +#elif __GNUC__ > 4 || __clang_major__ > 3 || __clang_minor__ > 4 +#pragma GCC diagnostic ignored "-Wswitch-bool" +#endif + +namespace uncrustify +{ + +##VALUE_STRINGS## +##CONVERSIONS## +} // namespace uncrustify diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/option_enum.h.in b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/option_enum.h.in new file mode 100644 index 00000000..e50a9281 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/option_enum.h.in @@ -0,0 +1,17 @@ +##BANNER## +#ifndef OPTION_ENUM_H_INCLUDED +#define OPTION_ENUM_H_INCLUDED + +#include "option.h" + +#ifdef IGNORE // WinBase.h +#undef IGNORE +#endif + +namespace uncrustify +{ + +##ALIASES## +} // namespace uncrustify + +#endif /* OPTION_ENUM_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/options.cpp.in b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/options.cpp.in new file mode 100644 index 00000000..2ee14c8b --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/options.cpp.in @@ -0,0 +1,26 @@ +##BANNER## + +#include "uncrustify_types.h" + +namespace uncrustify +{ + +//BEGIN declarations of option object instances + +namespace options +{ + +##DECLARATIONS## +} // namespace options + +//END declarations of option object instances + +/////////////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +void register_options(void) +{ +##REGISTRATIONS## +} + +} // namespace uncrustify diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/options.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/options.h new file mode 100644 index 00000000..7fabf1f7 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/options.h @@ -0,0 +1,4303 @@ +/** + * @file options.h + * Declarations of all the options. + * + * September 2020 + * @author Ben Gardner + * @author Guy Maurel + * @author Matthew Woehlke + * @license GPL v2+ + */ + +#ifndef OPTIONS_H_INCLUDED +#define OPTIONS_H_INCLUDED + +/* NOTE: + * This file is processed by make_options.py, and must conform to a particular + * format. Option groups are marked by '//begin ' (in upper case; this example + * is lower case to prevent being considered a region marker for code folding) + * followed by the group description. Options consist of two lines of + * declaration preceded by one or more lines of C++ comments. The comments form + * the option description and are taken verbatim, aside from stripping the + * leading '// '. Only comments immediately preceding an option declaration, + * with no blank lines, are taken as part of the description, so a blank line + * may be used to separate notations from a description. + * + * An option declaration is 'extern TYPE\nNAME;', optionally followed by + * ' // = VALUE' if the option has a default value that is different from the + * default-constructed value type of the option. The 'VALUE' must be valid C++ + * code, and is taken verbatim as an argument when creating the option's + * instantiation. Note also that the line break, as shown, is required. + */ + +#include "option_enum.h" + +namespace uncrustify +{ + +namespace options +{ + +using std::string; + +/////////////////////////////////////////////////////////////////////////////// +//BEGIN General options + +// The type of line endings. +extern Option<line_end_e> +newlines; // = LE_AUTO + +// The original size of tabs in the input. +extern BoundedOption<unsigned, 1, 32> +input_tab_size; // = 8 + +// The size of tabs in the output (only used if align_with_tabs=true). +extern BoundedOption<unsigned, 1, 32> +output_tab_size; // = 8 + +// The ASCII value of the string escape char, usually 92 (\) or (Pawn) 94 (^). +extern BoundedOption<unsigned, 0, 255> +string_escape_char; // = '\\' + +// Alternate string escape char (usually only used for Pawn). +// Only works right before the quote char. +extern BoundedOption<unsigned, 0, 255> +string_escape_char2; + +// Replace tab characters found in string literals with the escape sequence \t +// instead. +extern Option<bool> +string_replace_tab_chars; + +// Allow interpreting '>=' and '>>=' as part of a template in code like +// 'void f(list<list<B>>=val);'. If true, 'assert(x<0 && y>=3)' will be broken. +// Improvements to template detection may make this option obsolete. +extern Option<bool> +tok_split_gte; + +// Disable formatting of NL_CONT ('\\n') ended lines (e.g. multi-line macros). +extern Option<bool> +disable_processing_nl_cont; + +// Specify the marker used in comments to disable processing of part of the +// file. +extern Option<string> +disable_processing_cmt; // = UNCRUSTIFY_OFF_TEXT + +// Specify the marker used in comments to (re)enable processing in a file. +extern Option<string> +enable_processing_cmt; // = UNCRUSTIFY_ON_TEXT + +// Enable parsing of digraphs. +extern Option<bool> +enable_digraphs; + +// Option to allow both disable_processing_cmt and enable_processing_cmt +// strings, if specified, to be interpreted as ECMAScript regular expressions. +// If true, a regex search will be performed within comments according to the +// specified patterns in order to disable/enable processing. +extern Option<bool> +processing_cmt_as_regex; + +// Add or remove the UTF-8 BOM (recommend 'remove'). +extern Option<iarf_e> +utf8_bom; + +// If the file contains bytes with values between 128 and 255, but is not +// UTF-8, then output as UTF-8. +extern Option<bool> +utf8_byte; + +// Force the output encoding to UTF-8. +extern Option<bool> +utf8_force; + +//END + +/////////////////////////////////////////////////////////////////////////////// +//BEGIN Spacing options + +// Add or remove space around non-assignment symbolic operators ('+', '/', '%', +// '<<', and so forth). +extern Option<iarf_e> +sp_arith; + +// Add or remove space around arithmetic operators '+' and '-'. +// +// Overrides sp_arith. +extern Option<iarf_e> +sp_arith_additive; + +// Add or remove space around assignment operator '=', '+=', etc. +extern Option<iarf_e> +sp_assign; + +// Add or remove space around '=' in C++11 lambda capture specifications. +// +// Overrides sp_assign. +extern Option<iarf_e> +sp_cpp_lambda_assign; + +// Add or remove space after the capture specification of a C++11 lambda when +// an argument list is present, as in '[] <here> (int x){ ... }'. +extern Option<iarf_e> +sp_cpp_lambda_square_paren; + +// Add or remove space after the capture specification of a C++11 lambda with +// no argument list is present, as in '[] <here> { ... }'. +extern Option<iarf_e> +sp_cpp_lambda_square_brace; + +// Add or remove space after the opening parenthesis and before the closing +// parenthesis of a argument list of a C++11 lambda, as in +// '[]( <here> int x <here> ){ ... }'. +extern Option<iarf_e> +sp_cpp_lambda_argument_list; + +// Add or remove space after the argument list of a C++11 lambda, as in +// '[](int x) <here> { ... }'. +extern Option<iarf_e> +sp_cpp_lambda_paren_brace; + +// Add or remove space between a lambda body and its call operator of an +// immediately invoked lambda, as in '[]( ... ){ ... } <here> ( ... )'. +extern Option<iarf_e> +sp_cpp_lambda_fparen; + +// Add or remove space around assignment operator '=' in a prototype. +// +// If set to ignore, use sp_assign. +extern Option<iarf_e> +sp_assign_default; + +// Add or remove space before assignment operator '=', '+=', etc. +// +// Overrides sp_assign. +extern Option<iarf_e> +sp_before_assign; + +// Add or remove space after assignment operator '=', '+=', etc. +// +// Overrides sp_assign. +extern Option<iarf_e> +sp_after_assign; + +// Add or remove space in 'enum {'. +extern Option<iarf_e> +sp_enum_brace; // = IARF_ADD + +// Add or remove space in 'NS_ENUM ('. +extern Option<iarf_e> +sp_enum_paren; + +// Add or remove space around assignment '=' in enum. +extern Option<iarf_e> +sp_enum_assign; + +// Add or remove space before assignment '=' in enum. +// +// Overrides sp_enum_assign. +extern Option<iarf_e> +sp_enum_before_assign; + +// Add or remove space after assignment '=' in enum. +// +// Overrides sp_enum_assign. +extern Option<iarf_e> +sp_enum_after_assign; + +// Add or remove space around assignment ':' in enum. +extern Option<iarf_e> +sp_enum_colon; + +// Add or remove space around preprocessor '##' concatenation operator. +extern Option<iarf_e> +sp_pp_concat; // = IARF_ADD + +// Add or remove space after preprocessor '#' stringify operator. +// Also affects the '#@' charizing operator. +extern Option<iarf_e> +sp_pp_stringify; + +// Add or remove space before preprocessor '#' stringify operator +// as in '#define x(y) L#y'. +extern Option<iarf_e> +sp_before_pp_stringify; + +// Add or remove space around boolean operators '&&' and '||'. +extern Option<iarf_e> +sp_bool; + +// Add or remove space around compare operator '<', '>', '==', etc. +extern Option<iarf_e> +sp_compare; + +// Add or remove space inside '(' and ')'. +extern Option<iarf_e> +sp_inside_paren; + +// Add or remove space between nested parentheses, i.e. '((' vs. ') )'. +extern Option<iarf_e> +sp_paren_paren; + +// Add or remove space between back-to-back parentheses, i.e. ')(' vs. ') ('. +extern Option<iarf_e> +sp_cparen_oparen; + +// Whether to balance spaces inside nested parentheses. +extern Option<bool> +sp_balance_nested_parens; + +// Add or remove space between ')' and '{'. +extern Option<iarf_e> +sp_paren_brace; + +// Add or remove space between nested braces, i.e. '{{' vs. '{ {'. +extern Option<iarf_e> +sp_brace_brace; + +// Add or remove space before pointer star '*'. +extern Option<iarf_e> +sp_before_ptr_star; + +// Add or remove space before pointer star '*' that isn't followed by a +// variable name. If set to ignore, sp_before_ptr_star is used instead. +extern Option<iarf_e> +sp_before_unnamed_ptr_star; + +// Add or remove space between pointer stars '*', as in 'int ***a;'. +extern Option<iarf_e> +sp_between_ptr_star; + +// Add or remove space after pointer star '*', if followed by a word. +// +// Overrides sp_type_func. +extern Option<iarf_e> +sp_after_ptr_star; + +// Add or remove space after pointer caret '^', if followed by a word. +extern Option<iarf_e> +sp_after_ptr_block_caret; + +// Add or remove space after pointer star '*', if followed by a qualifier. +extern Option<iarf_e> +sp_after_ptr_star_qualifier; + +// Add or remove space after a pointer star '*', if followed by a function +// prototype or function definition. +// +// Overrides sp_after_ptr_star and sp_type_func. +extern Option<iarf_e> +sp_after_ptr_star_func; + +// Add or remove space after a pointer star '*' in the trailing return of a +// function prototype or function definition. +extern Option<iarf_e> +sp_after_ptr_star_trailing; + +// Add or remove space between the pointer star '*' and the name of the variable +// in a function pointer definition. +extern Option<iarf_e> +sp_ptr_star_func_var; + +// Add or remove space between the pointer star '*' and the name of the type +// in a function pointer type definition. +extern Option<iarf_e> +sp_ptr_star_func_type; + +// Add or remove space after a pointer star '*', if followed by an open +// parenthesis, as in 'void* (*)()'. +extern Option<iarf_e> +sp_ptr_star_paren; + +// Add or remove space before a pointer star '*', if followed by a function +// prototype or function definition. +extern Option<iarf_e> +sp_before_ptr_star_func; + +// Add or remove space before a pointer star '*' in the trailing return of a +// function prototype or function definition. +extern Option<iarf_e> +sp_before_ptr_star_trailing; + +// Add or remove space before a reference sign '&'. +extern Option<iarf_e> +sp_before_byref; + +// Add or remove space before a reference sign '&' that isn't followed by a +// variable name. If set to ignore, sp_before_byref is used instead. +extern Option<iarf_e> +sp_before_unnamed_byref; + +// Add or remove space after reference sign '&', if followed by a word. +// +// Overrides sp_type_func. +extern Option<iarf_e> +sp_after_byref; + +// Add or remove space after a reference sign '&', if followed by a function +// prototype or function definition. +// +// Overrides sp_after_byref and sp_type_func. +extern Option<iarf_e> +sp_after_byref_func; + +// Add or remove space before a reference sign '&', if followed by a function +// prototype or function definition. +extern Option<iarf_e> +sp_before_byref_func; + +// Add or remove space after a reference sign '&', if followed by an open +// parenthesis, as in 'char& (*)()'. +extern Option<iarf_e> +sp_byref_paren; + +// Add or remove space between type and word. In cases where total removal of +// whitespace would be a syntax error, a value of 'remove' is treated the same +// as 'force'. +// +// This also affects some other instances of space following a type that are +// not covered by other options; for example, between the return type and +// parenthesis of a function type template argument, between the type and +// parenthesis of an array parameter, or between 'decltype(...)' and the +// following word. +extern Option<iarf_e> +sp_after_type; // = IARF_FORCE + +// Add or remove space between 'decltype(...)' and word, +// brace or function call. +extern Option<iarf_e> +sp_after_decltype; + +// (D) Add or remove space before the parenthesis in the D constructs +// 'template Foo(' and 'class Foo('. +extern Option<iarf_e> +sp_before_template_paren; + +// Add or remove space between 'template' and '<'. +// If set to ignore, sp_before_angle is used. +extern Option<iarf_e> +sp_template_angle; + +// Add or remove space before '<'. +extern Option<iarf_e> +sp_before_angle; + +// Add or remove space inside '<' and '>'. +extern Option<iarf_e> +sp_inside_angle; + +// Add or remove space inside '<>'. +extern Option<iarf_e> +sp_inside_angle_empty; + +// Add or remove space between '>' and ':'. +extern Option<iarf_e> +sp_angle_colon; + +// Add or remove space after '>'. +extern Option<iarf_e> +sp_after_angle; + +// Add or remove space between '>' and '(' as found in 'new List<byte>(foo);'. +extern Option<iarf_e> +sp_angle_paren; + +// Add or remove space between '>' and '()' as found in 'new List<byte>();'. +extern Option<iarf_e> +sp_angle_paren_empty; + +// Add or remove space between '>' and a word as in 'List<byte> m;' or +// 'template <typename T> static ...'. +extern Option<iarf_e> +sp_angle_word; + +// Add or remove space between '>' and '>' in '>>' (template stuff). +extern Option<iarf_e> +sp_angle_shift; // = IARF_ADD + +// (C++11) Permit removal of the space between '>>' in 'foo<bar<int> >'. Note +// that sp_angle_shift cannot remove the space without this option. +extern Option<bool> +sp_permit_cpp11_shift; + +// Add or remove space before '(' of control statements ('if', 'for', 'switch', +// 'while', etc.). +extern Option<iarf_e> +sp_before_sparen; + +// Add or remove space inside '(' and ')' of control statements other than +// 'for'. +extern Option<iarf_e> +sp_inside_sparen; + +// Add or remove space after '(' of control statements other than 'for'. +// +// Overrides sp_inside_sparen. +extern Option<iarf_e> +sp_inside_sparen_open; + +// Add or remove space before ')' of control statements other than 'for'. +// +// Overrides sp_inside_sparen. +extern Option<iarf_e> +sp_inside_sparen_close; + +// Add or remove space inside '(' and ')' of 'for' statements. +extern Option<iarf_e> +sp_inside_for; + +// Add or remove space after '(' of 'for' statements. +// +// Overrides sp_inside_for. +extern Option<iarf_e> +sp_inside_for_open; + +// Add or remove space before ')' of 'for' statements. +// +// Overrides sp_inside_for. +extern Option<iarf_e> +sp_inside_for_close; + +// Add or remove space between '((' or '))' of control statements. +extern Option<iarf_e> +sp_sparen_paren; + +// Add or remove space after ')' of control statements. +extern Option<iarf_e> +sp_after_sparen; + +// Add or remove space between ')' and '{' of control statements. +extern Option<iarf_e> +sp_sparen_brace; + +// Add or remove space between 'do' and '{'. +extern Option<iarf_e> +sp_do_brace_open; + +// Add or remove space between '}' and 'while'. +extern Option<iarf_e> +sp_brace_close_while; + +// Add or remove space between 'while' and '('. Overrides sp_before_sparen. +extern Option<iarf_e> +sp_while_paren_open; + +// (D) Add or remove space between 'invariant' and '('. +extern Option<iarf_e> +sp_invariant_paren; + +// (D) Add or remove space after the ')' in 'invariant (C) c'. +extern Option<iarf_e> +sp_after_invariant_paren; + +// Add or remove space before empty statement ';' on 'if', 'for' and 'while'. +extern Option<iarf_e> +sp_special_semi; + +// Add or remove space before ';'. +extern Option<iarf_e> +sp_before_semi; // = IARF_REMOVE + +// Add or remove space before ';' in non-empty 'for' statements. +extern Option<iarf_e> +sp_before_semi_for; + +// Add or remove space before a semicolon of an empty left part of a for +// statement, as in 'for ( <here> ; ; )'. +extern Option<iarf_e> +sp_before_semi_for_empty; + +// Add or remove space between the semicolons of an empty middle part of a for +// statement, as in 'for ( ; <here> ; )'. +extern Option<iarf_e> +sp_between_semi_for_empty; + +// Add or remove space after ';', except when followed by a comment. +extern Option<iarf_e> +sp_after_semi; // = IARF_ADD + +// Add or remove space after ';' in non-empty 'for' statements. +extern Option<iarf_e> +sp_after_semi_for; // = IARF_FORCE + +// Add or remove space after the final semicolon of an empty part of a for +// statement, as in 'for ( ; ; <here> )'. +extern Option<iarf_e> +sp_after_semi_for_empty; + +// Add or remove space before '[' (except '[]'). +extern Option<iarf_e> +sp_before_square; + +// Add or remove space before '[' for a variable definition. +extern Option<iarf_e> +sp_before_vardef_square; // = IARF_REMOVE + +// Add or remove space before '[' for asm block. +extern Option<iarf_e> +sp_before_square_asm_block; + +// Add or remove space before '[]'. +extern Option<iarf_e> +sp_before_squares; + +// Add or remove space before C++17 structured bindings. +extern Option<iarf_e> +sp_cpp_before_struct_binding; + +// Add or remove space inside a non-empty '[' and ']'. +extern Option<iarf_e> +sp_inside_square; + +// Add or remove space inside '[]'. +extern Option<iarf_e> +sp_inside_square_empty; + +// (OC) Add or remove space inside a non-empty Objective-C boxed array '@[' and +// ']'. If set to ignore, sp_inside_square is used. +extern Option<iarf_e> +sp_inside_square_oc_array; + +// Add or remove space after ',', i.e. 'a,b' vs. 'a, b'. +extern Option<iarf_e> +sp_after_comma; + +// Add or remove space before ',', i.e. 'a,b' vs. 'a ,b'. +extern Option<iarf_e> +sp_before_comma; // = IARF_REMOVE + +// (C#, Vala) Add or remove space between ',' and ']' in multidimensional array type +// like 'int[,,]'. +extern Option<iarf_e> +sp_after_mdatype_commas; + +// (C#, Vala) Add or remove space between '[' and ',' in multidimensional array type +// like 'int[,,]'. +extern Option<iarf_e> +sp_before_mdatype_commas; + +// (C#, Vala) Add or remove space between ',' in multidimensional array type +// like 'int[,,]'. +extern Option<iarf_e> +sp_between_mdatype_commas; + +// Add or remove space between an open parenthesis and comma, +// i.e. '(,' vs. '( ,'. +extern Option<iarf_e> +sp_paren_comma; // = IARF_FORCE + +// Add or remove space between a type and ':'. +extern Option<iarf_e> +sp_type_colon; + +// Add or remove space after the variadic '...' when preceded by a +// non-punctuator. +// The value REMOVE will be overridden with FORCE +extern Option<iarf_e> +sp_after_ellipsis; + +// Add or remove space before the variadic '...' when preceded by a +// non-punctuator. +// The value REMOVE will be overridden with FORCE +extern Option<iarf_e> +sp_before_ellipsis; + +// Add or remove space between a type and '...'. +extern Option<iarf_e> +sp_type_ellipsis; + +// Add or remove space between a '*' and '...'. +extern Option<iarf_e> +sp_ptr_type_ellipsis; + +// Add or remove space between ')' and '...'. +extern Option<iarf_e> +sp_paren_ellipsis; + +// Add or remove space between '&&' and '...'. +extern Option<iarf_e> +sp_byref_ellipsis; + +// Add or remove space between ')' and a qualifier such as 'const'. +extern Option<iarf_e> +sp_paren_qualifier; + +// Add or remove space between ')' and 'noexcept'. +extern Option<iarf_e> +sp_paren_noexcept; + +// Add or remove space after class ':'. +extern Option<iarf_e> +sp_after_class_colon; + +// Add or remove space before class ':'. +extern Option<iarf_e> +sp_before_class_colon; + +// Add or remove space after class constructor ':'. +extern Option<iarf_e> +sp_after_constr_colon; // = IARF_ADD + +// Add or remove space before class constructor ':'. +extern Option<iarf_e> +sp_before_constr_colon; // = IARF_ADD + +// Add or remove space before case ':'. +extern Option<iarf_e> +sp_before_case_colon; // = IARF_REMOVE + +// Add or remove space between 'operator' and operator sign. +extern Option<iarf_e> +sp_after_operator; + +// Add or remove space between the operator symbol and the open parenthesis, as +// in 'operator ++('. +extern Option<iarf_e> +sp_after_operator_sym; + +// Overrides sp_after_operator_sym when the operator has no arguments, as in +// 'operator *()'. +extern Option<iarf_e> +sp_after_operator_sym_empty; + +// Add or remove space after C/D cast, i.e. 'cast(int)a' vs. 'cast(int) a' or +// '(int)a' vs. '(int) a'. +extern Option<iarf_e> +sp_after_cast; + +// Add or remove spaces inside cast parentheses. +extern Option<iarf_e> +sp_inside_paren_cast; + +// Add or remove space between the type and open parenthesis in a C++ cast, +// i.e. 'int(exp)' vs. 'int (exp)'. +extern Option<iarf_e> +sp_cpp_cast_paren; + +// Add or remove space between 'sizeof' and '('. +extern Option<iarf_e> +sp_sizeof_paren; + +// Add or remove space between 'sizeof' and '...'. +extern Option<iarf_e> +sp_sizeof_ellipsis; + +// Add or remove space between 'sizeof...' and '('. +extern Option<iarf_e> +sp_sizeof_ellipsis_paren; + +// Add or remove space between '...' and a parameter pack. +extern Option<iarf_e> +sp_ellipsis_parameter_pack; + +// Add or remove space between a parameter pack and '...'. +extern Option<iarf_e> +sp_parameter_pack_ellipsis; + +// Add or remove space between 'decltype' and '('. +extern Option<iarf_e> +sp_decltype_paren; + +// (Pawn) Add or remove space after the tag keyword. +extern Option<iarf_e> +sp_after_tag; + +// Add or remove space inside enum '{' and '}'. +extern Option<iarf_e> +sp_inside_braces_enum; + +// Add or remove space inside struct/union '{' and '}'. +extern Option<iarf_e> +sp_inside_braces_struct; + +// (OC) Add or remove space inside Objective-C boxed dictionary '{' and '}' +extern Option<iarf_e> +sp_inside_braces_oc_dict; + +// Add or remove space after open brace in an unnamed temporary +// direct-list-initialization +// if statement is a brace_init_lst +// works only if sp_brace_brace is set to ignore. +extern Option<iarf_e> +sp_after_type_brace_init_lst_open; + +// Add or remove space before close brace in an unnamed temporary +// direct-list-initialization +// if statement is a brace_init_lst +// works only if sp_brace_brace is set to ignore. +extern Option<iarf_e> +sp_before_type_brace_init_lst_close; + +// Add or remove space inside an unnamed temporary direct-list-initialization +// if statement is a brace_init_lst +// works only if sp_brace_brace is set to ignore +// works only if sp_before_type_brace_init_lst_close is set to ignore. +extern Option<iarf_e> +sp_inside_type_brace_init_lst; + +// Add or remove space inside '{' and '}'. +extern Option<iarf_e> +sp_inside_braces; + +// Add or remove space inside '{}'. +extern Option<iarf_e> +sp_inside_braces_empty; + +// Add or remove space around trailing return operator '->'. +extern Option<iarf_e> +sp_trailing_return; + +// Add or remove space between return type and function name. A minimum of 1 +// is forced except for pointer return types. +extern Option<iarf_e> +sp_type_func; + +// Add or remove space between type and open brace of an unnamed temporary +// direct-list-initialization. +extern Option<iarf_e> +sp_type_brace_init_lst; + +// Add or remove space between function name and '(' on function declaration. +extern Option<iarf_e> +sp_func_proto_paren; + +// Add or remove space between function name and '()' on function declaration +// without parameters. +extern Option<iarf_e> +sp_func_proto_paren_empty; + +// Add or remove space between function name and '(' with a typedef specifier. +extern Option<iarf_e> +sp_func_type_paren; + +// Add or remove space between alias name and '(' of a non-pointer function type typedef. +extern Option<iarf_e> +sp_func_def_paren; + +// Add or remove space between function name and '()' on function definition +// without parameters. +extern Option<iarf_e> +sp_func_def_paren_empty; + +// Add or remove space inside empty function '()'. +// Overrides sp_after_angle unless use_sp_after_angle_always is set to true. +extern Option<iarf_e> +sp_inside_fparens; + +// Add or remove space inside function '(' and ')'. +extern Option<iarf_e> +sp_inside_fparen; + +// Add or remove space inside the first parentheses in a function type, as in +// 'void (*x)(...)'. +extern Option<iarf_e> +sp_inside_tparen; + +// Add or remove space between the ')' and '(' in a function type, as in +// 'void (*x)(...)'. +extern Option<iarf_e> +sp_after_tparen_close; + +// Add or remove space between ']' and '(' when part of a function call. +extern Option<iarf_e> +sp_square_fparen; + +// Add or remove space between ')' and '{' of function. +extern Option<iarf_e> +sp_fparen_brace; + +// Add or remove space between ')' and '{' of a function call in object +// initialization. +// +// Overrides sp_fparen_brace. +extern Option<iarf_e> +sp_fparen_brace_initializer; + +// (Java) Add or remove space between ')' and '{{' of double brace initializer. +extern Option<iarf_e> +sp_fparen_dbrace; + +// Add or remove space between function name and '(' on function calls. +extern Option<iarf_e> +sp_func_call_paren; + +// Add or remove space between function name and '()' on function calls without +// parameters. If set to ignore (the default), sp_func_call_paren is used. +extern Option<iarf_e> +sp_func_call_paren_empty; + +// Add or remove space between the user function name and '(' on function +// calls. You need to set a keyword to be a user function in the config file, +// like: +// set func_call_user tr _ i18n +extern Option<iarf_e> +sp_func_call_user_paren; + +// Add or remove space inside user function '(' and ')'. +extern Option<iarf_e> +sp_func_call_user_inside_fparen; + +// Add or remove space between nested parentheses with user functions, +// i.e. '((' vs. '( ('. +extern Option<iarf_e> +sp_func_call_user_paren_paren; + +// Add or remove space between a constructor/destructor and the open +// parenthesis. +extern Option<iarf_e> +sp_func_class_paren; + +// Add or remove space between a constructor without parameters or destructor +// and '()'. +extern Option<iarf_e> +sp_func_class_paren_empty; + +// Add or remove space after 'return'. +extern Option<iarf_e> +sp_return; // = IARF_FORCE + +// Add or remove space between 'return' and '('. +extern Option<iarf_e> +sp_return_paren; + +// Add or remove space between 'return' and '{'. +extern Option<iarf_e> +sp_return_brace; + +// Add or remove space between '__attribute__' and '('. +extern Option<iarf_e> +sp_attribute_paren; + +// Add or remove space between 'defined' and '(' in '#if defined (FOO)'. +extern Option<iarf_e> +sp_defined_paren; + +// Add or remove space between 'throw' and '(' in 'throw (something)'. +extern Option<iarf_e> +sp_throw_paren; + +// Add or remove space between 'throw' and anything other than '(' as in +// '@throw [...];'. +extern Option<iarf_e> +sp_after_throw; + +// Add or remove space between 'catch' and '(' in 'catch (something) { }'. +// If set to ignore, sp_before_sparen is used. +extern Option<iarf_e> +sp_catch_paren; + +// (OC) Add or remove space between '@catch' and '(' +// in '@catch (something) { }'. If set to ignore, sp_catch_paren is used. +extern Option<iarf_e> +sp_oc_catch_paren; + +// (OC) Add or remove space before Objective-C protocol list +// as in '@protocol Protocol<here><Protocol_A>' or '@interface MyClass : NSObject<here><MyProtocol>'. +extern Option<iarf_e> +sp_before_oc_proto_list; + +// (OC) Add or remove space between class name and '(' +// in '@interface className(categoryName)<ProtocolName>:BaseClass' +extern Option<iarf_e> +sp_oc_classname_paren; + +// (D) Add or remove space between 'version' and '(' +// in 'version (something) { }'. If set to ignore, sp_before_sparen is used. +extern Option<iarf_e> +sp_version_paren; + +// (D) Add or remove space between 'scope' and '(' +// in 'scope (something) { }'. If set to ignore, sp_before_sparen is used. +extern Option<iarf_e> +sp_scope_paren; + +// Add or remove space between 'super' and '(' in 'super (something)'. +extern Option<iarf_e> +sp_super_paren; // = IARF_REMOVE + +// Add or remove space between 'this' and '(' in 'this (something)'. +extern Option<iarf_e> +sp_this_paren; // = IARF_REMOVE + +// Add or remove space between a macro name and its definition. +extern Option<iarf_e> +sp_macro; + +// Add or remove space between a macro function ')' and its definition. +extern Option<iarf_e> +sp_macro_func; + +// Add or remove space between 'else' and '{' if on the same line. +extern Option<iarf_e> +sp_else_brace; + +// Add or remove space between '}' and 'else' if on the same line. +extern Option<iarf_e> +sp_brace_else; + +// Add or remove space between '}' and the name of a typedef on the same line. +extern Option<iarf_e> +sp_brace_typedef; + +// Add or remove space before the '{' of a 'catch' statement, if the '{' and +// 'catch' are on the same line, as in 'catch (decl) <here> {'. +extern Option<iarf_e> +sp_catch_brace; + +// (OC) Add or remove space before the '{' of a '@catch' statement, if the '{' +// and '@catch' are on the same line, as in '@catch (decl) <here> {'. +// If set to ignore, sp_catch_brace is used. +extern Option<iarf_e> +sp_oc_catch_brace; + +// Add or remove space between '}' and 'catch' if on the same line. +extern Option<iarf_e> +sp_brace_catch; + +// (OC) Add or remove space between '}' and '@catch' if on the same line. +// If set to ignore, sp_brace_catch is used. +extern Option<iarf_e> +sp_oc_brace_catch; + +// Add or remove space between 'finally' and '{' if on the same line. +extern Option<iarf_e> +sp_finally_brace; + +// Add or remove space between '}' and 'finally' if on the same line. +extern Option<iarf_e> +sp_brace_finally; + +// Add or remove space between 'try' and '{' if on the same line. +extern Option<iarf_e> +sp_try_brace; + +// Add or remove space between get/set and '{' if on the same line. +extern Option<iarf_e> +sp_getset_brace; + +// Add or remove space between a variable and '{' for C++ uniform +// initialization. +extern Option<iarf_e> +sp_word_brace_init_lst; + +// Add or remove space between a variable and '{' for a namespace. +extern Option<iarf_e> +sp_word_brace_ns; // = IARF_ADD + +// Add or remove space before the '::' operator. +extern Option<iarf_e> +sp_before_dc; + +// Add or remove space after the '::' operator. +extern Option<iarf_e> +sp_after_dc; + +// (D) Add or remove around the D named array initializer ':' operator. +extern Option<iarf_e> +sp_d_array_colon; + +// Add or remove space after the '!' (not) unary operator. +extern Option<iarf_e> +sp_not; // = IARF_REMOVE + +// Add or remove space between two '!' (not) unary operators. +// If set to ignore, sp_not will be used. +extern Option<iarf_e> +sp_not_not; // = IARF_IGNORE + +// Add or remove space after the '~' (invert) unary operator. +extern Option<iarf_e> +sp_inv; // = IARF_REMOVE + +// Add or remove space after the '&' (address-of) unary operator. This does not +// affect the spacing after a '&' that is part of a type. +extern Option<iarf_e> +sp_addr; // = IARF_REMOVE + +// Add or remove space around the '.' or '->' operators. +extern Option<iarf_e> +sp_member; // = IARF_REMOVE + +// Add or remove space after the '*' (dereference) unary operator. This does +// not affect the spacing after a '*' that is part of a type. +extern Option<iarf_e> +sp_deref; // = IARF_REMOVE + +// Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. +extern Option<iarf_e> +sp_sign; // = IARF_REMOVE + +// Add or remove space between '++' and '--' the word to which it is being +// applied, as in '(--x)' or 'y++;'. +extern Option<iarf_e> +sp_incdec; // = IARF_REMOVE + +// Add or remove space before a backslash-newline at the end of a line. +extern Option<iarf_e> +sp_before_nl_cont; // = IARF_ADD + +// (OC) Add or remove space after the scope '+' or '-', as in '-(void) foo;' +// or '+(int) bar;'. +extern Option<iarf_e> +sp_after_oc_scope; + +// (OC) Add or remove space after the colon in message specs, +// i.e. '-(int) f:(int) x;' vs. '-(int) f: (int) x;'. +extern Option<iarf_e> +sp_after_oc_colon; + +// (OC) Add or remove space before the colon in message specs, +// i.e. '-(int) f: (int) x;' vs. '-(int) f : (int) x;'. +extern Option<iarf_e> +sp_before_oc_colon; + +// (OC) Add or remove space after the colon in immutable dictionary expression +// 'NSDictionary *test = @{@"foo" :@"bar"};'. +extern Option<iarf_e> +sp_after_oc_dict_colon; + +// (OC) Add or remove space before the colon in immutable dictionary expression +// 'NSDictionary *test = @{@"foo" :@"bar"};'. +extern Option<iarf_e> +sp_before_oc_dict_colon; + +// (OC) Add or remove space after the colon in message specs, +// i.e. '[object setValue:1];' vs. '[object setValue: 1];'. +extern Option<iarf_e> +sp_after_send_oc_colon; + +// (OC) Add or remove space before the colon in message specs, +// i.e. '[object setValue:1];' vs. '[object setValue :1];'. +extern Option<iarf_e> +sp_before_send_oc_colon; + +// (OC) Add or remove space after the (type) in message specs, +// i.e. '-(int)f: (int) x;' vs. '-(int)f: (int)x;'. +extern Option<iarf_e> +sp_after_oc_type; + +// (OC) Add or remove space after the first (type) in message specs, +// i.e. '-(int) f:(int)x;' vs. '-(int)f:(int)x;'. +extern Option<iarf_e> +sp_after_oc_return_type; + +// (OC) Add or remove space between '@selector' and '(', +// i.e. '@selector(msgName)' vs. '@selector (msgName)'. +// Also applies to '@protocol()' constructs. +extern Option<iarf_e> +sp_after_oc_at_sel; + +// (OC) Add or remove space between '@selector(x)' and the following word, +// i.e. '@selector(foo) a:' vs. '@selector(foo)a:'. +extern Option<iarf_e> +sp_after_oc_at_sel_parens; + +// (OC) Add or remove space inside '@selector' parentheses, +// i.e. '@selector(foo)' vs. '@selector( foo )'. +// Also applies to '@protocol()' constructs. +extern Option<iarf_e> +sp_inside_oc_at_sel_parens; + +// (OC) Add or remove space before a block pointer caret, +// i.e. '^int (int arg){...}' vs. ' ^int (int arg){...}'. +extern Option<iarf_e> +sp_before_oc_block_caret; + +// (OC) Add or remove space after a block pointer caret, +// i.e. '^int (int arg){...}' vs. '^ int (int arg){...}'. +extern Option<iarf_e> +sp_after_oc_block_caret; + +// (OC) Add or remove space between the receiver and selector in a message, +// as in '[receiver selector ...]'. +extern Option<iarf_e> +sp_after_oc_msg_receiver; + +// (OC) Add or remove space after '@property'. +extern Option<iarf_e> +sp_after_oc_property; + +// (OC) Add or remove space between '@synchronized' and the open parenthesis, +// i.e. '@synchronized(foo)' vs. '@synchronized (foo)'. +extern Option<iarf_e> +sp_after_oc_synchronized; + +// Add or remove space around the ':' in 'b ? t : f'. +extern Option<iarf_e> +sp_cond_colon; + +// Add or remove space before the ':' in 'b ? t : f'. +// +// Overrides sp_cond_colon. +extern Option<iarf_e> +sp_cond_colon_before; + +// Add or remove space after the ':' in 'b ? t : f'. +// +// Overrides sp_cond_colon. +extern Option<iarf_e> +sp_cond_colon_after; + +// Add or remove space around the '?' in 'b ? t : f'. +extern Option<iarf_e> +sp_cond_question; + +// Add or remove space before the '?' in 'b ? t : f'. +// +// Overrides sp_cond_question. +extern Option<iarf_e> +sp_cond_question_before; + +// Add or remove space after the '?' in 'b ? t : f'. +// +// Overrides sp_cond_question. +extern Option<iarf_e> +sp_cond_question_after; + +// In the abbreviated ternary form '(a ?: b)', add or remove space between '?' +// and ':'. +// +// Overrides all other sp_cond_* options. +extern Option<iarf_e> +sp_cond_ternary_short; + +// Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make +// sense here. +extern Option<iarf_e> +sp_case_label; + +// (D) Add or remove space around the D '..' operator. +extern Option<iarf_e> +sp_range; + +// Add or remove space after ':' in a Java/C++11 range-based 'for', +// as in 'for (Type var : <here> expr)'. +extern Option<iarf_e> +sp_after_for_colon; + +// Add or remove space before ':' in a Java/C++11 range-based 'for', +// as in 'for (Type var <here> : expr)'. +extern Option<iarf_e> +sp_before_for_colon; + +// (D) Add or remove space between 'extern' and '(' as in 'extern <here> (C)'. +extern Option<iarf_e> +sp_extern_paren; + +// Add or remove space after the opening of a C++ comment, as in '// <here> A'. +extern Option<iarf_e> +sp_cmt_cpp_start; + +// Add or remove space in a C++ region marker comment, as in '// <here> BEGIN'. +// A region marker is defined as a comment which is not preceded by other text +// (i.e. the comment is the first non-whitespace on the line), and which starts +// with either 'BEGIN' or 'END'. +// +// Overrides sp_cmt_cpp_start. +extern Option<iarf_e> +sp_cmt_cpp_region; + +// If true, space added with sp_cmt_cpp_start will be added after Doxygen +// sequences like '///', '///<', '//!' and '//!<'. +extern Option<bool> +sp_cmt_cpp_doxygen; + +// If true, space added with sp_cmt_cpp_start will be added after Qt translator +// or meta-data comments like '//:', '//=', and '//~'. +extern Option<bool> +sp_cmt_cpp_qttr; + +// Add or remove space between #else or #endif and a trailing comment. +extern Option<iarf_e> +sp_endif_cmt; + +// Add or remove space after 'new', 'delete' and 'delete[]'. +extern Option<iarf_e> +sp_after_new; + +// Add or remove space between 'new' and '(' in 'new()'. +extern Option<iarf_e> +sp_between_new_paren; + +// Add or remove space between ')' and type in 'new(foo) BAR'. +extern Option<iarf_e> +sp_after_newop_paren; + +// Add or remove space inside parentheses of the new operator +// as in 'new(foo) BAR'. +extern Option<iarf_e> +sp_inside_newop_paren; + +// Add or remove space after the open parenthesis of the new operator, +// as in 'new(foo) BAR'. +// +// Overrides sp_inside_newop_paren. +extern Option<iarf_e> +sp_inside_newop_paren_open; + +// Add or remove space before the close parenthesis of the new operator, +// as in 'new(foo) BAR'. +// +// Overrides sp_inside_newop_paren. +extern Option<iarf_e> +sp_inside_newop_paren_close; + +// Add or remove space before a trailing comment. +extern Option<iarf_e> +sp_before_tr_cmt; + +// Number of spaces before a trailing comment. +extern BoundedOption<unsigned, 0, 16> +sp_num_before_tr_cmt; + +// Add or remove space before an embedded comment. +extern Option<iarf_e> +sp_before_emb_cmt; // = IARF_FORCE + +// Number of spaces before an embedded comment. +extern BoundedOption<unsigned, 0, 16> +sp_num_before_emb_cmt; // = 1 + +// Add or remove space after an embedded comment. +extern Option<iarf_e> +sp_after_emb_cmt; // = IARF_FORCE + +// Number of spaces after an embedded comment. +extern BoundedOption<unsigned, 0, 16> +sp_num_after_emb_cmt; // = 1 + +// (Java) Add or remove space between an annotation and the open parenthesis. +extern Option<iarf_e> +sp_annotation_paren; + +// If true, vbrace tokens are dropped to the previous token and skipped. +extern Option<bool> +sp_skip_vbrace_tokens; + +// Add or remove space after 'noexcept'. +extern Option<iarf_e> +sp_after_noexcept; + +// Add or remove space after '_'. +extern Option<iarf_e> +sp_vala_after_translation; + +// If true, a <TAB> is inserted after #define. +extern Option<bool> +force_tab_after_define; + +//END + +/////////////////////////////////////////////////////////////////////////////// +//BEGIN Indenting options + +// The number of columns to indent per level. Usually 2, 3, 4, or 8. +extern BoundedOption<unsigned, 0, 16> +indent_columns; // = 8 + +// Whether to ignore indent for the first continuation line. Subsequent +// continuation lines will still be indented to match the first. +extern Option<bool> +indent_ignore_first_continue; + +// The continuation indent. If non-zero, this overrides the indent of '(', '[' +// and '=' continuation indents. Negative values are OK; negative value is +// absolute and not increased for each '(' or '[' level. +// +// For FreeBSD, this is set to 4. +// Requires indent_ignore_first_continue=false. +extern BoundedOption<signed, -16, 16> +indent_continue; + +// The continuation indent, only for class header line(s). If non-zero, this +// overrides the indent of 'class' continuation indents. +// Requires indent_ignore_first_continue=false. +extern BoundedOption<unsigned, 0, 16> +indent_continue_class_head; + +// Whether to indent empty lines (i.e. lines which contain only spaces before +// the newline character). +extern Option<bool> +indent_single_newlines; + +// The continuation indent for func_*_param if they are true. If non-zero, this +// overrides the indent. +extern BoundedOption<unsigned, 0, 16> +indent_param; + +// How to use tabs when indenting code. +// +// 0: Spaces only +// 1: Indent with tabs to brace level, align with spaces (default) +// 2: Indent and align with tabs, using spaces when not on a tabstop +extern BoundedOption<unsigned, 0, 2> +indent_with_tabs; // = 1 + +// Whether to indent comments that are not at a brace level with tabs on a +// tabstop. Requires indent_with_tabs=2. If false, will use spaces. +extern Option<bool> +indent_cmt_with_tabs; + +// Whether to indent strings broken by '\' so that they line up. +extern Option<bool> +indent_align_string; + +// The number of spaces to indent multi-line XML strings. +// Requires indent_align_string=true. +extern BoundedOption<unsigned, 0, 16> +indent_xml_string; + +// Spaces to indent '{' from level. +extern BoundedOption<unsigned, 0, 16> +indent_brace; + +// Whether braces are indented to the body level. +extern Option<bool> +indent_braces; + +// Whether to disable indenting function braces if indent_braces=true. +extern Option<bool> +indent_braces_no_func; + +// Whether to disable indenting class braces if indent_braces=true. +extern Option<bool> +indent_braces_no_class; + +// Whether to disable indenting struct braces if indent_braces=true. +extern Option<bool> +indent_braces_no_struct; + +// Whether to indent based on the size of the brace parent, +// i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc. +extern Option<bool> +indent_brace_parent; + +// Whether to indent based on the open parenthesis instead of the open brace +// in '({\n'. +extern Option<bool> +indent_paren_open_brace; + +// (C#) Whether to indent the brace of a C# delegate by another level. +extern Option<bool> +indent_cs_delegate_brace; + +// (C#) Whether to indent a C# delegate (to handle delegates with no brace) by +// another level. +extern Option<bool> +indent_cs_delegate_body; + +// Whether to indent the body of a 'namespace'. +extern Option<bool> +indent_namespace; + +// Whether to indent only the first namespace, and not any nested namespaces. +// Requires indent_namespace=true. +extern Option<bool> +indent_namespace_single_indent; + +// The number of spaces to indent a namespace block. +// If set to zero, use the value indent_columns +extern BoundedOption<unsigned, 0, 16> +indent_namespace_level; + +// If the body of the namespace is longer than this number, it won't be +// indented. Requires indent_namespace=true. 0 means no limit. +extern BoundedOption<unsigned, 0, 255> +indent_namespace_limit; + +// Whether to indent only in inner namespaces (nested in other namespaces). +// Requires indent_namespace=true. +extern Option<bool> +indent_namespace_inner_only; + +// Whether the 'extern "C"' body is indented. +extern Option<bool> +indent_extern; + +// Whether the 'class' body is indented. +extern Option<bool> +indent_class; + +// Whether to ignore indent for the leading base class colon. +extern Option<bool> +indent_ignore_before_class_colon; + +// Additional indent before the leading base class colon. +// Negative values decrease indent down to the first column. +// Requires indent_ignore_before_class_colon=false and a newline break before +// the colon (see pos_class_colon and nl_class_colon) +extern BoundedOption<signed, -16, 16> +indent_before_class_colon; + +// Whether to indent the stuff after a leading base class colon. +extern Option<bool> +indent_class_colon; + +// Whether to indent based on a class colon instead of the stuff after the +// colon. Requires indent_class_colon=true. +extern Option<bool> +indent_class_on_colon; + +// Whether to ignore indent for a leading class initializer colon. +extern Option<bool> +indent_ignore_before_constr_colon; + +// Whether to indent the stuff after a leading class initializer colon. +extern Option<bool> +indent_constr_colon; + +// Virtual indent from the ':' for leading member initializers. +extern BoundedOption<unsigned, 0, 16> +indent_ctor_init_leading; // = 2 + +// Virtual indent from the ':' for following member initializers. +extern BoundedOption<unsigned, 0, 16> +indent_ctor_init_following; // = 2 + +// Additional indent for constructor initializer list. +// Negative values decrease indent down to the first column. +extern BoundedOption<signed, -16, 16> +indent_ctor_init; + +// Whether to indent 'if' following 'else' as a new block under the 'else'. +// If false, 'else\nif' is treated as 'else if' for indenting purposes. +extern Option<bool> +indent_else_if; + +// Amount to indent variable declarations after a open brace. +// +// <0: Relative +// >=0: Absolute +extern BoundedOption<signed, -16, 16> +indent_var_def_blk; + +// Whether to indent continued variable declarations instead of aligning. +extern Option<bool> +indent_var_def_cont; + +// How to indent continued shift expressions ('<<' and '>>'). +// Set align_left_shift=false when using this. +// 0: Align shift operators instead of indenting them (default) +// 1: Indent by one level +// -1: Preserve original indentation +extern BoundedOption<signed, -1, 1> +indent_shift; + +// Whether to force indentation of function definitions to start in column 1. +extern Option<bool> +indent_func_def_force_col1; + +// Whether to indent continued function call parameters one indent level, +// rather than aligning parameters under the open parenthesis. +extern Option<bool> +indent_func_call_param; + +// Whether to indent continued function definition parameters one indent level, +// rather than aligning parameters under the open parenthesis. +extern Option<bool> +indent_func_def_param; + +// for function definitions, only if indent_func_def_param is false +// Allows to align params when appropriate and indent them when not +// behave as if it was true if paren position is more than this value +// if paren position is more than the option value +extern BoundedOption<unsigned, 0, 160> +indent_func_def_param_paren_pos_threshold; + +// Whether to indent continued function call prototype one indent level, +// rather than aligning parameters under the open parenthesis. +extern Option<bool> +indent_func_proto_param; + +// Whether to indent continued function call declaration one indent level, +// rather than aligning parameters under the open parenthesis. +extern Option<bool> +indent_func_class_param; + +// Whether to indent continued class variable constructors one indent level, +// rather than aligning parameters under the open parenthesis. +extern Option<bool> +indent_func_ctor_var_param; + +// Whether to indent continued template parameter list one indent level, +// rather than aligning parameters under the open parenthesis. +extern Option<bool> +indent_template_param; + +// Double the indent for indent_func_xxx_param options. +// Use both values of the options indent_columns and indent_param. +extern Option<bool> +indent_func_param_double; + +// Indentation column for standalone 'const' qualifier on a function +// prototype. +extern BoundedOption<unsigned, 0, 69> +indent_func_const; + +// Indentation column for standalone 'throw' qualifier on a function +// prototype. +extern BoundedOption<unsigned, 0, 41> +indent_func_throw; + +// How to indent within a macro followed by a brace on the same line +// This allows reducing the indent in macros that have (for example) +// `do { ... } while (0)` blocks bracketing them. +// +// true: add an indent for the brace on the same line as the macro +// false: do not add an indent for the brace on the same line as the macro +extern Option<bool> +indent_macro_brace; // = true + +// The number of spaces to indent a continued '->' or '.'. +// Usually set to 0, 1, or indent_columns. +extern BoundedOption<unsigned, 0, 16> +indent_member; + +// Whether lines broken at '.' or '->' should be indented by a single indent. +// The indent_member option will not be effective if this is set to true. +extern Option<bool> +indent_member_single; + +// Spaces to indent single line ('//') comments on lines before code. +extern BoundedOption<unsigned, 0, 16> +indent_single_line_comments_before; + +// Spaces to indent single line ('//') comments on lines after code. +extern BoundedOption<unsigned, 0, 16> +indent_single_line_comments_after; + +// When opening a paren for a control statement (if, for, while, etc), increase +// the indent level by this value. Negative values decrease the indent level. +extern BoundedOption<signed, -16, 16> +indent_sparen_extra; + +// Whether to indent trailing single line ('//') comments relative to the code +// instead of trying to keep the same absolute column. +extern Option<bool> +indent_relative_single_line_comments; + +// Spaces to indent 'case' from 'switch'. Usually 0 or indent_columns. +// It might be wise to choose the same value for the option indent_case_brace. +extern BoundedOption<unsigned, 0, 16> +indent_switch_case; + +// Spaces to indent the body of a 'switch' before any 'case'. +// Usually the same as indent_columns or indent_switch_case. +extern BoundedOption<unsigned, 0, 16> +indent_switch_body; + +// Whether to ignore indent for '{' following 'case'. +extern Option<bool> +indent_ignore_case_brace; + +// Spaces to indent '{' from 'case'. By default, the brace will appear under +// the 'c' in case. Usually set to 0 or indent_columns. Negative values are OK. +// It might be wise to choose the same value for the option indent_switch_case. +extern BoundedOption<signed, -16, 16> +indent_case_brace; + +// indent 'break' with 'case' from 'switch'. +extern Option<bool> +indent_switch_break_with_case; + +// Whether to indent preprocessor statements inside of switch statements. +extern Option<bool> +indent_switch_pp; // = true + +// Spaces to shift the 'case' line, without affecting any other lines. +// Usually 0. +extern BoundedOption<unsigned, 0, 16> +indent_case_shift; + +// Whether to align comments before 'case' with the 'case'. +extern Option<bool> +indent_case_comment; // = true + +// Whether to indent comments not found in first column. +extern Option<bool> +indent_comment; // = true + +// Whether to indent comments found in first column. +extern Option<bool> +indent_col1_comment; + +// Whether to indent multi string literal in first column. +extern Option<bool> +indent_col1_multi_string_literal; + +// Align comments on adjacent lines that are this many columns apart or less. +extern BoundedOption<unsigned, 0, 16> +indent_comment_align_thresh; // = 3 + +// Whether to ignore indent for goto labels. +extern Option<bool> +indent_ignore_label; + +// How to indent goto labels. Requires indent_ignore_label=false. +// +// >0: Absolute column where 1 is the leftmost column +// <=0: Subtract from brace indent +extern BoundedOption<signed, -16, 16> +indent_label; // = 1 + +// How to indent access specifiers that are followed by a +// colon. +// +// >0: Absolute column where 1 is the leftmost column +// <=0: Subtract from brace indent +extern BoundedOption<signed, -16, 16> +indent_access_spec; // = 1 + +// Whether to indent the code after an access specifier by one level. +// If true, this option forces 'indent_access_spec=0'. +extern Option<bool> +indent_access_spec_body; + +// If an open parenthesis is followed by a newline, whether to indent the next +// line so that it lines up after the open parenthesis (not recommended). +extern Option<bool> +indent_paren_nl; + +// How to indent a close parenthesis after a newline. +// +// 0: Indent to body level (default) +// 1: Align under the open parenthesis +// 2: Indent to the brace level +// -1: Preserve original indentation +extern BoundedOption<signed, -1, 2> +indent_paren_close; + +// Whether to indent the open parenthesis of a function definition, +// if the parenthesis is on its own line. +extern Option<bool> +indent_paren_after_func_def; + +// Whether to indent the open parenthesis of a function declaration, +// if the parenthesis is on its own line. +extern Option<bool> +indent_paren_after_func_decl; + +// Whether to indent the open parenthesis of a function call, +// if the parenthesis is on its own line. +extern Option<bool> +indent_paren_after_func_call; + +// How to indent a comma when inside braces. +// 0: Indent by one level (default) +// 1: Align under the open brace +// -1: Preserve original indentation +extern BoundedOption<signed, -1, 1> +indent_comma_brace; + +// How to indent a comma when inside parentheses. +// 0: Indent by one level (default) +// 1: Align under the open parenthesis +// -1: Preserve original indentation +extern BoundedOption<signed, -1, 1> +indent_comma_paren; + +// How to indent a Boolean operator when inside parentheses. +// 0: Indent by one level (default) +// 1: Align under the open parenthesis +// -1: Preserve original indentation +extern BoundedOption<signed, -1, 1> +indent_bool_paren; + +// Whether to ignore the indentation of a Boolean operator when outside +// parentheses. +extern Option<bool> +indent_ignore_bool; + +// Whether to ignore the indentation of an arithmetic operator. +extern Option<bool> +indent_ignore_arith; + +// Whether to indent a semicolon when inside a for parenthesis. +// If true, aligns under the open for parenthesis. +extern Option<bool> +indent_semicolon_for_paren; + +// Whether to ignore the indentation of a semicolon outside of a 'for' +// statement. +extern Option<bool> +indent_ignore_semicolon; + +// Whether to align the first expression to following ones +// if indent_bool_paren=1. +extern Option<bool> +indent_first_bool_expr; + +// Whether to align the first expression to following ones +// if indent_semicolon_for_paren=true. +extern Option<bool> +indent_first_for_expr; + +// If an open square is followed by a newline, whether to indent the next line +// so that it lines up after the open square (not recommended). +extern Option<bool> +indent_square_nl; + +// (ESQL/C) Whether to preserve the relative indent of 'EXEC SQL' bodies. +extern Option<bool> +indent_preserve_sql; + +// Whether to ignore the indentation of an assignment operator. +extern Option<bool> +indent_ignore_assign; + +// Whether to align continued statements at the '='. If false or if the '=' is +// followed by a newline, the next line is indent one tab. +extern Option<bool> +indent_align_assign; // = true + +// If true, the indentation of the chunks after a '=' sequence will be set at +// LHS token indentation column before '='. +extern Option<bool> +indent_off_after_assign; + +// Whether to align continued statements at the '('. If false or the '(' is +// followed by a newline, the next line indent is one tab. +extern Option<bool> +indent_align_paren; // = true + +// (OC) Whether to indent Objective-C code inside message selectors. +extern Option<bool> +indent_oc_inside_msg_sel; + +// (OC) Whether to indent Objective-C blocks at brace level instead of usual +// rules. +extern Option<bool> +indent_oc_block; + +// (OC) Indent for Objective-C blocks in a message relative to the parameter +// name. +// +// =0: Use indent_oc_block rules +// >0: Use specified number of spaces to indent +extern BoundedOption<unsigned, 0, 16> +indent_oc_block_msg; + +// (OC) Minimum indent for subsequent parameters +extern BoundedOption<unsigned, 0, 5000> +indent_oc_msg_colon; + +// (OC) Whether to prioritize aligning with initial colon (and stripping spaces +// from lines, if necessary). +extern Option<bool> +indent_oc_msg_prioritize_first_colon; // = true + +// (OC) Whether to indent blocks the way that Xcode does by default +// (from the keyword if the parameter is on its own line; otherwise, from the +// previous indentation level). Requires indent_oc_block_msg=true. +extern Option<bool> +indent_oc_block_msg_xcode_style; + +// (OC) Whether to indent blocks from where the brace is, relative to a +// message keyword. Requires indent_oc_block_msg=true. +extern Option<bool> +indent_oc_block_msg_from_keyword; + +// (OC) Whether to indent blocks from where the brace is, relative to a message +// colon. Requires indent_oc_block_msg=true. +extern Option<bool> +indent_oc_block_msg_from_colon; + +// (OC) Whether to indent blocks from where the block caret is. +// Requires indent_oc_block_msg=true. +extern Option<bool> +indent_oc_block_msg_from_caret; + +// (OC) Whether to indent blocks from where the brace caret is. +// Requires indent_oc_block_msg=true. +extern Option<bool> +indent_oc_block_msg_from_brace; + +// When indenting after virtual brace open and newline add further spaces to +// reach this minimum indent. +extern BoundedOption<unsigned, 0, 16> +indent_min_vbrace_open; + +// Whether to add further spaces after regular indent to reach next tabstop +// when indenting after virtual brace open and newline. +extern Option<bool> +indent_vbrace_open_on_tabstop; + +// How to indent after a brace followed by another token (not a newline). +// true: indent all contained lines to match the token +// false: indent all contained lines to match the brace +extern Option<bool> +indent_token_after_brace; // = true + +// Whether to indent the body of a C++11 lambda. +extern Option<bool> +indent_cpp_lambda_body; + +// How to indent compound literals that are being returned. +// true: add both the indent from return & the compound literal open brace +// (i.e. 2 indent levels) +// false: only indent 1 level, don't add the indent for the open brace, only +// add the indent for the return. +extern Option<bool> +indent_compound_literal_return; // = true + +// (C#) Whether to indent a 'using' block if no braces are used. +extern Option<bool> +indent_using_block; // = true + +// How to indent the continuation of ternary operator. +// +// 0: Off (default) +// 1: When the `if_false` is a continuation, indent it under the `if_true` branch +// 2: When the `:` is a continuation, indent it under `?` +extern BoundedOption<unsigned, 0, 2> +indent_ternary_operator; + +// Whether to indent the statements inside ternary operator. +extern Option<bool> +indent_inside_ternary_operator; + +// If true, the indentation of the chunks after a `return` sequence will be set at return indentation column. +extern Option<bool> +indent_off_after_return; + +// If true, the indentation of the chunks after a `return new` sequence will be set at return indentation column. +extern Option<bool> +indent_off_after_return_new; + +// If true, the tokens after return are indented with regular single indentation. By default (false) the indentation is after the return token. +extern Option<bool> +indent_single_after_return; + +// Whether to ignore indent and alignment for 'asm' blocks (i.e. assume they +// have their own indentation). +extern Option<bool> +indent_ignore_asm_block; + +// Don't indent the close parenthesis of a function definition, +// if the parenthesis is on its own line. +extern Option<bool> +donot_indent_func_def_close_paren; + +//END + +/////////////////////////////////////////////////////////////////////////////// +//BEGIN Newline adding and removing options + +// Whether to collapse empty blocks between '{' and '}' except for functions. +// Use nl_collapse_empty_body_functions to specify how empty function braces +// should be formatted. +extern Option<bool> +nl_collapse_empty_body; + +// Whether to collapse empty blocks between '{' and '}' for functions only. +// If true, overrides nl_inside_empty_func. +extern Option<bool> +nl_collapse_empty_body_functions; + +// Don't split one-line braced assignments, as in 'foo_t f = { 1, 2 };'. +extern Option<bool> +nl_assign_leave_one_liners; + +// Don't split one-line braced statements inside a 'class xx { }' body. +extern Option<bool> +nl_class_leave_one_liners; + +// Don't split one-line enums, as in 'enum foo { BAR = 15 };' +extern Option<bool> +nl_enum_leave_one_liners; + +// Don't split one-line get or set functions. +extern Option<bool> +nl_getset_leave_one_liners; + +// (C#) Don't split one-line property get or set functions. +extern Option<bool> +nl_cs_property_leave_one_liners; + +// Don't split one-line function definitions, as in 'int foo() { return 0; }'. +// might modify nl_func_type_name +extern Option<bool> +nl_func_leave_one_liners; + +// Don't split one-line C++11 lambdas, as in '[]() { return 0; }'. +extern Option<bool> +nl_cpp_lambda_leave_one_liners; + +// Don't split one-line if/else statements, as in 'if(...) b++;'. +extern Option<bool> +nl_if_leave_one_liners; + +// Don't split one-line while statements, as in 'while(...) b++;'. +extern Option<bool> +nl_while_leave_one_liners; + +// Don't split one-line do statements, as in 'do { b++; } while(...);'. +extern Option<bool> +nl_do_leave_one_liners; + +// Don't split one-line for statements, as in 'for(...) b++;'. +extern Option<bool> +nl_for_leave_one_liners; + +// (OC) Don't split one-line Objective-C messages. +extern Option<bool> +nl_oc_msg_leave_one_liner; + +// (OC) Add or remove newline between method declaration and '{'. +extern Option<iarf_e> +nl_oc_mdef_brace; + +// (OC) Add or remove newline between Objective-C block signature and '{'. +extern Option<iarf_e> +nl_oc_block_brace; + +// (OC) Add or remove blank line before '@interface' statement. +extern Option<iarf_e> +nl_oc_before_interface; + +// (OC) Add or remove blank line before '@implementation' statement. +extern Option<iarf_e> +nl_oc_before_implementation; + +// (OC) Add or remove blank line before '@end' statement. +extern Option<iarf_e> +nl_oc_before_end; + +// (OC) Add or remove newline between '@interface' and '{'. +extern Option<iarf_e> +nl_oc_interface_brace; + +// (OC) Add or remove newline between '@implementation' and '{'. +extern Option<iarf_e> +nl_oc_implementation_brace; + +// Add or remove newlines at the start of the file. +extern Option<iarf_e> +nl_start_of_file; + +// The minimum number of newlines at the start of the file (only used if +// nl_start_of_file is 'add' or 'force'). +extern BoundedOption<unsigned, 0, 16> +nl_start_of_file_min; + +// Add or remove newline at the end of the file. +extern Option<iarf_e> +nl_end_of_file; + +// The minimum number of newlines at the end of the file (only used if +// nl_end_of_file is 'add' or 'force'). +extern BoundedOption<unsigned, 0, 16> +nl_end_of_file_min; + +// Add or remove newline between '=' and '{'. +extern Option<iarf_e> +nl_assign_brace; + +// (D) Add or remove newline between '=' and '['. +extern Option<iarf_e> +nl_assign_square; + +// Add or remove newline between '[]' and '{'. +extern Option<iarf_e> +nl_tsquare_brace; + +// (D) Add or remove newline after '= ['. Will also affect the newline before +// the ']'. +extern Option<iarf_e> +nl_after_square_assign; + +// Add or remove newline between a function call's ')' and '{', as in +// 'list_for_each(item, &list) { }'. +extern Option<iarf_e> +nl_fcall_brace; + +// Add or remove newline between 'enum' and '{'. +extern Option<iarf_e> +nl_enum_brace; + +// Add or remove newline between 'enum' and 'class'. +extern Option<iarf_e> +nl_enum_class; + +// Add or remove newline between 'enum class' and the identifier. +extern Option<iarf_e> +nl_enum_class_identifier; + +// Add or remove newline between 'enum class' type and ':'. +extern Option<iarf_e> +nl_enum_identifier_colon; + +// Add or remove newline between 'enum class identifier :' and type. +extern Option<iarf_e> +nl_enum_colon_type; + +// Add or remove newline between 'struct and '{'. +extern Option<iarf_e> +nl_struct_brace; + +// Add or remove newline between 'union' and '{'. +extern Option<iarf_e> +nl_union_brace; + +// Add or remove newline between 'if' and '{'. +extern Option<iarf_e> +nl_if_brace; + +// Add or remove newline between '}' and 'else'. +extern Option<iarf_e> +nl_brace_else; + +// Add or remove newline between 'else if' and '{'. If set to ignore, +// nl_if_brace is used instead. +extern Option<iarf_e> +nl_elseif_brace; + +// Add or remove newline between 'else' and '{'. +extern Option<iarf_e> +nl_else_brace; + +// Add or remove newline between 'else' and 'if'. +extern Option<iarf_e> +nl_else_if; + +// Add or remove newline before '{' opening brace +extern Option<iarf_e> +nl_before_opening_brace_func_class_def; + +// Add or remove newline before 'if'/'else if' closing parenthesis. +extern Option<iarf_e> +nl_before_if_closing_paren; + +// Add or remove newline between '}' and 'finally'. +extern Option<iarf_e> +nl_brace_finally; + +// Add or remove newline between 'finally' and '{'. +extern Option<iarf_e> +nl_finally_brace; + +// Add or remove newline between 'try' and '{'. +extern Option<iarf_e> +nl_try_brace; + +// Add or remove newline between get/set and '{'. +extern Option<iarf_e> +nl_getset_brace; + +// Add or remove newline between 'for' and '{'. +extern Option<iarf_e> +nl_for_brace; + +// Add or remove newline before the '{' of a 'catch' statement, as in +// 'catch (decl) <here> {'. +extern Option<iarf_e> +nl_catch_brace; + +// (OC) Add or remove newline before the '{' of a '@catch' statement, as in +// '@catch (decl) <here> {'. If set to ignore, nl_catch_brace is used. +extern Option<iarf_e> +nl_oc_catch_brace; + +// Add or remove newline between '}' and 'catch'. +extern Option<iarf_e> +nl_brace_catch; + +// (OC) Add or remove newline between '}' and '@catch'. If set to ignore, +// nl_brace_catch is used. +extern Option<iarf_e> +nl_oc_brace_catch; + +// Add or remove newline between '}' and ']'. +extern Option<iarf_e> +nl_brace_square; + +// Add or remove newline between '}' and ')' in a function invocation. +extern Option<iarf_e> +nl_brace_fparen; + +// Add or remove newline between 'while' and '{'. +extern Option<iarf_e> +nl_while_brace; + +// (D) Add or remove newline between 'scope (x)' and '{'. +extern Option<iarf_e> +nl_scope_brace; + +// (D) Add or remove newline between 'unittest' and '{'. +extern Option<iarf_e> +nl_unittest_brace; + +// (D) Add or remove newline between 'version (x)' and '{'. +extern Option<iarf_e> +nl_version_brace; + +// (C#) Add or remove newline between 'using' and '{'. +extern Option<iarf_e> +nl_using_brace; + +// Add or remove newline between two open or close braces. Due to general +// newline/brace handling, REMOVE may not work. +extern Option<iarf_e> +nl_brace_brace; + +// Add or remove newline between 'do' and '{'. +extern Option<iarf_e> +nl_do_brace; + +// Add or remove newline between '}' and 'while' of 'do' statement. +extern Option<iarf_e> +nl_brace_while; + +// Add or remove newline between 'switch' and '{'. +extern Option<iarf_e> +nl_switch_brace; + +// Add or remove newline between 'synchronized' and '{'. +extern Option<iarf_e> +nl_synchronized_brace; + +// Add a newline between ')' and '{' if the ')' is on a different line than the +// if/for/etc. +// +// Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch and +// nl_catch_brace. +extern Option<bool> +nl_multi_line_cond; + +// Add a newline after '(' if an if/for/while/switch condition spans multiple +// lines +extern Option<iarf_e> +nl_multi_line_sparen_open; + +// Add a newline before ')' if an if/for/while/switch condition spans multiple +// lines. Overrides nl_before_if_closing_paren if both are specified. +extern Option<iarf_e> +nl_multi_line_sparen_close; + +// Force a newline in a define after the macro name for multi-line defines. +extern Option<bool> +nl_multi_line_define; + +// Whether to add a newline before 'case', and a blank line before a 'case' +// statement that follows a ';' or '}'. +extern Option<bool> +nl_before_case; + +// Whether to add a newline after a 'case' statement. +extern Option<bool> +nl_after_case; + +// Add or remove newline between a case ':' and '{'. +// +// Overrides nl_after_case. +extern Option<iarf_e> +nl_case_colon_brace; + +// Add or remove newline between ')' and 'throw'. +extern Option<iarf_e> +nl_before_throw; + +// Add or remove newline between 'namespace' and '{'. +extern Option<iarf_e> +nl_namespace_brace; + +// Add or remove newline after 'template<...>' of a template class. +extern Option<iarf_e> +nl_template_class; + +// Add or remove newline after 'template<...>' of a template class declaration. +// +// Overrides nl_template_class. +extern Option<iarf_e> +nl_template_class_decl; + +// Add or remove newline after 'template<>' of a specialized class declaration. +// +// Overrides nl_template_class_decl. +extern Option<iarf_e> +nl_template_class_decl_special; + +// Add or remove newline after 'template<...>' of a template class definition. +// +// Overrides nl_template_class. +extern Option<iarf_e> +nl_template_class_def; + +// Add or remove newline after 'template<>' of a specialized class definition. +// +// Overrides nl_template_class_def. +extern Option<iarf_e> +nl_template_class_def_special; + +// Add or remove newline after 'template<...>' of a template function. +extern Option<iarf_e> +nl_template_func; + +// Add or remove newline after 'template<...>' of a template function +// declaration. +// +// Overrides nl_template_func. +extern Option<iarf_e> +nl_template_func_decl; + +// Add or remove newline after 'template<>' of a specialized function +// declaration. +// +// Overrides nl_template_func_decl. +extern Option<iarf_e> +nl_template_func_decl_special; + +// Add or remove newline after 'template<...>' of a template function +// definition. +// +// Overrides nl_template_func. +extern Option<iarf_e> +nl_template_func_def; + +// Add or remove newline after 'template<>' of a specialized function +// definition. +// +// Overrides nl_template_func_def. +extern Option<iarf_e> +nl_template_func_def_special; + +// Add or remove newline after 'template<...>' of a template variable. +extern Option<iarf_e> +nl_template_var; + +// Add or remove newline between 'template<...>' and 'using' of a templated +// type alias. +extern Option<iarf_e> +nl_template_using; + +// Add or remove newline between 'class' and '{'. +extern Option<iarf_e> +nl_class_brace; + +// Add or remove newline before or after (depending on pos_class_comma, +// may not be IGNORE) each',' in the base class list. +extern Option<iarf_e> +nl_class_init_args; + +// Add or remove newline after each ',' in the constructor member +// initialization. Related to nl_constr_colon, pos_constr_colon and +// pos_constr_comma. +extern Option<iarf_e> +nl_constr_init_args; + +// Add or remove newline before first element, after comma, and after last +// element, in 'enum'. +extern Option<iarf_e> +nl_enum_own_lines; + +// Add or remove newline between return type and function name in a function +// definition. +// might be modified by nl_func_leave_one_liners +extern Option<iarf_e> +nl_func_type_name; + +// Add or remove newline between return type and function name inside a class +// definition. If set to ignore, nl_func_type_name or nl_func_proto_type_name +// is used instead. +extern Option<iarf_e> +nl_func_type_name_class; + +// Add or remove newline between class specification and '::' +// in 'void A::f() { }'. Only appears in separate member implementation (does +// not appear with in-line implementation). +extern Option<iarf_e> +nl_func_class_scope; + +// Add or remove newline between function scope and name, as in +// 'void A :: <here> f() { }'. +extern Option<iarf_e> +nl_func_scope_name; + +// Add or remove newline between return type and function name in a prototype. +extern Option<iarf_e> +nl_func_proto_type_name; + +// Add or remove newline between a function name and the opening '(' in the +// declaration. +extern Option<iarf_e> +nl_func_paren; + +// Overrides nl_func_paren for functions with no parameters. +extern Option<iarf_e> +nl_func_paren_empty; + +// Add or remove newline between a function name and the opening '(' in the +// definition. +extern Option<iarf_e> +nl_func_def_paren; + +// Overrides nl_func_def_paren for functions with no parameters. +extern Option<iarf_e> +nl_func_def_paren_empty; + +// Add or remove newline between a function name and the opening '(' in the +// call. +extern Option<iarf_e> +nl_func_call_paren; + +// Overrides nl_func_call_paren for functions with no parameters. +extern Option<iarf_e> +nl_func_call_paren_empty; + +// Add or remove newline after '(' in a function declaration. +extern Option<iarf_e> +nl_func_decl_start; + +// Add or remove newline after '(' in a function definition. +extern Option<iarf_e> +nl_func_def_start; + +// Overrides nl_func_decl_start when there is only one parameter. +extern Option<iarf_e> +nl_func_decl_start_single; + +// Overrides nl_func_def_start when there is only one parameter. +extern Option<iarf_e> +nl_func_def_start_single; + +// Whether to add a newline after '(' in a function declaration if '(' and ')' +// are in different lines. If false, nl_func_decl_start is used instead. +extern Option<bool> +nl_func_decl_start_multi_line; + +// Whether to add a newline after '(' in a function definition if '(' and ')' +// are in different lines. If false, nl_func_def_start is used instead. +extern Option<bool> +nl_func_def_start_multi_line; + +// Add or remove newline after each ',' in a function declaration. +extern Option<iarf_e> +nl_func_decl_args; + +// Add or remove newline after each ',' in a function definition. +extern Option<iarf_e> +nl_func_def_args; + +// Add or remove newline after each ',' in a function call. +extern Option<iarf_e> +nl_func_call_args; + +// Whether to add a newline after each ',' in a function declaration if '(' +// and ')' are in different lines. If false, nl_func_decl_args is used instead. +extern Option<bool> +nl_func_decl_args_multi_line; + +// Whether to add a newline after each ',' in a function definition if '(' +// and ')' are in different lines. If false, nl_func_def_args is used instead. +extern Option<bool> +nl_func_def_args_multi_line; + +// Add or remove newline before the ')' in a function declaration. +extern Option<iarf_e> +nl_func_decl_end; + +// Add or remove newline before the ')' in a function definition. +extern Option<iarf_e> +nl_func_def_end; + +// Overrides nl_func_decl_end when there is only one parameter. +extern Option<iarf_e> +nl_func_decl_end_single; + +// Overrides nl_func_def_end when there is only one parameter. +extern Option<iarf_e> +nl_func_def_end_single; + +// Whether to add a newline before ')' in a function declaration if '(' and ')' +// are in different lines. If false, nl_func_decl_end is used instead. +extern Option<bool> +nl_func_decl_end_multi_line; + +// Whether to add a newline before ')' in a function definition if '(' and ')' +// are in different lines. If false, nl_func_def_end is used instead. +extern Option<bool> +nl_func_def_end_multi_line; + +// Add or remove newline between '()' in a function declaration. +extern Option<iarf_e> +nl_func_decl_empty; + +// Add or remove newline between '()' in a function definition. +extern Option<iarf_e> +nl_func_def_empty; + +// Add or remove newline between '()' in a function call. +extern Option<iarf_e> +nl_func_call_empty; + +// Whether to add a newline after '(' in a function call, +// has preference over nl_func_call_start_multi_line. +extern Option<iarf_e> +nl_func_call_start; + +// Whether to add a newline before ')' in a function call. +extern Option<iarf_e> +nl_func_call_end; + +// Whether to add a newline after '(' in a function call if '(' and ')' are in +// different lines. +extern Option<bool> +nl_func_call_start_multi_line; + +// Whether to add a newline after each ',' in a function call if '(' and ')' +// are in different lines. +extern Option<bool> +nl_func_call_args_multi_line; + +// Whether to add a newline before ')' in a function call if '(' and ')' are in +// different lines. +extern Option<bool> +nl_func_call_end_multi_line; + +// Whether to respect nl_func_call_XXX option in case of closure args. +extern Option<bool> +nl_func_call_args_multi_line_ignore_closures; // false + +// Whether to add a newline after '<' of a template parameter list. +extern Option<bool> +nl_template_start; + +// Whether to add a newline after each ',' in a template parameter list. +extern Option<bool> +nl_template_args; + +// Whether to add a newline before '>' of a template parameter list. +extern Option<bool> +nl_template_end; + +// (OC) Whether to put each Objective-C message parameter on a separate line. +// See nl_oc_msg_leave_one_liner. +extern Option<bool> +nl_oc_msg_args; + +// (OC) Minimum number of Objective-C message parameters before applying nl_oc_msg_args. +extern BoundedOption<unsigned, 0, 16> +nl_oc_msg_args_min_params; + +// (OC) Max code width of Objective-C message before applying nl_oc_msg_args. +extern BoundedOption<unsigned, 0, 10000> +nl_oc_msg_args_max_code_width; + +// Add or remove newline between function signature and '{'. +extern Option<iarf_e> +nl_fdef_brace; + +// Add or remove newline between function signature and '{', +// if signature ends with ')'. Overrides nl_fdef_brace. +extern Option<iarf_e> +nl_fdef_brace_cond; + +// Add or remove newline between C++11 lambda signature and '{'. +extern Option<iarf_e> +nl_cpp_ldef_brace; + +// Add or remove newline between 'return' and the return expression. +extern Option<iarf_e> +nl_return_expr; + +// Add or remove newline between 'throw' and the throw expression. +extern Option<iarf_e> +nl_throw_expr; + +// Whether to add a newline after semicolons, except in 'for' statements. +extern Option<bool> +nl_after_semicolon; + +// (Java) Add or remove newline between the ')' and '{{' of the double brace +// initializer. +extern Option<iarf_e> +nl_paren_dbrace_open; + +// Whether to add a newline after the type in an unnamed temporary +// direct-list-initialization, better: +// before a direct-list-initialization. +extern Option<iarf_e> +nl_type_brace_init_lst; + +// Whether to add a newline after the open brace in an unnamed temporary +// direct-list-initialization. +extern Option<iarf_e> +nl_type_brace_init_lst_open; + +// Whether to add a newline before the close brace in an unnamed temporary +// direct-list-initialization. +extern Option<iarf_e> +nl_type_brace_init_lst_close; + +// Whether to add a newline before '{'. +extern Option<bool> +nl_before_brace_open; + +// Whether to add a newline after '{'. +extern Option<bool> +nl_after_brace_open; + +// Whether to add a newline between the open brace and a trailing single-line +// comment. Requires nl_after_brace_open=true. +extern Option<bool> +nl_after_brace_open_cmt; + +// Whether to add a newline after a virtual brace open with a non-empty body. +// These occur in un-braced if/while/do/for statement bodies. +extern Option<bool> +nl_after_vbrace_open; + +// Whether to add a newline after a virtual brace open with an empty body. +// These occur in un-braced if/while/do/for statement bodies. +extern Option<bool> +nl_after_vbrace_open_empty; + +// Whether to add a newline after '}'. Does not apply if followed by a +// necessary ';'. +extern Option<bool> +nl_after_brace_close; + +// Whether to add a newline after a virtual brace close, +// as in 'if (foo) a++; <here> return;'. +extern Option<bool> +nl_after_vbrace_close; + +// Add or remove newline between the close brace and identifier, +// as in 'struct { int a; } <here> b;'. Affects enumerations, unions and +// structures. If set to ignore, uses nl_after_brace_close. +extern Option<iarf_e> +nl_brace_struct_var; + +// Whether to alter newlines in '#define' macros. +extern Option<bool> +nl_define_macro; + +// Whether to alter newlines between consecutive parenthesis closes. The number +// of closing parentheses in a line will depend on respective open parenthesis +// lines. +extern Option<bool> +nl_squeeze_paren_close; + +// Whether to remove blanks after '#ifxx' and '#elxx', or before '#elxx' and +// '#endif'. Does not affect top-level #ifdefs. +extern Option<bool> +nl_squeeze_ifdef; + +// Makes the nl_squeeze_ifdef option affect the top-level #ifdefs as well. +extern Option<bool> +nl_squeeze_ifdef_top_level; + +// Add or remove blank line before 'if'. +extern Option<iarf_e> +nl_before_if; + +// Add or remove blank line after 'if' statement. Add/Force work only if the +// next token is not a closing brace. +extern Option<iarf_e> +nl_after_if; + +// Add or remove blank line before 'for'. +extern Option<iarf_e> +nl_before_for; + +// Add or remove blank line after 'for' statement. +extern Option<iarf_e> +nl_after_for; + +// Add or remove blank line before 'while'. +extern Option<iarf_e> +nl_before_while; + +// Add or remove blank line after 'while' statement. +extern Option<iarf_e> +nl_after_while; + +// Add or remove blank line before 'switch'. +extern Option<iarf_e> +nl_before_switch; + +// Add or remove blank line after 'switch' statement. +extern Option<iarf_e> +nl_after_switch; + +// Add or remove blank line before 'synchronized'. +extern Option<iarf_e> +nl_before_synchronized; + +// Add or remove blank line after 'synchronized' statement. +extern Option<iarf_e> +nl_after_synchronized; + +// Add or remove blank line before 'do'. +extern Option<iarf_e> +nl_before_do; + +// Add or remove blank line after 'do/while' statement. +extern Option<iarf_e> +nl_after_do; + +// Ignore nl_before_{if,for,switch,do,synchronized} if the control +// statement is immediately after a case statement. +// if nl_before_{if,for,switch,do} is set to remove, this option +// does nothing. +extern Option<bool> +nl_before_ignore_after_case; + +// Whether to put a blank line before 'return' statements, unless after an open +// brace. +extern Option<bool> +nl_before_return; + +// Whether to put a blank line after 'return' statements, unless followed by a +// close brace. +extern Option<bool> +nl_after_return; + +// Whether to put a blank line before a member '.' or '->' operators. +extern Option<iarf_e> +nl_before_member; + +// (Java) Whether to put a blank line after a member '.' or '->' operators. +extern Option<iarf_e> +nl_after_member; + +// Whether to double-space commented-entries in 'struct'/'union'/'enum'. +extern Option<bool> +nl_ds_struct_enum_cmt; + +// Whether to force a newline before '}' of a 'struct'/'union'/'enum'. +// (Lower priority than eat_blanks_before_close_brace.) +extern Option<bool> +nl_ds_struct_enum_close_brace; + +// Add or remove newline before or after (depending on pos_class_colon) a class +// colon, as in 'class Foo <here> : <or here> public Bar'. +extern Option<iarf_e> +nl_class_colon; + +// Add or remove newline around a class constructor colon. The exact position +// depends on nl_constr_init_args, pos_constr_colon and pos_constr_comma. +extern Option<iarf_e> +nl_constr_colon; + +// Whether to collapse a two-line namespace, like 'namespace foo\n{ decl; }' +// into a single line. If true, prevents other brace newline rules from turning +// such code into four lines. If true, it also preserves one-liner namespaces. +extern Option<bool> +nl_namespace_two_to_one_liner; + +// Whether to remove a newline in simple unbraced if statements, turning them +// into one-liners, as in 'if(b)\n i++;' => 'if(b) i++;'. +extern Option<bool> +nl_create_if_one_liner; + +// Whether to remove a newline in simple unbraced for statements, turning them +// into one-liners, as in 'for (...)\n stmt;' => 'for (...) stmt;'. +extern Option<bool> +nl_create_for_one_liner; + +// Whether to remove a newline in simple unbraced while statements, turning +// them into one-liners, as in 'while (expr)\n stmt;' => 'while (expr) stmt;'. +extern Option<bool> +nl_create_while_one_liner; + +// Whether to collapse a function definition whose body (not counting braces) +// is only one line so that the entire definition (prototype, braces, body) is +// a single line. +extern Option<bool> +nl_create_func_def_one_liner; + +// Whether to split one-line simple list definitions into three lines by +// adding newlines, as in 'int a[12] = { <here> 0 <here> };'. +extern Option<bool> +nl_create_list_one_liner; + +// Whether to split one-line simple unbraced if statements into two lines by +// adding a newline, as in 'if(b) <here> i++;'. +extern Option<bool> +nl_split_if_one_liner; + +// Whether to split one-line simple unbraced for statements into two lines by +// adding a newline, as in 'for (...) <here> stmt;'. +extern Option<bool> +nl_split_for_one_liner; + +// Whether to split one-line simple unbraced while statements into two lines by +// adding a newline, as in 'while (expr) <here> stmt;'. +extern Option<bool> +nl_split_while_one_liner; + +// Don't add a newline before a cpp-comment in a parameter list of a function +// call. +extern Option<bool> +donot_add_nl_before_cpp_comment; + +//END + +/////////////////////////////////////////////////////////////////////////////// +//BEGIN Blank line options + +// The maximum number of consecutive newlines (3 = 2 blank lines). +extern BoundedOption<unsigned, 0, 16> +nl_max; + +// The maximum number of consecutive newlines in a function. +extern BoundedOption<unsigned, 0, 16> +nl_max_blank_in_func; + +// The number of newlines inside an empty function body. +// This option overrides eat_blanks_after_open_brace and +// eat_blanks_before_close_brace, but is ignored when +// nl_collapse_empty_body_functions=true +extern BoundedOption<unsigned, 0, 16> +nl_inside_empty_func; + +// The number of newlines before a function prototype. +extern BoundedOption<unsigned, 0, 16> +nl_before_func_body_proto; + +// The number of newlines before a multi-line function definition. Where +// applicable, this option is overridden with eat_blanks_after_open_brace=true +extern BoundedOption<unsigned, 0, 16> +nl_before_func_body_def; + +// The number of newlines before a class constructor/destructor prototype. +extern BoundedOption<unsigned, 0, 16> +nl_before_func_class_proto; + +// The number of newlines before a class constructor/destructor definition. +extern BoundedOption<unsigned, 0, 16> +nl_before_func_class_def; + +// The number of newlines after a function prototype. +extern BoundedOption<unsigned, 0, 16> +nl_after_func_proto; + +// The number of newlines after a function prototype, if not followed by +// another function prototype. +extern BoundedOption<unsigned, 0, 16> +nl_after_func_proto_group; + +// The number of newlines after a class constructor/destructor prototype. +extern BoundedOption<unsigned, 0, 16> +nl_after_func_class_proto; + +// The number of newlines after a class constructor/destructor prototype, +// if not followed by another constructor/destructor prototype. +extern BoundedOption<unsigned, 0, 16> +nl_after_func_class_proto_group; + +// Whether one-line method definitions inside a class body should be treated +// as if they were prototypes for the purposes of adding newlines. +// +// Requires nl_class_leave_one_liners=true. Overrides nl_before_func_body_def +// and nl_before_func_class_def for one-liners. +extern Option<bool> +nl_class_leave_one_liner_groups; + +// The number of newlines after '}' of a multi-line function body. +extern BoundedOption<unsigned, 0, 16> +nl_after_func_body; + +// The number of newlines after '}' of a multi-line function body in a class +// declaration. Also affects class constructors/destructors. +// +// Overrides nl_after_func_body. +extern BoundedOption<unsigned, 0, 16> +nl_after_func_body_class; + +// The number of newlines after '}' of a single line function body. Also +// affects class constructors/destructors. +// +// Overrides nl_after_func_body and nl_after_func_body_class. +extern BoundedOption<unsigned, 0, 16> +nl_after_func_body_one_liner; + +// The number of newlines before a block of typedefs. If nl_after_access_spec +// is non-zero, that option takes precedence. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_typedef_blk_start; + +// The number of newlines after a block of typedefs. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_typedef_blk_end; + +// The maximum number of consecutive newlines within a block of typedefs. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_typedef_blk_in; + +// The minimum number of blank lines after a block of variable definitions +// at the top of a function body. If any preprocessor directives appear +// between the opening brace of the function and the variable block, then +// it is considered as not at the top of the function.Newlines are added +// before trailing preprocessor directives, if any exist. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_var_def_blk_end_func_top; + +// The minimum number of empty newlines before a block of variable definitions +// not at the top of a function body. If nl_after_access_spec is non-zero, +// that option takes precedence. Newlines are not added at the top of the +// file or just after an opening brace. Newlines are added above any +// preprocessor directives before the block. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_var_def_blk_start; + +// The minimum number of empty newlines after a block of variable definitions +// not at the top of a function body. Newlines are not added if the block +// is at the bottom of the file or just before a preprocessor directive. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_var_def_blk_end; + +// The maximum number of consecutive newlines within a block of variable +// definitions. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_var_def_blk_in; + +// The minimum number of newlines before a multi-line comment. +// Doesn't apply if after a brace open or another multi-line comment. +extern BoundedOption<unsigned, 0, 16> +nl_before_block_comment; + +// The minimum number of newlines before a single-line C comment. +// Doesn't apply if after a brace open or other single-line C comments. +extern BoundedOption<unsigned, 0, 16> +nl_before_c_comment; + +// The minimum number of newlines before a CPP comment. +// Doesn't apply if after a brace open or other CPP comments. +extern BoundedOption<unsigned, 0, 16> +nl_before_cpp_comment; + +// Whether to force a newline after a multi-line comment. +extern Option<bool> +nl_after_multiline_comment; + +// Whether to force a newline after a label's colon. +extern Option<bool> +nl_after_label_colon; + +// The number of newlines before a struct definition. +extern BoundedOption<unsigned, 0, 16> +nl_before_struct; + +// The number of newlines after '}' or ';' of a struct/enum/union definition. +extern BoundedOption<unsigned, 0, 16> +nl_after_struct; + +// The number of newlines before a class definition. +extern BoundedOption<unsigned, 0, 16> +nl_before_class; + +// The number of newlines after '}' or ';' of a class definition. +extern BoundedOption<unsigned, 0, 16> +nl_after_class; + +// The number of newlines before a namespace. +extern BoundedOption<unsigned, 0, 16> +nl_before_namespace; + +// The number of newlines after '{' of a namespace. This also adds newlines +// before the matching '}'. +// +// 0: Apply eat_blanks_after_open_brace or eat_blanks_before_close_brace if +// applicable, otherwise no change. +// +// Overrides eat_blanks_after_open_brace and eat_blanks_before_close_brace. +extern BoundedOption<unsigned, 0, 16> +nl_inside_namespace; + +// The number of newlines after '}' of a namespace. +extern BoundedOption<unsigned, 0, 16> +nl_after_namespace; + +// The number of newlines before an access specifier label. This also includes +// the Qt-specific 'signals:' and 'slots:'. Will not change the newline count +// if after a brace open. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_before_access_spec; + +// The number of newlines after an access specifier label. This also includes +// the Qt-specific 'signals:' and 'slots:'. Will not change the newline count +// if after a brace open. +// +// 0: No change (default). +// +// Overrides nl_typedef_blk_start and nl_var_def_blk_start. +extern BoundedOption<unsigned, 0, 16> +nl_after_access_spec; + +// The number of newlines between a function definition and the function +// comment, as in '// comment\n <here> void foo() {...}'. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_comment_func_def; + +// The number of newlines after a try-catch-finally block that isn't followed +// by a brace close. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_after_try_catch_finally; + +// (C#) The number of newlines before and after a property, indexer or event +// declaration. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_around_cs_property; + +// (C#) The number of newlines between the get/set/add/remove handlers. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_between_get_set; + +// (C#) Add or remove newline between property and the '{'. +extern Option<iarf_e> +nl_property_brace; + +// Whether to remove blank lines after '{'. +extern Option<bool> +eat_blanks_after_open_brace; + +// Whether to remove blank lines before '}'. +extern Option<bool> +eat_blanks_before_close_brace; + +// How aggressively to remove extra newlines not in preprocessor. +// +// 0: No change (default) +// 1: Remove most newlines not handled by other config +// 2: Remove all newlines and reformat completely by config +extern BoundedOption<unsigned, 0, 2> +nl_remove_extra_newlines; + +// (Java) Add or remove newline after an annotation statement. Only affects +// annotations that are after a newline. +extern Option<iarf_e> +nl_after_annotation; + +// (Java) Add or remove newline between two annotations. +extern Option<iarf_e> +nl_between_annotation; + +// The number of newlines before a whole-file #ifdef. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_before_whole_file_ifdef; + +// The number of newlines after a whole-file #ifdef. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_after_whole_file_ifdef; + +// The number of newlines before a whole-file #endif. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_before_whole_file_endif; + +// The number of newlines after a whole-file #endif. +// +// 0: No change (default). +extern BoundedOption<unsigned, 0, 16> +nl_after_whole_file_endif; + +//END + +/////////////////////////////////////////////////////////////////////////////// +//BEGIN Positioning options + +// The position of arithmetic operators in wrapped expressions. +extern Option<token_pos_e> +pos_arith; + +// The position of assignment in wrapped expressions. Do not affect '=' +// followed by '{'. +extern Option<token_pos_e> +pos_assign; + +// The position of Boolean operators in wrapped expressions. +extern Option<token_pos_e> +pos_bool; + +// The position of comparison operators in wrapped expressions. +extern Option<token_pos_e> +pos_compare; + +// The position of conditional operators, as in the '?' and ':' of +// 'expr ? stmt : stmt', in wrapped expressions. +extern Option<token_pos_e> +pos_conditional; + +// The position of the comma in wrapped expressions. +extern Option<token_pos_e> +pos_comma; + +// The position of the comma in enum entries. +extern Option<token_pos_e> +pos_enum_comma; + +// The position of the comma in the base class list if there is more than one +// line. Affects nl_class_init_args. +extern Option<token_pos_e> +pos_class_comma; + +// The position of the comma in the constructor initialization list. +// Related to nl_constr_colon, nl_constr_init_args and pos_constr_colon. +extern Option<token_pos_e> +pos_constr_comma; + +// The position of trailing/leading class colon, between class and base class +// list. Affects nl_class_colon. +extern Option<token_pos_e> +pos_class_colon; + +// The position of colons between constructor and member initialization. +// Related to nl_constr_colon, nl_constr_init_args and pos_constr_comma. +extern Option<token_pos_e> +pos_constr_colon; + +// The position of shift operators in wrapped expressions. +extern Option<token_pos_e> +pos_shift; + +//END + +/////////////////////////////////////////////////////////////////////////////// +//BEGIN Line splitting options + +// Try to limit code width to N columns. +extern BoundedOption<unsigned, 0, 10000> +code_width; + +// Whether to fully split long 'for' statements at semi-colons. +extern Option<bool> +ls_for_split_full; + +// Whether to fully split long function prototypes/calls at commas. +// The option ls_code_width has priority over the option ls_func_split_full. +extern Option<bool> +ls_func_split_full; + +// Whether to split lines as close to code_width as possible and ignore some +// groupings. +// The option ls_code_width has priority over the option ls_func_split_full. +extern Option<bool> +ls_code_width; + +//END + +/////////////////////////////////////////////////////////////////////////////// +//BEGIN Code alignment options (not left column spaces/tabs) + +// Whether to keep non-indenting tabs. +extern Option<bool> +align_keep_tabs; + +// Whether to use tabs for aligning. +extern Option<bool> +align_with_tabs; + +// Whether to bump out to the next tab when aligning. +extern Option<bool> +align_on_tabstop; + +// Whether to right-align numbers. +extern Option<bool> +align_number_right; + +// Whether to keep whitespace not required for alignment. +extern Option<bool> +align_keep_extra_space; + +// Whether to align variable definitions in prototypes and functions. +extern Option<bool> +align_func_params; + +// The span for aligning parameter definitions in function on parameter name. +// +// 0: Don't align (default). +extern BoundedOption<unsigned, 0, 16> +align_func_params_span; + +// The threshold for aligning function parameter definitions. +// Use a negative number for absolute thresholds. +// +// 0: No limit (default). +extern BoundedOption<signed, -1000, 5000> +align_func_params_thresh; + +// The gap for aligning function parameter definitions. +extern BoundedOption<unsigned, 0, 16> +align_func_params_gap; + +// The span for aligning constructor value. +// +// 0: Don't align (default). +extern BoundedOption<unsigned, 0, 16> +align_constr_value_span; + +// The threshold for aligning constructor value. +// Use a negative number for absolute thresholds. +// +// 0: No limit (default). +extern BoundedOption<signed, -1000, 5000> +align_constr_value_thresh; + +// The gap for aligning constructor value. +extern BoundedOption<unsigned, 0, 16> +align_constr_value_gap; + +// Whether to align parameters in single-line functions that have the same +// name. The function names must already be aligned with each other. +extern Option<bool> +align_same_func_call_params; + +// The span for aligning function-call parameters for single line functions. +// +// 0: Don't align (default). +extern BoundedOption<unsigned, 0, 5000> +align_same_func_call_params_span; + +// The threshold for aligning function-call parameters for single line +// functions. +// Use a negative number for absolute thresholds. +// +// 0: No limit (default). +extern BoundedOption<signed, -1000, 5000> +align_same_func_call_params_thresh; + +// The span for aligning variable definitions. +// +// 0: Don't align (default). +extern BoundedOption<unsigned, 0, 5000> +align_var_def_span; + +// How to consider (or treat) the '*' in the alignment of variable definitions. +// +// 0: Part of the type 'void * foo;' (default) +// 1: Part of the variable 'void *foo;' +// 2: Dangling 'void *foo;' +// Dangling: the '*' will not be taken into account when aligning. +extern BoundedOption<unsigned, 0, 2> +align_var_def_star_style; + +// How to consider (or treat) the '&' in the alignment of variable definitions. +// +// 0: Part of the type 'long & foo;' (default) +// 1: Part of the variable 'long &foo;' +// 2: Dangling 'long &foo;' +// Dangling: the '&' will not be taken into account when aligning. +extern BoundedOption<unsigned, 0, 2> +align_var_def_amp_style; + +// The threshold for aligning variable definitions. +// Use a negative number for absolute thresholds. +// +// 0: No limit (default). +extern BoundedOption<signed, -1000, 5000> +align_var_def_thresh; + +// The gap for aligning variable definitions. +extern BoundedOption<unsigned, 0, 16> +align_var_def_gap; + +// Whether to align the colon in struct bit fields. +extern Option<bool> +align_var_def_colon; + +// The gap for aligning the colon in struct bit fields. +extern BoundedOption<unsigned, 0, 16> +align_var_def_colon_gap; + +// Whether to align any attribute after the variable name. +extern Option<bool> +align_var_def_attribute; + +// Whether to align inline struct/enum/union variable definitions. +extern Option<bool> +align_var_def_inline; + +// The span for aligning on '=' in assignments. +// +// 0: Don't align (default). +extern BoundedOption<unsigned, 0, 5000> +align_assign_span; + +// The span for aligning on '=' in function prototype modifier. +// +// 0: Don't align (default). +extern BoundedOption<unsigned, 0, 5000> +align_assign_func_proto_span; + +// The threshold for aligning on '=' in assignments. +// Use a negative number for absolute thresholds. +// +// 0: No limit (default). +extern BoundedOption<signed, -1000, 5000> +align_assign_thresh; + +// Whether to align on the left most assignment when multiple +// definitions are found on the same line. +// Depends on 'align_assign_span' and 'align_assign_thresh' settings. +extern Option<bool> +align_assign_on_multi_var_defs; + +// The span for aligning on '{' in braced init list. +// +// 0: Don't align (default). +extern BoundedOption<unsigned, 0, 5000> +align_braced_init_list_span; + +// The threshold for aligning on '{' in braced init list. +// Use a negative number for absolute thresholds. +// +// 0: No limit (default). +extern BoundedOption<signed, -1000, 5000> +align_braced_init_list_thresh; + +// How to apply align_assign_span to function declaration "assignments", i.e. +// 'virtual void foo() = 0' or '~foo() = {default|delete}'. +// +// 0: Align with other assignments (default) +// 1: Align with each other, ignoring regular assignments +// 2: Don't align +extern BoundedOption<unsigned, 0, 2> +align_assign_decl_func; + +// The span for aligning on '=' in enums. +// +// 0: Don't align (default). +extern BoundedOption<unsigned, 0, 5000> +align_enum_equ_span; + +// The threshold for aligning on '=' in enums. +// Use a negative number for absolute thresholds. +// +// 0: no limit (default). +extern BoundedOption<signed, -1000, 5000> +align_enum_equ_thresh; + +// The span for aligning class member definitions. +// +// 0: Don't align (default). +extern BoundedOption<unsigned, 0, 5000> +align_var_class_span; + +// The threshold for aligning class member definitions. +// Use a negative number for absolute thresholds. +// +// 0: No limit (default). +extern BoundedOption<signed, -1000, 5000> +align_var_class_thresh; + +// The gap for aligning class member definitions. +extern BoundedOption<unsigned, 0, 16> +align_var_class_gap; + +// The span for aligning struct/union member definitions. +// +// 0: Don't align (default). +extern BoundedOption<unsigned, 0, 5000> +align_var_struct_span; + +// The threshold for aligning struct/union member definitions. +// Use a negative number for absolute thresholds. +// +// 0: No limit (default). +extern BoundedOption<signed, -1000, 5000> +align_var_struct_thresh; + +// The gap for aligning struct/union member definitions. +extern BoundedOption<unsigned, 0, 16> +align_var_struct_gap; + +// The span for aligning struct initializer values. +// +// 0: Don't align (default). +extern BoundedOption<unsigned, 0, 5000> +align_struct_init_span; + +// The span for aligning single-line typedefs. +// +// 0: Don't align (default). +extern BoundedOption<unsigned, 0, 16> +align_typedef_span; + +// The minimum space between the type and the synonym of a typedef. +extern BoundedOption<unsigned, 0, 16> +align_typedef_gap; + +// How to align typedef'd functions with other typedefs. +// +// 0: Don't mix them at all (default) +// 1: Align the open parenthesis with the types +// 2: Align the function type name with the other type names +extern BoundedOption<unsigned, 0, 2> +align_typedef_func; + +// How to consider (or treat) the '*' in the alignment of typedefs. +// +// 0: Part of the typedef type, 'typedef int * pint;' (default) +// 1: Part of type name: 'typedef int *pint;' +// 2: Dangling: 'typedef int *pint;' +// Dangling: the '*' will not be taken into account when aligning. +extern BoundedOption<unsigned, 0, 2> +align_typedef_star_style; + +// How to consider (or treat) the '&' in the alignment of typedefs. +// +// 0: Part of the typedef type, 'typedef int & intref;' (default) +// 1: Part of type name: 'typedef int &intref;' +// 2: Dangling: 'typedef int &intref;' +// Dangling: the '&' will not be taken into account when aligning. +extern BoundedOption<unsigned, 0, 2> +align_typedef_amp_style; + +// The span for aligning comments that end lines. +// +// 0: Don't align (default). +extern BoundedOption<unsigned, 0, 5000> +align_right_cmt_span; + +// Minimum number of columns between preceding text and a trailing comment in +// order for the comment to qualify for being aligned. Must be non-zero to have +// an effect. +extern BoundedOption<unsigned, 0, 16> +align_right_cmt_gap; + +// If aligning comments, whether to mix with comments after '}' and #endif with +// less than three spaces before the comment. +extern Option<bool> +align_right_cmt_mix; + +// Whether to only align trailing comments that are at the same brace level. +extern Option<bool> +align_right_cmt_same_level; + +// Minimum column at which to align trailing comments. Comments which are +// aligned beyond this column, but which can be aligned in a lesser column, +// may be "pulled in". +// +// 0: Ignore (default). +extern BoundedOption<unsigned, 0, 200> +align_right_cmt_at_col; + +// The span for aligning function prototypes. +// +// 0: Don't align (default). +extern BoundedOption<unsigned, 0, 5000> +align_func_proto_span; + +// How to consider (or treat) the '*' in the alignment of function prototypes. +// +// 0: Part of the type 'void * foo();' (default) +// 1: Part of the function 'void *foo();' +// 2: Dangling 'void *foo();' +// Dangling: the '*' will not be taken into account when aligning. +extern BoundedOption<unsigned, 0, 2> +align_func_proto_star_style; + +// How to consider (or treat) the '&' in the alignment of function prototypes. +// +// 0: Part of the type 'long & foo();' (default) +// 1: Part of the function 'long &foo();' +// 2: Dangling 'long &foo();' +// Dangling: the '&' will not be taken into account when aligning. +extern BoundedOption<unsigned, 0, 2> +align_func_proto_amp_style; + +// The threshold for aligning function prototypes. +// Use a negative number for absolute thresholds. +// +// 0: No limit (default). +extern BoundedOption<signed, -1000, 5000> +align_func_proto_thresh; + +// Minimum gap between the return type and the function name. +extern BoundedOption<unsigned, 0, 16> +align_func_proto_gap; + +// Whether to align function prototypes on the 'operator' keyword instead of +// what follows. +extern Option<bool> +align_on_operator; + +// Whether to mix aligning prototype and variable declarations. If true, +// align_var_def_XXX options are used instead of align_func_proto_XXX options. +extern Option<bool> +align_mix_var_proto; + +// Whether to align single-line functions with function prototypes. +// Uses align_func_proto_span. +extern Option<bool> +align_single_line_func; + +// Whether to align the open brace of single-line functions. +// Requires align_single_line_func=true. Uses align_func_proto_span. +extern Option<bool> +align_single_line_brace; + +// Gap for align_single_line_brace. +extern BoundedOption<unsigned, 0, 16> +align_single_line_brace_gap; + +// (OC) The span for aligning Objective-C message specifications. +// +// 0: Don't align (default). +extern BoundedOption<unsigned, 0, 5000> +align_oc_msg_spec_span; + +// Whether to align macros wrapped with a backslash and a newline. This will +// not work right if the macro contains a multi-line comment. +extern Option<bool> +align_nl_cont; + +// Whether to align macro functions and variables together. +extern Option<bool> +align_pp_define_together; + +// The span for aligning on '#define' bodies. +// +// =0: Don't align (default) +// >0: Number of lines (including comments) between blocks +extern BoundedOption<unsigned, 0, 5000> +align_pp_define_span; + +// The minimum space between label and value of a preprocessor define. +extern BoundedOption<unsigned, 0, 16> +align_pp_define_gap; + +// Whether to align lines that start with '<<' with previous '<<'. +extern Option<bool> +align_left_shift; // = true + +// Whether to align comma-separated statements following '<<' (as used to +// initialize Eigen matrices). +extern Option<bool> +align_eigen_comma_init; + +// Whether to align text after 'asm volatile ()' colons. +extern Option<bool> +align_asm_colon; + +// (OC) Span for aligning parameters in an Objective-C message call +// on the ':'. +// +// 0: Don't align. +extern BoundedOption<unsigned, 0, 5000> +align_oc_msg_colon_span; + +// (OC) Whether to always align with the first parameter, even if it is too +// short. +extern Option<bool> +align_oc_msg_colon_first; + +// (OC) Whether to align parameters in an Objective-C '+' or '-' declaration +// on the ':'. +extern Option<bool> +align_oc_decl_colon; + +// (OC) Whether to not align parameters in an Objectve-C message call if first +// colon is not on next line of the message call (the same way Xcode does +// alignment) +extern Option<bool> +align_oc_msg_colon_xcode_like; + +//END + +/////////////////////////////////////////////////////////////////////////////// +//BEGIN Comment modification options + +// Try to wrap comments at N columns. +extern BoundedOption<unsigned, 0, 256> +cmt_width; + +// How to reflow comments. +// +// 0: No reflowing (apart from the line wrapping due to cmt_width) (default) +// 1: No touching at all +// 2: Full reflow (enable cmt_indent_multi for indent with line wrapping due to cmt_width) +extern BoundedOption<unsigned, 0, 2> +cmt_reflow_mode; + +// Path to a file that contains regular expressions describing patterns for +// which the end of one line and the beginning of the next will be folded into +// the same sentence or paragraph during full comment reflow. The regular +// expressions are described using ECMAScript syntax. The syntax for this +// specification is as follows, where "..." indicates the custom regular +// expression and "n" indicates the nth end_of_prev_line_regex and +// beg_of_next_line_regex regular expression pair: +// +// end_of_prev_line_regex[1] = "...$" +// beg_of_next_line_regex[1] = "^..." +// end_of_prev_line_regex[2] = "...$" +// beg_of_next_line_regex[2] = "^..." +// . +// . +// . +// end_of_prev_line_regex[n] = "...$" +// beg_of_next_line_regex[n] = "^..." +// +// Note that use of this option overrides the default reflow fold regular +// expressions, which are internally defined as follows: +// +// end_of_prev_line_regex[1] = "[\w,\]\)]$" +// beg_of_next_line_regex[1] = "^[\w,\[\(]" +// end_of_prev_line_regex[2] = "\.$" +// beg_of_next_line_regex[2] = "^[A-Z]" +extern Option<string> +cmt_reflow_fold_regex_file; + +// Whether to indent wrapped lines to the start of the encompassing paragraph +// during full comment reflow (cmt_reflow_mode = 2). Overrides the value +// specified by cmt_sp_after_star_cont. +// +// Note that cmt_align_doxygen_javadoc_tags overrides this option for +// paragraphs associated with javadoc tags +extern Option<bool> +cmt_reflow_indent_to_paragraph_start; + +// Whether to convert all tabs to spaces in comments. If false, tabs in +// comments are left alone, unless used for indenting. +extern Option<bool> +cmt_convert_tab_to_spaces; + +// TODO This description is confusing and should be revised. + +// Whether to apply changes to multi-line comments, including cmt_width, +// keyword substitution and leading chars. +extern Option<bool> +cmt_indent_multi; // = true + +// Whether to align doxygen javadoc-style tags ('@param', '@return', etc.) +// and corresponding fields such that groups of consecutive block tags, +// parameter names, and descriptions align with one another. Overrides that +// which is specified by the cmt_sp_after_star_cont. If cmt_width > 0, it may +// be necessary to enable cmt_indent_multi and set cmt_reflow_mode = 2 +// in order to achieve the desired alignment for line-wrapping. +extern Option<bool> +cmt_align_doxygen_javadoc_tags; + +// The number of spaces to insert after the star and before doxygen +// javadoc-style tags (@param, @return, etc). Requires enabling +// cmt_align_doxygen_javadoc_tags. Overrides that which is specified by the +// cmt_sp_after_star_cont. +extern BoundedOption<unsigned, 0, 16> +cmt_sp_before_doxygen_javadoc_tags; // = 1 + +// Whether to change trailing, single-line c-comments into cpp-comments. +extern Option<bool> +cmt_trailing_single_line_c_to_cpp; + +// Whether to group c-comments that look like they are in a block. +extern Option<bool> +cmt_c_group; + +// Whether to put an empty '/*' on the first line of the combined c-comment. +extern Option<bool> +cmt_c_nl_start; + +// Whether to add a newline before the closing '*/' of the combined c-comment. +extern Option<bool> +cmt_c_nl_end; + +// Whether to change cpp-comments into c-comments. +extern Option<bool> +cmt_cpp_to_c; + +// Whether to group cpp-comments that look like they are in a block. Only +// meaningful if cmt_cpp_to_c=true. +extern Option<bool> +cmt_cpp_group; + +// Whether to put an empty '/*' on the first line of the combined cpp-comment +// when converting to a c-comment. +// +// Requires cmt_cpp_to_c=true and cmt_cpp_group=true. +extern Option<bool> +cmt_cpp_nl_start; + +// Whether to add a newline before the closing '*/' of the combined cpp-comment +// when converting to a c-comment. +// +// Requires cmt_cpp_to_c=true and cmt_cpp_group=true. +extern Option<bool> +cmt_cpp_nl_end; + +// Whether to put a star on subsequent comment lines. +extern Option<bool> +cmt_star_cont; + +// The number of spaces to insert at the start of subsequent comment lines. +extern BoundedOption<unsigned, 0, 16> +cmt_sp_before_star_cont; + +// The number of spaces to insert after the star on subsequent comment lines. +extern BoundedOption<unsigned, 0, 16> +cmt_sp_after_star_cont; + +// TODO This description is confusing and should be revised. + +// For multi-line comments with a '*' lead, remove leading spaces if the first +// and last lines of the comment are the same length. +extern Option<bool> +cmt_multi_check_last; // = true + +// TODO This description is confusing and should be revised. + +// For multi-line comments with a '*' lead, remove leading spaces if the first +// and last lines of the comment are the same length AND if the length is +// bigger as the first_len minimum. +extern BoundedOption<unsigned, 1, 20> +cmt_multi_first_len_minimum; // = 4 + +// Path to a file that contains text to insert at the beginning of a file if +// the file doesn't start with a C/C++ comment. If the inserted text contains +// '$(filename)', that will be replaced with the current file's name. +extern Option<string> +cmt_insert_file_header; + +// Path to a file that contains text to insert at the end of a file if the +// file doesn't end with a C/C++ comment. If the inserted text contains +// '$(filename)', that will be replaced with the current file's name. +extern Option<string> +cmt_insert_file_footer; + +// Path to a file that contains text to insert before a function definition if +// the function isn't preceded by a C/C++ comment. If the inserted text +// contains '$(function)', '$(javaparam)' or '$(fclass)', these will be +// replaced with, respectively, the name of the function, the javadoc '@param' +// and '@return' stuff, or the name of the class to which the member function +// belongs. +extern Option<string> +cmt_insert_func_header; + +// Path to a file that contains text to insert before a class if the class +// isn't preceded by a C/C++ comment. If the inserted text contains '$(class)', +// that will be replaced with the class name. +extern Option<string> +cmt_insert_class_header; + +// Path to a file that contains text to insert before an Objective-C message +// specification, if the method isn't preceded by a C/C++ comment. If the +// inserted text contains '$(message)' or '$(javaparam)', these will be +// replaced with, respectively, the name of the function, or the javadoc +// '@param' and '@return' stuff. +extern Option<string> +cmt_insert_oc_msg_header; + +// TODO This description may be confusing; consider revising. + +// Whether a comment should be inserted if a preprocessor is encountered when +// stepping backwards from a function name. +// +// Applies to cmt_insert_oc_msg_header, cmt_insert_func_header and +// cmt_insert_class_header. +extern Option<bool> +cmt_insert_before_preproc; + +// Whether a comment should be inserted if a function is declared inline to a +// class definition. +// +// Applies to cmt_insert_func_header. +extern Option<bool> +cmt_insert_before_inlines; // = true + +// Whether a comment should be inserted if the function is a class constructor +// or destructor. +// +// Applies to cmt_insert_func_header. +extern Option<bool> +cmt_insert_before_ctor_dtor; + +//END + +/////////////////////////////////////////////////////////////////////////////// +//BEGIN Code modifying options (non-whitespace) + +// Add or remove braces on a single-line 'do' statement. +extern Option<iarf_e> +mod_full_brace_do; + +// Add or remove braces on a single-line 'for' statement. +extern Option<iarf_e> +mod_full_brace_for; + +// (Pawn) Add or remove braces on a single-line function definition. +extern Option<iarf_e> +mod_full_brace_function; + +// Add or remove braces on a single-line 'if' statement. Braces will not be +// removed if the braced statement contains an 'else'. +extern Option<iarf_e> +mod_full_brace_if; + +// Whether to enforce that all blocks of an 'if'/'else if'/'else' chain either +// have, or do not have, braces. Overrides mod_full_brace_if. +// +// 0: Don't override mod_full_brace_if +// 1: Add braces to all blocks if any block needs braces and remove braces if +// they can be removed from all blocks +// 2: Add braces to all blocks if any block already has braces, regardless of +// whether it needs them +// 3: Add braces to all blocks if any block needs braces and remove braces if +// they can be removed from all blocks, except if all blocks have braces +// despite none needing them +extern BoundedOption<unsigned, 0, 3> +mod_full_brace_if_chain; + +// Whether to add braces to all blocks of an 'if'/'else if'/'else' chain. +// If true, mod_full_brace_if_chain will only remove braces from an 'if' that +// does not have an 'else if' or 'else'. +extern Option<bool> +mod_full_brace_if_chain_only; + +// Add or remove braces on single-line 'while' statement. +extern Option<iarf_e> +mod_full_brace_while; + +// Add or remove braces on single-line 'using ()' statement. +extern Option<iarf_e> +mod_full_brace_using; + +// Don't remove braces around statements that span N newlines +extern BoundedOption<unsigned, 0, 5000> +mod_full_brace_nl; + +// Whether to prevent removal of braces from 'if'/'for'/'while'/etc. blocks +// which span multiple lines. +// +// Affects: +// mod_full_brace_for +// mod_full_brace_if +// mod_full_brace_if_chain +// mod_full_brace_if_chain_only +// mod_full_brace_while +// mod_full_brace_using +// +// Does not affect: +// mod_full_brace_do +// mod_full_brace_function +extern Option<bool> +mod_full_brace_nl_block_rem_mlcond; + +// Add or remove unnecessary parentheses on 'return' statement. +extern Option<iarf_e> +mod_paren_on_return; + +// Add or remove unnecessary parentheses on 'throw' statement. +extern Option<iarf_e> +mod_paren_on_throw; + +// (Pawn) Whether to change optional semicolons to real semicolons. +extern Option<bool> +mod_pawn_semicolon; + +// Whether to fully parenthesize Boolean expressions in 'while' and 'if' +// statement, as in 'if (a && b > c)' => 'if (a && (b > c))'. +extern Option<bool> +mod_full_paren_if_bool; + +// Whether to fully parenthesize Boolean expressions after '=' +// statement, as in 'x = a && b > c;' => 'x = (a && (b > c));'. +extern Option<bool> +mod_full_paren_assign_bool; + +// Whether to fully parenthesize Boolean expressions after '=' +// statement, as in 'return a && b > c;' => 'return (a && (b > c));'. +extern Option<bool> +mod_full_paren_return_bool; + +// Whether to remove superfluous semicolons. +extern Option<bool> +mod_remove_extra_semicolon; + +// Whether to remove duplicate include. +extern Option<bool> +mod_remove_duplicate_include; + +// If a function body exceeds the specified number of newlines and doesn't have +// a comment after the close brace, a comment will be added. +extern BoundedOption<unsigned, 0, 255> +mod_add_long_function_closebrace_comment; + +// If a namespace body exceeds the specified number of newlines and doesn't +// have a comment after the close brace, a comment will be added. +extern BoundedOption<unsigned, 0, 255> +mod_add_long_namespace_closebrace_comment; + +// If a class body exceeds the specified number of newlines and doesn't have a +// comment after the close brace, a comment will be added. +extern BoundedOption<unsigned, 0, 255> +mod_add_long_class_closebrace_comment; + +// If a switch body exceeds the specified number of newlines and doesn't have a +// comment after the close brace, a comment will be added. +extern BoundedOption<unsigned, 0, 255> +mod_add_long_switch_closebrace_comment; + +// If an #ifdef body exceeds the specified number of newlines and doesn't have +// a comment after the #endif, a comment will be added. +extern BoundedOption<unsigned, 0, 255> +mod_add_long_ifdef_endif_comment; + +// If an #ifdef or #else body exceeds the specified number of newlines and +// doesn't have a comment after the #else, a comment will be added. +extern BoundedOption<unsigned, 0, 255> +mod_add_long_ifdef_else_comment; + +// Whether to take care of the case by the mod_sort_xx options. +extern Option<bool> +mod_sort_case_sensitive; + +// Whether to sort consecutive single-line 'import' statements. +extern Option<bool> +mod_sort_import; + +// (C#) Whether to sort consecutive single-line 'using' statements. +extern Option<bool> +mod_sort_using; + +// Whether to sort consecutive single-line '#include' statements (C/C++) and +// '#import' statements (Objective-C). Be aware that this has the potential to +// break your code if your includes/imports have ordering dependencies. +extern Option<bool> +mod_sort_include; + +// Whether to prioritize '#include' and '#import' statements that contain +// filename without extension when sorting is enabled. +extern Option<bool> +mod_sort_incl_import_prioritize_filename; + +// Whether to prioritize '#include' and '#import' statements that does not +// contain extensions when sorting is enabled. +extern Option<bool> +mod_sort_incl_import_prioritize_extensionless; + +// Whether to prioritize '#include' and '#import' statements that contain +// angle over quotes when sorting is enabled. +extern Option<bool> +mod_sort_incl_import_prioritize_angle_over_quotes; + +// Whether to ignore file extension in '#include' and '#import' statements +// for sorting comparison. +extern Option<bool> +mod_sort_incl_import_ignore_extension; + +// Whether to group '#include' and '#import' statements when sorting is enabled. +extern Option<bool> +mod_sort_incl_import_grouping_enabled; + +// Whether to move a 'break' that appears after a fully braced 'case' before +// the close brace, as in 'case X: { ... } break;' => 'case X: { ... break; }'. +extern Option<bool> +mod_move_case_break; + +// Whether to move a 'return' that appears after a fully braced 'case' before +// the close brace, as in 'case X: { ... } return;' => 'case X: { ... return; }'. +extern Option<bool> +mod_move_case_return; + +// Add or remove braces around a fully braced case statement. Will only remove +// braces if there are no variable declarations in the block. +extern Option<iarf_e> +mod_case_brace; + +// Whether to remove a void 'return;' that appears as the last statement in a +// function. +extern Option<bool> +mod_remove_empty_return; + +// Add or remove the comma after the last value of an enumeration. +extern Option<iarf_e> +mod_enum_last_comma; + +// Syntax to use for infinite loops. +// +// 0: Leave syntax alone (default) +// 1: Rewrite as `for(;;)` +// 2: Rewrite as `while(true)` +// 3: Rewrite as `do`...`while(true);` +// 4: Rewrite as `while(1)` +// 5: Rewrite as `do`...`while(1);` +// +// Infinite loops that do not already match one of these syntaxes are ignored. +// Other options that affect loop formatting will be applied after transforming +// the syntax. +extern BoundedOption<unsigned, 0, 5> +mod_infinite_loop; + +// Add or remove the 'int' keyword in 'int short'. +extern Option<iarf_e> +mod_int_short; + +// Add or remove the 'int' keyword in 'short int'. +extern Option<iarf_e> +mod_short_int; + +// Add or remove the 'int' keyword in 'int long'. +extern Option<iarf_e> +mod_int_long; + +// Add or remove the 'int' keyword in 'long int'. +extern Option<iarf_e> +mod_long_int; + +// Add or remove the 'int' keyword in 'int signed'. +extern Option<iarf_e> +mod_int_signed; + +// Add or remove the 'int' keyword in 'signed int'. +extern Option<iarf_e> +mod_signed_int; + +// Add or remove the 'int' keyword in 'int unsigned'. +extern Option<iarf_e> +mod_int_unsigned; + +// Add or remove the 'int' keyword in 'unsigned int'. +extern Option<iarf_e> +mod_unsigned_int; + +// If there is a situation where mod_int_* and mod_*_int would result in +// multiple int keywords, whether to keep the rightmost int (the default) or the +// leftmost int. +extern Option<bool> +mod_int_prefer_int_on_left; + +// (OC) Whether to organize the properties. If true, properties will be +// rearranged according to the mod_sort_oc_property_*_weight factors. +extern Option<bool> +mod_sort_oc_properties; + +// (OC) Weight of a class property modifier. +extern Option<signed> +mod_sort_oc_property_class_weight; + +// (OC) Weight of 'atomic' and 'nonatomic'. +extern Option<signed> +mod_sort_oc_property_thread_safe_weight; + +// (OC) Weight of 'readwrite' when organizing properties. +extern Option<signed> +mod_sort_oc_property_readwrite_weight; + +// (OC) Weight of a reference type specifier ('retain', 'copy', 'assign', +// 'weak', 'strong') when organizing properties. +extern Option<signed> +mod_sort_oc_property_reference_weight; + +// (OC) Weight of getter type ('getter=') when organizing properties. +extern Option<signed> +mod_sort_oc_property_getter_weight; + +// (OC) Weight of setter type ('setter=') when organizing properties. +extern Option<signed> +mod_sort_oc_property_setter_weight; + +// (OC) Weight of nullability type ('nullable', 'nonnull', 'null_unspecified', +// 'null_resettable') when organizing properties. +extern Option<signed> +mod_sort_oc_property_nullability_weight; + +//END + +/////////////////////////////////////////////////////////////////////////////// +//BEGIN Preprocessor options + +// How to use tabs when indenting preprocessor code. +// +// -1: Use 'indent_with_tabs' setting (default) +// 0: Spaces only +// 1: Indent with tabs to brace level, align with spaces +// 2: Indent and align with tabs, using spaces when not on a tabstop +extern BoundedOption<signed, -1, 2> +pp_indent_with_tabs; // = -1 + +// Add or remove indentation of preprocessor directives inside #if blocks +// at brace level 0 (file-level). +extern Option<iarf_e> +pp_indent; + +// Whether to indent #if/#else/#endif at the brace level. If false, these are +// indented from column 1. +extern Option<bool> +pp_indent_at_level; + +// Whether to indent #if/#else/#endif at the parenthesis level if the brace +// level is 0. If false, these are indented from column 1. +extern Option<bool> +pp_indent_at_level0; + +// Specifies the number of columns to indent preprocessors per level +// at brace level 0 (file-level). If pp_indent_at_level=false, also specifies +// the number of columns to indent preprocessors per level +// at brace level > 0 (function-level). +extern BoundedOption<unsigned, 0, 16> +pp_indent_count; // = 1 + +// Add or remove space after # based on pp level of #if blocks. +extern Option<iarf_e> +pp_space_after; + +// Sets the number of spaces per level added with pp_space_after. +extern BoundedOption<unsigned, 0, 16> +pp_space_count; + +// The indent for '#region' and '#endregion' in C# and '#pragma region' in +// C/C++. Negative values decrease indent down to the first column. +extern BoundedOption<signed, -16, 16> +pp_indent_region; + +// Whether to indent the code between #region and #endregion. +extern Option<bool> +pp_region_indent_code; + +// If pp_indent_at_level=true, sets the indent for #if, #else and #endif when +// not at file-level. Negative values decrease indent down to the first column. +// +// =0: Indent preprocessors using output_tab_size +// >0: Column at which all preprocessors will be indented +extern BoundedOption<signed, -16, 16> +pp_indent_if; + +// Whether to indent the code between #if, #else and #endif. +extern Option<bool> +pp_if_indent_code; + +// Whether to indent the body of an #if that encompasses all the code in the file. +extern Option<bool> +pp_indent_in_guard; + +// Whether to indent '#define' at the brace level. If false, these are +// indented from column 1. +extern Option<bool> +pp_define_at_level; + +// Whether to indent '#include' at the brace level. +extern Option<bool> +pp_include_at_level; + +// Whether to ignore the '#define' body while formatting. +extern Option<bool> +pp_ignore_define_body; + +// An offset value that controls the indentation of the body of a multiline #define. +// 'body' refers to all the lines of a multiline #define except the first line. +// Requires 'pp_ignore_define_body = false'. +// +// <0: Absolute column: the body indentation starts off at the specified column +// (ex. -3 ==> the body is indented starting from column 3) +// >=0: Relative to the column of the '#' of '#define' +// (ex. 3 ==> the body is indented starting 3 columns at the right of '#') +extern BoundedOption<signed, -32, 32> +pp_multiline_define_body_indent; // = 8 + +// TODO The following descriptions are confusing and suffer from sub-optimal +// grammar, and should be revised; from here... + +// Whether to indent case statements between #if, #else, and #endif. +// Only applies to the indent of the preprocessor that the case statements +// directly inside of. +extern Option<bool> +pp_indent_case; // = true + +// Whether to indent whole function definitions between #if, #else, and #endif. +// Only applies to the indent of the preprocessor that the function definition +// is directly inside of. +extern Option<bool> +pp_indent_func_def; // = true + +// Whether to indent extern C blocks between #if, #else, and #endif. +// Only applies to the indent of the preprocessor that the extern block is +// directly inside of. +extern Option<bool> +pp_indent_extern; // = true + +// How to indent braces directly inside #if, #else, and #endif. +// Requires pp_if_indent_code=true and only applies to the indent of the +// preprocessor that the braces are directly inside of. +// 0: No extra indent +// 1: Indent by one level +// -1: Preserve original indentation +extern BoundedOption<signed, -1, 1> +pp_indent_brace; // = 1 + +// Whether to print warning messages for unbalanced #if and #else blocks. +// This will print a message in the following cases: +// - if an #ifdef block ends on a different indent level than +// where it started from. Example: +// +// #ifdef TEST +// int i; +// { +// int j; +// #endif +// +// - an #elif/#else block ends on a different indent level than +// the corresponding #ifdef block. Example: +// +// #ifdef TEST +// int i; +// #else +// } +// int j; +// #endif +extern Option<bool> +pp_warn_unbalanced_if; // = false + +// TODO ...until here. + +//END + +/////////////////////////////////////////////////////////////////////////////// +//BEGIN Sort includes options + +// The regex for include category with priority 0. +extern Option<string> +include_category_0; + +// The regex for include category with priority 1. +extern Option<string> +include_category_1; + +// The regex for include category with priority 2. +extern Option<string> +include_category_2; + +//END + +/////////////////////////////////////////////////////////////////////////////// +//BEGIN Use or Do not Use options + +// true: indent_func_call_param will be used (default) +// false: indent_func_call_param will NOT be used +extern Option<bool> +use_indent_func_call_param; // = true + +// The value of the indentation for a continuation line is calculated +// differently if the statement is: +// - a declaration: your case with QString fileName ... +// - an assignment: your case with pSettings = new QSettings( ... +// +// At the second case the indentation value might be used twice: +// - at the assignment +// - at the function call (if present) +// +// To prevent the double use of the indentation value, use this option with the +// value 'true'. +// +// true: indent_continue will be used only once +// false: indent_continue will be used every time (default) +// +// Requires indent_ignore_first_continue=false. +extern Option<bool> +use_indent_continue_only_once; + +// The indentation can be: +// - after the assignment, at the '[' character +// - at the beginning of the lambda body +// +// true: indentation will be at the beginning of the lambda body +// false: indentation will be after the assignment (default) +extern Option<bool> +indent_cpp_lambda_only_once; + +// Whether sp_after_angle takes precedence over sp_inside_fparen. This was the +// historic behavior, but is probably not the desired behavior, so this is off +// by default. +extern Option<bool> +use_sp_after_angle_always; + +// Whether to apply special formatting for Qt SIGNAL/SLOT macros. Essentially, +// this tries to format these so that they match Qt's normalized form (i.e. the +// result of QMetaObject::normalizedSignature), which can slightly improve the +// performance of the QObject::connect call, rather than how they would +// otherwise be formatted. +// +// See options_for_QT.cpp for details. +extern Option<bool> +use_options_overriding_for_qt_macros; // = true + +// If true: the form feed character is removed from the list of whitespace +// characters. See https://en.cppreference.com/w/cpp/string/byte/isspace. +extern Option<bool> +use_form_feed_no_more_as_whitespace_character; + +//END + +/////////////////////////////////////////////////////////////////////////////// +//BEGIN Warn levels - 1: error, 2: warning (default), 3: note + +// (C#) Warning is given if doing tab-to-\t replacement and we have found one +// in a C# verbatim string literal. +extern BoundedOption<unsigned, 1, 3> +warn_level_tabs_found_in_verbatim_string_literals; // = LWARN + +// For debugging purpose only. + +// Limit the number of loops. +// Used by uncrustify.cpp to exit from infinite loop. +// 0: no limit. +extern Option<signed> +debug_max_number_of_loops; + +// Set the number of the line to protocol; +// Used in the function prot_the_line if the 2. parameter is zero. +// 0: nothing protocol. +extern Option<signed> +debug_line_number_to_protocol; + +// Set the number of second(s) before terminating formatting the current file, +// 0: no timeout. +// only for linux +extern Option<signed> +debug_timeout; + +// Set the number of characters to be printed if the text is too long, +// 0: do not truncate. +extern BoundedOption<unsigned, 0, 960> +debug_truncate; + +// sort (or not) the tracking info. +extern Option<bool> +debug_sort_the_tracks; // = true + +// decode (or not) the flags as a new line. +// only if the -p option is set. +extern Option<bool> +debug_decode_the_flags; + +// insert the number of the line at the beginning of each line +extern Option<bool> +set_numbering_for_html_output; + +//END + +} // namespace options + +} // namespace uncrustify + +#endif /* OPTIONS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/options_for_QT.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/options_for_QT.cpp new file mode 100644 index 00000000..c0a178f0 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/options_for_QT.cpp @@ -0,0 +1,126 @@ +/** + * @file options_for_QT.cpp + * Save the options which are needed to be changed to + * process the SIGNAL and SLOT QT macros. + * http://doc.qt.io/qt-4.8/qtglobal.html + * + * @author Guy Maurel since version 0.62 for uncrustify4Qt + * October 2015, 2016 + * @license GPL v2+ + */ + +#include "options_for_QT.h" + +#include "log_rules.h" + +constexpr static auto LCURRENT = LQT; + +using namespace uncrustify; + +// for the modification of options within the SIGNAL/SLOT call. +bool QT_SIGNAL_SLOT_found = false; +size_t QT_SIGNAL_SLOT_level = 0; +bool restoreValues = false; + +namespace +{ + +//----------------------------------------------------------------------------- +class temporary_iarf_option +{ +public: + temporary_iarf_option(Option<iarf_e> *option, + iarf_e override_value = IARF_REMOVE) + : m_option{option} + , m_override_value{override_value} + {} + + void save_and_override(); + void restore(); + +private: + Option<iarf_e> *m_option; + const iarf_e m_override_value; + + iarf_e m_saved_value = IARF_NOT_DEFINED; +}; + + +//----------------------------------------------------------------------------- +void temporary_iarf_option::save_and_override() +{ + m_saved_value = (*m_option)(); + (*m_option) = m_override_value; +} + + +//----------------------------------------------------------------------------- +void temporary_iarf_option::restore() +{ + (*m_option) = m_saved_value; + m_saved_value = IARF_NOT_DEFINED; +} + +//----------------------------------------------------------------------------- +temporary_iarf_option for_qt_options[] = +{ + { &options::sp_inside_fparen }, +// Issue #481 +// connect( timer,SIGNAL( timeout() ),this,SLOT( timeoutImage() ) ); + { &options::sp_inside_fparens }, + { &options::sp_paren_paren }, + { &options::sp_before_comma }, + { &options::sp_after_comma }, +// Bug #654 +// connect(&mapper, SIGNAL(mapped(QString &)), this, SLOT(onSomeEvent(QString &))); + { &options::sp_before_byref }, + { &options::sp_before_unnamed_byref }, + { &options::sp_after_type }, +// Issue #1969 +// connect( a, SIGNAL(b(c *)), this, SLOT(d(e *)) ); + { &options::sp_before_ptr_star }, + { &options::sp_before_unnamed_ptr_star }, +// connect( a, SIGNAL(b(c< d >)), this, SLOT(e(f< g >)) ); + { &options::sp_inside_angle }, +}; + +} // anonymous namespace + + +//----------------------------------------------------------------------------- +void save_set_options_for_QT(size_t level) +{ + log_rule_B("use_options_overriding_for_qt_macros"); + assert(options::use_options_overriding_for_qt_macros()); + + LOG_FMT(LGUY, "save values, level=%zu\n", level); + // save the values + QT_SIGNAL_SLOT_level = level; + + for (auto &opt : for_qt_options) + { + opt.save_and_override(); + } + + QT_SIGNAL_SLOT_found = true; +} + + +//----------------------------------------------------------------------------- +void restore_options_for_QT() +{ + log_rule_B("use_options_overriding_for_qt_macros"); + assert(options::use_options_overriding_for_qt_macros()); + + LOG_FMT(LGUY, "restore values\n"); + // restore the values we had before SIGNAL/SLOT + QT_SIGNAL_SLOT_level = 0; + + for (auto &opt : for_qt_options) + { + opt.restore(); + } + + QT_SIGNAL_SLOT_found = false; + restoreValues = false; +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/options_for_QT.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/options_for_QT.h new file mode 100644 index 00000000..1b8bfccf --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/options_for_QT.h @@ -0,0 +1,29 @@ +/** + * @file options_for_QT.h + * Save the options which are needed to be changed to + * process the SIGNAL and SLOT QT macros. + * http://doc.qt.io/qt-4.8/qtglobal.html + * + * @author Guy Maurel since version 0.62 for uncrustify4Qt + * January 2016 + * @license GPL v2+ + */ + +#ifndef OPTIONS_FOR_QT_H_INCLUDED +#define OPTIONS_FOR_QT_H_INCLUDED + +#include "uncrustify_types.h" + +// TODO can we avoid those extern variables? +extern bool QT_SIGNAL_SLOT_found; +extern size_t QT_SIGNAL_SLOT_level; +extern bool restoreValues; + + +void save_set_options_for_QT(size_t level); + + +void restore_options_for_QT(); + + +#endif /* OPTIONS_FOR_QT_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/output.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/output.cpp new file mode 100644 index 00000000..0914d107 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/output.cpp @@ -0,0 +1,3597 @@ +/** + * @file output.cpp + * Does all the output & comment formatting. + * + * @author Ben Gardner + * @author Guy Maurel October 2015, 2021 + * @license GPL v2+ + */ + +#include "output.h" + +#include "align_tab_column.h" +#include "braces.h" +#include "indent.h" +#include "prototypes.h" +#include "tokenize.h" +#include "unc_ctype.h" +#include "unicode.h" + +#include <ctime> +#include <map> +#include <regex> +#include <set> + +// if you need more logs, commented out the next define line +#define EXTRA_LOG + +constexpr static auto LCURRENT = LOUTPUT; + +using namespace uncrustify; + + +struct cmt_reflow +{ + Chunk *pc = nullptr; + size_t column = 0; //! Column of the comment start + size_t brace_col = 0; //! Brace column (for indenting with tabs) + size_t base_col = 0; //! Base column (for indenting with tabs) + size_t word_count = 0; //! number of words on this line + size_t xtra_indent = 0; //! extra indent of non-first lines (0 or 1) + unc_text cont_text; //! fixed text to output at the start of a line (0 to 3 chars) + bool reflow = false; //! reflow the current line +}; + + +// for tracking line numbering +bool numbering_status = false; +int line_number; +char char_number[16] = { 0 }; + + +void set_numbering(bool status) +{ + if (options::set_numbering_for_html_output()) + { + numbering_status = status; + } +} + + +bool get_numbering() +{ + return(numbering_status); +} + + +void set_line_number() +{ + line_number = 0; +} + + +void print_numbering() +{ + if (get_numbering()) + { + line_number++; + sprintf(char_number, "%d ", line_number); + write_string(char_number); + } +} + + +/** + * A multiline comment + * The only trick here is that we have to trim out whitespace characters + * to get the comment to line up. + */ +static void output_comment_multi(Chunk *pc); + + +static bool kw_fcn_filename(Chunk *cmt, unc_text &out_txt); + + +static bool kw_fcn_class(Chunk *cmt, unc_text &out_txt); + + +static bool kw_fcn_message(Chunk *cmt, unc_text &out_txt); + + +static bool kw_fcn_category(Chunk *cmt, unc_text &out_txt); + + +static bool kw_fcn_scope(Chunk *cmt, unc_text &out_txt); + + +static bool kw_fcn_function(Chunk *cmt, unc_text &out_txt); + + +/** + * Adds the javadoc-style @param and @return stuff, based on the params and + * return value for pc. + * If the arg list is '()' or '(void)', then no @params are added. + * Likewise, if the return value is 'void', then no @return is added. + */ +static bool kw_fcn_javaparam(Chunk *cmt, unc_text &out_txt); + + +static bool kw_fcn_fclass(Chunk *cmt, unc_text &out_txt); + + +static bool kw_fcn_year(Chunk *cmt, unc_text &out_txt); + + +/** + * Output a multiline comment without any reformatting other than shifting + * it left or right to get the column right. + * + * Trims trailing whitespaces. + */ +static void output_comment_multi_simple(Chunk *pc); + + +/** + * This renders the #if condition to a string buffer. + * + * @param[out] dst unc_text buffer to be filled + * @param[in] ifdef if conditional as chunk list + */ +static void generate_if_conditional_as_text(unc_text &dst, Chunk *ifdef); + + +/** + * Do keyword substitution on a comment. + * NOTE: it is assumed that a comment will contain at most one of each type + * of keyword. + */ +static void do_kw_subst(Chunk *pc); + + +//! All output text is sent here, one char at a time. +static void add_char(UINT32 ch, bool is_literal = false); + + +static void add_text(const char *ascii_text); + + +static void add_text(const unc_text &text, bool is_ignored, bool is_literal); + + +/** + * Count the number of characters to the end of the next chunk of text. + * If it exceeds the limit, return true. + */ +static bool next_word_exceeds_limit(const unc_text &text, size_t idx); + + +/** + * Output a comment to the column using indent_with_tabs and + * indent_cmt_with_tabs as the rules. + * base_col is the indent of the first line of the comment. + * On the first line, column == base_col. + * On subsequent lines, column >= base_col. + * + * @param brace_col the brace-level indent of the comment + * @param base_col the indent of the start of the comment (multiline) + * @param column the column that we should end up in + */ +static void cmt_output_indent(size_t brace_col, size_t base_col, size_t column); + + +/** + * Checks for and updates the lead chars. + * + * @param line the comment line + * + * @return 0: not present, >0: number of chars that are part of the lead + */ +static size_t cmt_parse_lead(const unc_text &line, bool is_last); + + +/** + * Scans a multiline comment to determine the following: + * - the extra indent of the non-first line (0 or 1) + * - the continuation text ('' or '* ') + * + * The decision is based on: + * - cmt_indent_multi + * - cmt_star_cont + * - cmt_multi_first_len_minimum + * - the first line length + * - the second line leader length + * - the last line length (without leading space/tab) + * + * If the first and last line are the same length and don't contain any alnum + * chars and (the first line len > 2 or the second leader is the same as the + * first line length), then the indent is 0. + * + * If the leader on the second line is 1 wide or missing, then the indent is 1. + * + * Otherwise, the indent is 0. + * + * @param str The comment string + * @param len Length of the comment + * @param start_col Starting column + * + * @return cmt.xtra_indent is set to 0 or 1 + */ +static void calculate_comment_body_indent(cmt_reflow &cmt, const unc_text &str); + + +static int next_up(const unc_text &text, size_t idx, const unc_text &tag); + + +/** + * Outputs the C comment at pc. + * C comment combining is done here + * + * @return the last chunk output'd + */ +static Chunk *output_comment_c(Chunk *pc); + + +/** + * Outputs the CPP comment at pc. + * CPP comment combining is done here + * + * @return the last chunk output'd + */ +static Chunk *output_comment_cpp(Chunk *pc); + + +static void cmt_trim_whitespace(unc_text &line, bool in_preproc); + + +/** + * Outputs a comment. The initial opening '//' may be included in the text. + * Subsequent openings (if combining comments), should not be included. + * The closing (for C/D comments) should not be included. + * + * TODO: + * If reflowing text, the comment should be added one word (or line) at a time. + * A newline should only be sent if a blank line is encountered or if the next + * line is indented beyond the current line (optional?). + * If the last char on a line is a ':' or '.', then the next line won't be + * combined. + */ +static void add_comment_text(const unc_text &text, cmt_reflow &cmt, bool esc_close, size_t continuation_indent = 0); + + +static void output_cmt_start(cmt_reflow &cmt, Chunk *pc); + + +/** + * Checks to see if the current comment can be combined with the next comment. + * The two can be combined if: + * 1. They are the same type + * 2. There is exactly one newline between then + * 3. They are indented to the same level + */ +static bool can_combine_comment(Chunk *pc, cmt_reflow &cmt); + + +#define LOG_CONTTEXT() \ + LOG_FMT(LCONTTEXT, "%s(%d): set cont_text to '%s'\n", __func__, __LINE__, cmt.cont_text.c_str()) + + +static void add_spaces() +{ + while (cpd.spaces > 0) + { + write_char(' '); + cpd.spaces--; + } +} + + +static void add_char(UINT32 ch, bool is_literal) +{ + // If we did a '\r' and it isn't followed by a '\n', then output a newline + if ( (cpd.last_char == '\r') + && (ch != '\n')) + { + write_string(cpd.newline); + cpd.column = 1; + cpd.did_newline = true; + cpd.spaces = 0; + } + + // convert a newline into the LF/CRLF/CR sequence + if (ch == '\n') + { + add_spaces(); + write_string(cpd.newline); + cpd.column = 1; + cpd.did_newline = true; + cpd.spaces = 0; + print_numbering(); + } + else if (ch == '\r') // do not output the CARRIAGERETURN + { + // do not output '\r' + cpd.column = 1; + cpd.did_newline = true; + cpd.spaces = 0; + } + else if ( (ch == '\t') + && cpd.output_tab_as_space) + { + size_t endcol = next_tab_column(cpd.column); + + while (cpd.column < endcol) + { + add_char(' '); + } + return; + } + else + { + // explicitly disallow a tab after a space + if ( !is_literal + && ch == '\t' + && cpd.last_char == ' ') + { + log_rule_B("indent_with_tabs"); + + int indent_with_tabs = options::pp_indent_with_tabs(); + + if ( cpd.in_preproc != CT_PREPROC + || indent_with_tabs == -1) + { + indent_with_tabs = options::indent_with_tabs(); + } + + if (indent_with_tabs == 0) + { + size_t endcol = next_tab_column(cpd.column); + + while (cpd.column < endcol) + { + add_char(' '); + } + return; + } + } + + if ( (ch == ' ') + && !cpd.output_trailspace) + { + cpd.spaces++; + cpd.column++; + } + else + { + add_spaces(); + write_char(ch); + + if (ch == '\t') + { + cpd.column = next_tab_column(cpd.column); + } + else + { + cpd.column++; + } + } + } + cpd.last_char = ch; +} // add_char + + +static void add_text(const char *ascii_text) +{ + char ch; + + while ((ch = *ascii_text) != 0) + { + ascii_text++; + add_char(ch); + } +} + + +static void add_text(const unc_text &text, bool is_ignored = false, bool is_literal = false) +{ + for (size_t idx = 0; idx < text.size(); idx++) + { + int ch = text[idx]; + + if (is_ignored) + { + write_char(ch); + } + else + { + add_char(ch, is_literal); + } + } +} + + +static bool next_word_exceeds_limit(const unc_text &text, size_t idx) +{ + LOG_FMT(LCONTTEXT, "%s(%d): idx is %zu\n", + __func__, __LINE__, idx); + size_t length = 0; + + // Count any whitespace + while ( (idx < text.size()) + && unc_isspace(text[idx])) + { + idx++; + length++; + } + + // Count non-whitespace + while ( (idx < text.size()) + && !unc_isspace(text[idx])) + { + idx++; + length++; + } + return((cpd.column + length - 1) > options::cmt_width()); +} + + +/** + * Advance to a specific column + * cpd.column is the current column + * + * @param column The column to advance to + */ +static void output_to_column(size_t column, bool allow_tabs) +{ + cpd.did_newline = false; + + if (allow_tabs) + { + // tab out as far as possible and then use spaces + size_t next_column = next_tab_column(cpd.column); + + while (next_column <= column) + { + add_text("\t"); + next_column = next_tab_column(cpd.column); + } + } + + // space out the final bit + while (cpd.column < column) + { + add_text(" "); + } +} + + +static void cmt_output_indent(size_t brace_col, size_t base_col, size_t column) +{ + log_rule_B("indent_cmt_with_tabs"); + size_t iwt = options::indent_cmt_with_tabs() ? 2 : + (options::indent_with_tabs() ? 1 : 0); + + size_t tab_col = (iwt == 0) ? 0 : ((iwt == 1) ? brace_col : base_col); + + // LOG_FMT(LSYS, "%s(brace=%zd base=%zd col=%zd iwt=%zd) tab=%zd cur=%zd\n", + // __func__, brace_col, base_col, column, iwt, tab_col, cpd.column); + + cpd.did_newline = false; + + if ( iwt == 2 + || ( cpd.column == 1 + && iwt == 1)) + { + // tab out as far as possible and then use spaces + while (next_tab_column(cpd.column) <= tab_col) + { + add_text("\t"); + } + } + + // space out the rest + while (cpd.column < column) + { + add_text(" "); + } +} // cmt_output_indent + + +void output_parsed(FILE *pfile, bool withOptions) +{ + const char *eol_marker = get_eol_marker(); + + if (withOptions) + { + save_option_file(pfile, false, true); + } + fprintf(pfile, "# -=====-%s", eol_marker); + fprintf(pfile, "# number of loops = %d\n", cpd.changes); + fprintf(pfile, "# -=====-%s", eol_marker); + fprintf(pfile, "# language = %s\n", language_name_from_flags(cpd.lang_flags)); + fprintf(pfile, "# -=====-%s", eol_marker); + // MAXLENGTHOFTHENAME must be consider at the format line at the file + // output.cpp, line 427: fprintf(pfile, "# Line Tag Parent... + // and 430: ... fprintf(pfile, "%s# %3zu>%19.19s[%19.19s] ... + // here xx xx xx xx +#ifdef WIN32 + fprintf(pfile, "# Line Tag Parent_type Type of the parent Columns Br/Lvl/pp Nl Text"); +#else // not WIN32 + fprintf(pfile, "# Line Tag Parent_type Type of the parent Columns Br/Lvl/pp Flags Nl Text"); +#endif // ifdef WIN32 + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { +#ifdef WIN32 + fprintf(pfile, "%s# %3d>%19.19s|%19.19s|%19.19s[%3d/%3d/%3d/%3d][%d/%d/%d][%d-%d]", + eol_marker, (int)pc->GetOrigLine(), get_token_name(pc->GetType()), + get_token_name(pc->GetParentType()), get_token_name(pc->GetTypeOfParent()), + (int)pc->GetColumn(), (int)pc->GetOrigCol(), (int)pc->GetOrigColEnd(), (int)pc->GetOrigPrevSp(), + (int)pc->GetBraceLevel(), (int)pc->GetLevel(), (int)pc->GetPpLevel(), (int)pc->GetNlCount(), pc->GetAfterTab()); +#else // not WIN32 + fprintf(pfile, "%s# %3zu>%19.19s|%19.19s|%19.19s[%3zu/%3zu/%3zu/%3zu][%zu/%zu/%zu]", + eol_marker, pc->GetOrigLine(), get_token_name(pc->GetType()), + get_token_name(pc->GetParentType()), get_token_name(pc->GetTypeOfParent()), + pc->GetColumn(), pc->GetOrigCol(), pc->GetOrigColEnd(), pc->GetOrigPrevSp(), + pc->GetBraceLevel(), pc->GetLevel(), pc->GetPpLevel()); + // Print pc flags in groups of 4 hex characters + char flag_string[24]; + sprintf(flag_string, "%16llx", static_cast<T_PcfFlags::int_t>(pc->GetFlags())); + fprintf(pfile, "[%.4s %.4s %.4s %.4s]", flag_string, flag_string + 4, flag_string + 8, flag_string + 12); + fprintf(pfile, "[%zu-%d]", + pc->GetNlCount(), pc->GetAfterTab()); +#endif // ifdef WIN32 + + if ( pc->IsNot(CT_NEWLINE) + && (pc->Len() != 0)) + { + for (size_t cnt = 0; cnt < pc->GetColumn(); cnt++) + { + fprintf(pfile, " "); + } + + if (pc->IsNot(CT_NL_CONT)) + { + fprintf(pfile, "%s", pc->Text()); + } + else + { + fprintf(pfile, "\\"); + } + } + + if (options::debug_decode_the_flags()) + { + // such as: + // The flags are: [0xc0400:IN_CLASS,STMT_START,EXPR_START] + fprintf(pfile, "%s The flags are: ", eol_marker); + fprintf(pfile, "%s", pcf_flags_str(pc->GetFlags()).c_str()); + } + } + + fprintf(pfile, "%s# -=====-%s", eol_marker, eol_marker); + fflush(pfile); +} // output_parsed + + +void output_parsed_csv(FILE *pfile) +{ + const char *eol_marker = get_eol_marker(); + + fprintf(pfile, "number of loops,%d,\n", cpd.changes); + fprintf(pfile, "language,%s,\n", language_name_from_flags(cpd.lang_flags)); + fprintf(pfile, "Line,Tag,Parent_type,Type of the parent,Column,Orig Col Strt," + "Orig Col End,Orig Sp Before,Br,Lvl,pp,Flags,Nl Before,Nl After,Text,"); + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + fprintf(pfile, "%s%zu,%s,%s,%s,%zu,%zu,%zu,%zu,%zu,%zu,%zu,", + eol_marker, pc->GetOrigLine(), get_token_name(pc->GetType()), + get_token_name(pc->GetParentType()), get_token_name(pc->GetTypeOfParent()), + pc->GetColumn(), pc->GetOrigCol(), pc->GetOrigColEnd(), pc->GetOrigPrevSp(), + pc->GetBraceLevel(), pc->GetLevel(), pc->GetPpLevel()); + + auto pcf_flag_str = pcf_flags_str(E_PcfFlag(pc->GetFlags())); +#ifdef WIN32 + auto pcf_flag_str_start = pcf_flag_str.find("[") + 1; +#else // not WIN32 + auto pcf_flag_str_start = pcf_flag_str.find(":") + 1; +#endif // ifdef WIN32 + auto pcf_flag_str_end = pcf_flag_str.find("]"); + auto pcf_names = pcf_flag_str.substr(pcf_flag_str_start, + pcf_flag_str_end - pcf_flag_str_start); + fprintf(pfile, "\"%s\",", pcf_names.c_str()); + fprintf(pfile, "%zu,%d,", + pc->GetNlCount(), pc->GetAfterTab()); + + if ( pc->IsNot(CT_NEWLINE) + && (pc->Len() != 0)) + { + fprintf(pfile, "\""); + + for (size_t cnt = 0; cnt < pc->GetColumn(); cnt++) + { + fprintf(pfile, " "); + } + + if (pc->IsNot(CT_NL_CONT)) + { + for (auto *ch = pc->Text(); *ch != '\0'; ++ch) + { + fprintf(pfile, "%c", *ch); + + if (*ch == '"') + { + // need to escape the double-quote for csv-format + fprintf(pfile, "\""); + } + } + } + else + { + fprintf(pfile, "\\"); + } + fprintf(pfile, "\""); + } + } + + fflush(pfile); +} // output_parsed_csv + + +// Compares two tracks according to second in descending order. +bool compareTrack(Track_nr t1, Track_nr t2) +{ + char *t1s = t1.second; + char *t2s = t2.second; + int vergleich = strcmp(t2s, t1s); + bool int_vergleich = vergleich > 0; + + return(int_vergleich); +} + + +void output_text(FILE *pfile) +{ + bool tracking = cpd.html_type != tracking_type_e::TT_NONE; // special for debugging + + cpd.fout = pfile; + cpd.did_newline = true; + cpd.column = 1; + + if (cpd.bom) + { + write_bom(); + } + Chunk *pc; + + if (cpd.frag_cols > 0) + { + size_t indent = cpd.frag_cols - 1; + + // loop over the whole chunk list + for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + pc->SetColumn(pc->GetColumn() + indent); + pc->SetColumnIndent(pc->GetColumnIndent() + indent); + } + + cpd.frag_cols = 0; + } + + if (tracking) + { + set_numbering(false); + add_text("<html>\n"); + add_text("<head>\n"); + add_text(" <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/>\n"); + add_text(" <title>Uncrustify: where do the Spaces options work</title>\n"); + add_text("</head>\n"); + add_text("<body lang=\"en-US\">\n"); + add_text("<p>\n"); + add_text("</p>\n"); + add_text("<pre>\n"); + set_numbering(true); + set_line_number(); + print_numbering(); + } + bool write_in_tracking = false; + int pp_indent_with_tabs = options::pp_indent_with_tabs(); + + if (pp_indent_with_tabs == -1) + { + pp_indent_with_tabs = options::indent_with_tabs(); + } + + // loop over the whole chunk list + for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + char copy[1000]; + LOG_FMT(LCONTTEXT, "%s(%d): Text() is '%s', type is %s, orig line is %zu, column is %zu, nl is %zu\n", + __func__, __LINE__, pc->ElidedText(copy), get_token_name(pc->GetType()), pc->GetOrigLine(), pc->GetColumn(), pc->GetNlCount()); + cpd.output_tab_as_space = false; + + if (pc->Is(CT_NEWLINE)) + { + for (size_t cnt = 0; cnt < pc->GetNlCount(); cnt++) + { + if ( cnt > 0 + && pc->GetNlColumn() > 1) + { + log_rule_B("indent_with_tabs - newline"); + + if (pc->IsPreproc()) + { + output_to_column(pc->GetNlColumn(), (pp_indent_with_tabs == 2)); + } + else + { + output_to_column(pc->GetNlColumn(), (options::indent_with_tabs() == 2)); + } + } + add_char('\n'); + } + + cpd.did_newline = true; + cpd.column = 1; + } + else if (pc->Is(CT_NL_CONT)) + { + // FIXME: this really shouldn't be done here! + if (!pc->TestFlags(PCF_WAS_ALIGNED)) + { + // Add or remove space before a backslash-newline at the end of a line. + log_rule_B("sp_before_nl_cont"); + + if (options::sp_before_nl_cont() & IARF_REMOVE) + { + log_rule_B("sp_before_nl_cont"); + pc->SetColumn(cpd.column + (options::sp_before_nl_cont() == IARF_FORCE)); + } + else + { + // Try to keep the same relative spacing + Chunk *prev = pc->GetPrev(); + + if (prev->Is(CT_PP_IGNORE)) + { + /* + * Want to completely leave alone PP_IGNORE'd blocks because + * they likely have special column aligned newline + * continuations (common in multiline macros) + */ + pc->SetColumn(pc->GetOrigCol()); + } + else + { + // Try to keep the same relative spacing + while ( prev != nullptr + && prev->IsNotNullChunk() + && prev->GetOrigCol() == 0 + && prev->GetNlCount() == 0) + { + prev = prev->GetPrev(); + } + + if ( prev != nullptr + && prev->IsNotNullChunk() + && prev->GetNlCount() == 0) + { + int orig_sp = pc->GetOrigPrevSp(); + + if ((int)(cpd.column + orig_sp) < 0) + { +#ifdef WIN32 + fprintf(stderr, "FATAL: negative value.\n pc->GetOrigCol() is %d, prev->GetOrigColEnd() is %d\n", + (int)pc->GetOrigCol(), (int)prev->GetOrigColEnd()); +#else // not WIN32 + fprintf(stderr, "FATAL: negative value.\n pc->GetOrigCol() is %zu, prev->GetOrigColEnd() is %zu\n", + pc->GetOrigCol(), prev->GetOrigColEnd()); +#endif // ifdef WIN32 + log_flush(true); + exit(EX_SOFTWARE); + } + pc->SetColumn(cpd.column + orig_sp); + + // Add or remove space before a backslash-newline at the end of a line. + log_rule_B("sp_before_nl_cont"); + + if ( (options::sp_before_nl_cont() != IARF_IGNORE) + && (pc->GetColumn() < (cpd.column + 1))) + { + pc->SetColumn(cpd.column + 1); + } + } + } + } + output_to_column(pc->GetColumn(), false); + } + else + { + log_rule_B("indent_with_tabs - newline cont"); + + if (pc->IsPreproc()) + { + output_to_column(pc->GetColumn(), (pp_indent_with_tabs == 2)); + } + else + { + output_to_column(pc->GetColumn(), (options::indent_with_tabs() == 2)); + } + } + add_char('\\'); + add_char('\n'); + cpd.did_newline = true; + cpd.column = 1; + } + else if (pc->Is(CT_COMMENT_MULTI)) + { + log_rule_B("cmt_indent_multi"); + log_rule_B("cmt_convert_tab_to_spaces - multi"); + cpd.output_tab_as_space = options::cmt_convert_tab_to_spaces(); + + if (options::cmt_indent_multi()) + { + output_comment_multi(pc); + } + else + { + output_comment_multi_simple(pc); + } + } + else if (pc->Is(CT_COMMENT_CPP)) + { + log_rule_B("cmt_comment_cpp"); + log_rule_B("cmt_convert_tab_to_spaces - comment_cpp"); + cpd.output_tab_as_space = options::cmt_convert_tab_to_spaces(); + + bool tmp = cpd.output_trailspace; + /* + * keep trailing spaces if they are still present in a chunk; + * note that tokenize() already strips spaces in comments, + * so if they made it up to here, they are to stay + */ + cpd.output_trailspace = true; + pc = output_comment_cpp(pc); + cpd.output_trailspace = tmp; + } + else if (pc->Is(CT_COMMENT)) + { + log_rule_B("cmt_comment"); + log_rule_B("cmt_convert_tab_to_spaces - comment"); + cpd.output_tab_as_space = options::cmt_convert_tab_to_spaces(); + + pc = output_comment_c(pc); + } + else if ( pc->Is(CT_JUNK) + || pc->Is(CT_IGNORED)) + { + LOG_FMT(LOUTIND, "%s(%d): orig line is %zu, orig col is %zu,\npc->Text() >%s<, pc->str.size() is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), pc->GetStr().size()); + // do not adjust the column for junk + add_text(pc->GetStr(), true); + } + else if (pc->Len() == 0) + { + // don't do anything for non-visible stuff + LOG_FMT(LOUTIND, "%s(%d): orig line is %zu, column is %zu, non-visible stuff: type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetColumn(), get_token_name(pc->GetType())); + } + else + { + bool allow_tabs; + cpd.output_trailspace = (pc->Is(CT_STRING_MULTI)); + + // indent to the 'level' first + if (cpd.did_newline) + { + if ( ( pc->IsPreproc() + && pp_indent_with_tabs == 1) + || ( !pc->IsPreproc() + && options::indent_with_tabs() == 1)) + { + size_t lvlcol; + + /* + * FIXME: it would be better to properly set m_columnIndent in + * indent_text(), but this hack for '}' and '#' seems to work. + */ + if ( pc->Is(CT_BRACE_CLOSE) + || pc->Is(CT_CASE_COLON) + || pc->IsPreproc()) + { + lvlcol = pc->GetColumn(); + } + else + { + lvlcol = pc->GetColumnIndent(); + + if (lvlcol > pc->GetColumn()) + { + lvlcol = pc->GetColumn(); + } + } + + if (lvlcol > 1) + { + log_rule_B("indent_with_tabs - hack"); + output_to_column(lvlcol, true); + } + } + log_rule_B("indent_with_tabs"); + allow_tabs = ( pc->IsPreproc() + && pp_indent_with_tabs == 2) + || ( !pc->IsPreproc() + && options::indent_with_tabs() == 2) + || ( pc->IsComment() + && options::indent_with_tabs() != 0); + + LOG_FMT(LOUTIND, "%s(%d): orig line is %zu, column is %zu, column indent is %zu, cpd.column is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetColumn(), pc->GetColumnIndent(), cpd.column); + } + else + { + /* + * Reformatting multi-line comments can screw up the column. + * Make sure we don't mess up the spacing on this line. + * This has to be done here because comments are not formatted + * until the output phase. + */ + if (pc->GetColumn() < cpd.column) + { + reindent_line(pc, cpd.column); + } + // not the first item on a line + Chunk *prev = pc->GetPrev(); + log_rule_B("align_with_tabs"); + allow_tabs = ( options::align_with_tabs() + && pc->TestFlags(PCF_WAS_ALIGNED) + && ((prev->GetColumn() + prev->Len() + 1) != pc->GetColumn())); + + log_rule_B("align_keep_tabs"); + + if (options::align_keep_tabs()) + { + allow_tabs |= pc->GetAfterTab(); + } + LOG_FMT(LOUTIND, "%s(%d): at column %zu(%s)\n", + __func__, __LINE__, pc->GetColumn(), (allow_tabs ? "true" : "FALSE")); + } + output_to_column(pc->GetColumn(), allow_tabs); + + if (write_in_tracking) + { + if (pc->Is(CT_ANGLE_OPEN)) + { + add_text("<", false, false); + } + else if (pc->Is(CT_ANGLE_CLOSE)) + { + add_text(">", false, false); + } + else + { + if (tracking) + { + if (pc->GetStr()[0] == '<') + { + add_text("<", false, false); + size_t lang = pc->GetStr().size(); + + for (size_t idx = 1; idx < lang - 1; idx++) + { + int ch = pc->GetStr()[idx]; + add_char(ch); + } + + add_text(">", false, false); + } + } + add_text(pc->GetStr(), false, pc->Is(CT_STRING)); + } + write_in_tracking = false; + } + else + { + add_text(pc->GetStr(), false, pc->Is(CT_STRING)); + } + + if (pc->Is(CT_PP_DEFINE)) // Issue #876 + { + // If true, a <TAB> is inserted after #define. + log_rule_B("force_tab_after_define"); + + if (options::force_tab_after_define()) + { + add_char('\t'); + } + } + cpd.did_newline = pc->IsNewline(); + cpd.output_trailspace = false; + } + + if (pc->GetTrackingData() != nullptr) + { + LOG_FMT(LGUY, " Tracking info are: \n"); + LOG_FMT(LGUY, " number of track(s) %zu\n", pc->GetTrackingData()->size()); + add_text("<a title=\""); + char tempText[80]; + + // is sorting necessary? + size_t many = pc->GetTrackingData()->size(); + + if (many > 1) + { +#ifdef EXTRA_LOG + // protocol before sort + for (size_t track = 0; track < pc->GetTrackingData()->size(); track++) + { + const track_list *A = pc->GetTrackingData(); + const Track_nr B = A->at(track); + size_t Bfirst = B.first; + char *Bsecond = B.second; + + LOG_FMT(LGUY, " %zu, tracking number is %zu\n", track, Bfirst); + LOG_FMT(LGUY, " %zu, rule is %s\n", track, Bsecond); + } +#endif + + if (options::debug_sort_the_tracks()) + { + track_list *A1 = pc->TrackingData(); + sort(A1->begin(), A1->end(), compareTrack); + } +#ifdef EXTRA_LOG + // protocol after sort + for (size_t track = 0; track < pc->GetTrackingData()->size(); track++) + { + const track_list *A = pc->GetTrackingData(); + const Track_nr B = A->at(track); + size_t Bfirst = B.first; + char *Bsecond = B.second; + + LOG_FMT(LGUY, " %zu, tracking number is %zu\n", track, Bfirst); + LOG_FMT(LGUY, " %zu, rule is %s\n", track, Bsecond); + } +#endif + } + char *old_one = nullptr; + + for (size_t track = 0; track < pc->GetTrackingData()->size(); track++) + { + const track_list *A = pc->GetTrackingData(); + const Track_nr B = A->at(track); + size_t Bfirst = B.first; + char *Bsecond = B.second; + bool first_text = true; + + if ( old_one == nullptr + || strcmp(old_one, Bsecond) != 0) + { + // first time this option + if (old_one != nullptr) + { + add_text("
"); + } + old_one = Bsecond; + + if (first_text) + { + sprintf(tempText, "%s", Bsecond); + add_text(tempText); + add_text(": "); + first_text = false; + } + } + else + { + add_text(", "); + } + sprintf(tempText, "%zu", Bfirst); + add_text(tempText); + } // for (size_t track = 0; track < pc->GetTrackingData()->size(); track++) + + add_text("\"><font color=\"red\">M</font></a>"); + write_in_tracking = true; + } // if (pc->GetTrackingData() != nullptr) + } // loop over the whole chunk list + + if (tracking) + { + set_numbering(false); + add_text("</pre>\n"); + add_text("</body>\n"); + add_text("</html>\n"); + } +} // output_text + + +void dump_step(const char *filename, const char *step_description) +{ + static int file_num = 0; + char buffer[256]; + FILE *dump_file; + + if ( filename == nullptr + || strlen(filename) == 0) + { + return; + } + + // On the first call, also save the options in use + if (file_num == 0) + { + snprintf(buffer, 256, "New dump file: %s_%03d.log - Options in use", filename, file_num); + log_rule_B(buffer); + + snprintf(buffer, 256, "%s_%03d.log", filename, file_num); + ++file_num; + + dump_file = fopen(buffer, "wb"); + + if (dump_file != nullptr) + { + save_option_file(dump_file, false, true); + fclose(dump_file); + } + } + snprintf(buffer, 256, "New dump file: %s_%03d.log - %s", filename, file_num, step_description); + log_rule_B(buffer); + + snprintf(buffer, 256, "%s_%03d.log", filename, file_num); + ++file_num; + + dump_file = fopen(buffer, "wb"); + + if (dump_file != nullptr) + { + fprintf(dump_file, "STEP: %s\n--------------\n", step_description); + output_parsed(dump_file, false); + fclose(dump_file); + } +} // dump_step + + +static size_t cmt_parse_lead(const unc_text &line, bool is_last) +{ + size_t len = 0; + + while ( len < 32 + && len < line.size()) // TODO what is the meaning of 32? + { + if ( len > 0 + && line[len] == '/') + { + // ignore combined comments + size_t tmp = len + 1; + + while ( tmp < line.size() + && unc_isspace(line[tmp])) + { + tmp++; + } + + if ( tmp < line.size() + && line[tmp] == '/') + { + return(1); + } + break; + } + else if (strchr("*|\\#+", line[len]) == nullptr) + { + break; // none of the characters '*|\#+' found in line + } + len++; + } + + if (len > 30) // TODO: what is the meaning of 30? + { + return(1); + } + + if ( len > 0 + && ( len >= line.size() + || unc_isspace(line[len]))) + { + return(len); + } + + if ( len == 1 + && line[0] == '*') + { + return(len); + } + + if ( is_last + && len > 0) + { + return(len); + } + return(0); +} // cmt_parse_lead + + +/** + * Eat whitespace characters starting at the specified index in the forward or reverse direction + * within a single line + * @param str the input string containing the comment text + * @param idx the starting index + * @param forward if true, searches in the forward direction; + * if false, searches in the reverse direction + * @return the first index at which a non-whitespace character is encountered, including + * a newline character + */ +template<typename String> +static int eat_line_whitespace(const String &str, + int idx, bool + forward = true) +{ + auto advance_index = [&](int i) + { + return(forward ? i + 1 : i - 1); + }; + + auto index_in_range = [&](int i) + { + // TODO: the following BREAKS with source code formatting; uncrustify seems to + // think that the following is a template. This will NEED to be fixed!!! + // For now, reformulate the statement + //return(forward ? i<int(str.size()) : i> = 0); + return(forward ? (i < int(str.size())) : (i >= 0)); + }; + + while ( index_in_range(idx) + && str[idx] != '\n' + && str[idx] != '\r' + && unc_isspace(str[idx])) + { + idx = advance_index(idx); + } + return(idx); +} // eat_line_whitespace + + +/** + * Returns whether or not a javaparam tag is the leading + * text in a comment line, with only a sequence of whitespace + * and/or '*' characters preceding it + * @param str the input string containing the comment text + * @param idx the starting index + * @return true/false + */ +template<typename String> +static bool javaparam_tag_is_start_of_line(const String &str, int idx) +{ + idx = eat_line_whitespace(str, + str[idx] == '@' ? idx - 1 : idx, + false); + + while (true) + { + if ( idx < 0 + || str[idx] == '\n' + || str[idx] == '\r') + { + return(true); + } + + if (str[idx] == '*') + { + idx = eat_line_whitespace(str, + idx - 1, + false); + } + else + { + return(false); + } + } +} // javaparam_tag_is_start_of_line + + +/** + * Attempts to match a doxygen/javadoc-style comment tag + * @param str the input string containing the comment text + * @param idx the starting index + * @return the index of the character immediately following the matched tag, + * or -1 if no match is found + */ +static int match_doxygen_javadoc_tag(const std::wstring &str, size_t idx) +{ + std::wsmatch match; + + if (str[idx] == L'@') + { + // Issue #3357 + std::wregex criteria(L"(@(?:author|" + L"deprecated|" + L"exception|" + L"param(?:\\s*?\\[\\s*(?:in\\s*,\\s*out|in|out)\\s*?\\])?|" + L"return|" + L"see|" + L"since|" + L"throws|" + L"version)(?=\\s))"); + + if ( std::regex_search(str.cbegin() + idx, str.cend(), match, criteria) + && match[1].matched + && match.position(1) == std::wsmatch::difference_type(0)) + { + std::set<std::wstring> block_tags = + { + L"@author", + L"@deprecated", + L"@exception", + L"@param", + L"@param[in]", + L"@param[in,out]", + L"@param[out]", + L"@return", + L"@see", + L"@since", + L"@throws", + L"@version" + }; + std::wstring result(match[1]); + result.erase(std::remove_if(result.begin(), result.end(), ::isspace), result.end()); + auto &&it_block_tag = block_tags.find(result); + + if ( it_block_tag != block_tags.end() + && javaparam_tag_is_start_of_line(str, idx)) + { + return(int(idx + match[1].length())); + } + } + } + return(-1); +} // match_javadoc_block_tag + + +static void calculate_doxygen_javadoc_indent_alignment(const std::wstring &str, + size_t &doxygen_javadoc_param_name_indent, + size_t &doxygen_javadoc_continuation_indent) +{ + log_rule_B("cmt_align_doxygen_javadoc_tags"); + + doxygen_javadoc_continuation_indent = 0; + doxygen_javadoc_param_name_indent = 0; + + if (!options::cmt_align_doxygen_javadoc_tags()) + { + return; + } + + for (size_t idx = 0; idx < str.size(); ++idx) + { + int start_idx = idx; + int end_idx = match_doxygen_javadoc_tag(str, start_idx); + + if (end_idx > start_idx) + { + size_t block_tag_width = 1 + std::count_if(str.begin() + start_idx, + str.begin() + end_idx, + [](wchar_t ch) { + return(!unc_isspace(ch)); + }); + + if (block_tag_width > doxygen_javadoc_param_name_indent) + { + doxygen_javadoc_param_name_indent = block_tag_width; + } + idx = eat_line_whitespace(str, end_idx); + + size_t param_name_width = 0; + + if (str.find(L"@param", start_idx) == size_t(start_idx)) + { + param_name_width = 1; + + while (true) + { + while ( !unc_isspace(str[idx]) + && str[idx] != ',') + { + ++param_name_width; + ++idx; + } + idx = eat_line_whitespace(str, idx); + + if (str[idx] != ',') + { + break; + } + param_name_width += 2; + idx = eat_line_whitespace(str, idx + 1); + } + } + + if (param_name_width > doxygen_javadoc_continuation_indent) + { + doxygen_javadoc_continuation_indent = param_name_width; + } + } + } + + if (doxygen_javadoc_param_name_indent > 0) + { + log_rule_B("cmt_sp_before_doxygen_javadoc_tags"); + + doxygen_javadoc_param_name_indent += options::cmt_sp_before_doxygen_javadoc_tags(); + doxygen_javadoc_continuation_indent += doxygen_javadoc_param_name_indent; + } +} // calculate_doxygen_javadoc_indent_alignment + + +static void calculate_comment_body_indent(cmt_reflow &cmt, const unc_text &str) +{ + cmt.xtra_indent = 0; + + log_rule_B("cmt_indent_multi"); + + if (!options::cmt_indent_multi()) + { + return; + } + size_t idx = 0; + size_t len = str.size(); + size_t last_len = 0; + + log_rule_B("cmt_multi_check_last"); + + if (options::cmt_multi_check_last()) + { + // find the last line length + for (idx = len - 1; idx > 0; idx--) + { + if ( str[idx] == '\n' + || str[idx] == '\r') + { + idx++; + + while ( idx < len + && ( str[idx] == ' ' + || str[idx] == '\t')) + { + idx++; + } + last_len = len - idx; + break; + } + } + } + // find the first line length + size_t first_len = 0; + + for (idx = 0; idx < len; idx++) + { + if ( str[idx] == '\n' + || str[idx] == '\r') + { + first_len = idx; + + while ( str[first_len - 1] == ' ' + || str[first_len - 1] == '\t') + { + if (first_len == 0) + { + fprintf(stderr, "%s(%d): first_len is ZERO, cannot be decremented.\n", + __func__, __LINE__); + log_flush(true); + exit(EX_SOFTWARE); + } + first_len--; + } + + // handle DOS endings + if ( str[idx] == '\r' + && str[idx + 1] == '\n') + { + idx++; + } + idx++; + break; + } + } + + // Scan the second line + size_t width = 0; + + for ( ; idx < len - 1; idx++) + { + if ( str[idx] == ' ' + || str[idx] == '\t') + { + if (width > 0) + { + break; + } + continue; + } + + if ( str[idx] == '\n' + || str[idx] == '\r') + { + break; // Done with second line + } + + // Count the leading chars + if ( str[idx] == '*' + || str[idx] == '|' + || str[idx] == '\\' + || str[idx] == '#' + || str[idx] == '+') + { + width++; + } + else + { + if ( width != 1 + || str[idx - 1] != '*') + { + width = 0; + } + break; + } + } + + // LOG_FMT(LSYS, "%s: first=%d last=%d width=%d\n", __func__, first_len, last_len, width); + + /* + * If the first and last line are the same length and don't contain any + * alphanumeric chars and (the first line len > cmt_multi_first_len_minimum + * or the second leader is the same as the first line length), then the + * indent is 0. + */ + log_rule_B("cmt_multi_first_len_minimum"); + + if ( first_len == last_len + && ( first_len > options::cmt_multi_first_len_minimum() + || first_len == width)) + { + return; + } + cmt.xtra_indent = (width == 2) ? 0 : 1; +} // calculate_comment_body_indent + + +// TODO: can we use search_next_chunk here? +static Chunk *get_next_function(Chunk *pc) +{ + if (pc == nullptr) + { + pc = Chunk::NullChunkPtr; + } + + while ((pc = pc->GetNext())->IsNotNullChunk()) + { + if ( pc->Is(CT_FUNC_DEF) + || pc->Is(CT_FUNC_PROTO) + || pc->Is(CT_FUNC_CLASS_DEF) + || pc->Is(CT_FUNC_CLASS_PROTO) + || pc->Is(CT_OC_MSG_DECL)) + { + return(pc); + } + } + return(nullptr); +} + + +static Chunk *get_next_class(Chunk *pc) +{ + return(pc->GetNextType(CT_CLASS)->GetNext()); +} + + +static Chunk *get_prev_category(Chunk *pc) +{ + return(pc->GetPrevType(CT_OC_CATEGORY)); +} + + +static Chunk *get_next_scope(Chunk *pc) +{ + return(pc->GetNextType(CT_OC_SCOPE)); +} + + +static Chunk *get_prev_oc_class(Chunk *pc) +{ + return(pc->GetPrevType(CT_OC_CLASS)); +} + + +static int next_up(const unc_text &text, size_t idx, const unc_text &tag) +{ + size_t offs = 0; + + while ( idx < text.size() + && unc_isspace(text[idx])) + { + idx++; + offs++; + } + + if (text.startswith(tag, idx)) + { + return(offs); + } + return(-1); +} + + +static void add_comment_text(const unc_text &text, + cmt_reflow &cmt, + bool esc_close, + size_t continuation_indent) +{ + bool was_star = false; + bool was_slash = false; + bool in_word = false; + size_t len = text.size(); + size_t ch_cnt = 0; // chars since newline + + // If the '//' is included write it first else we may wrap an empty line + size_t idx = 0; + + if (text.startswith("//")) + { + add_text("//"); + idx += 2; + + while (unc_isspace(text[idx])) + { + add_char(text[idx++]); + } + } + + for ( ; idx < len; idx++) // TODO: avoid modifying idx in loop + { + // Split the comment + if (text[idx] == '\n') + { + in_word = false; + add_char('\n'); + cmt_output_indent(cmt.brace_col, cmt.base_col, cmt.column); + + if (cmt.xtra_indent > 0) + { + add_char(' '); + } + // hack to get escaped newlines to align and not duplicate the leading '//' + int tmp = next_up(text, idx + 1, "//"); + + if (tmp < 0) + { + add_text(cmt.cont_text); + } + else + { + idx += tmp; + } + ch_cnt = 0; + } + else if ( cmt.reflow + && text[idx] == ' ' + && options::cmt_width() > 0 + && ( cpd.column > options::cmt_width() + || ( ch_cnt > 1 + && next_word_exceeds_limit(text, idx)))) + { + log_rule_B("cmt_width"); + in_word = false; + add_char('\n'); + cmt_output_indent(cmt.brace_col, cmt.base_col, cmt.column); + + if (cmt.xtra_indent > 0) + { + add_char(' '); + } + // The number of spaces to insert after the star on subsequent comment lines. + log_rule_B("cmt_sp_after_star_cont"); + + /** + * calculate the output column + */ + size_t column = options::cmt_sp_after_star_cont(); + + if ( text[idx + 1] == 42 // this is star * + && text[idx + 2] == 47) // this is / + { + LOG_FMT(LCONTTEXT, "%s(%d): we have a comment end\n", + __func__, __LINE__); + + column += cmt.column; + } + else + { + add_text(cmt.cont_text); + + if (continuation_indent > 0) + { + if (options::cmt_align_doxygen_javadoc_tags()) + { + log_rule_B("cmt_align_doxygen_javadoc_tags"); + } + else if (options::cmt_reflow_indent_to_paragraph_start()) + { + log_rule_B("cmt_reflow_indent_to_paragraph_start"); + } + column += continuation_indent; + + log_rule_B("cmt_sp_after_star_cont"); + + if (column >= options::cmt_sp_after_star_cont()) + { + column -= options::cmt_sp_after_star_cont(); + } + } + /** + * count the number trailing spaces in the comment continuation text + */ + size_t num_trailing_sp = 0; + + while ( num_trailing_sp < cmt.cont_text.size() + && unc_isspace(cmt.cont_text[cmt.cont_text.size() - 1 - num_trailing_sp])) + { + ++num_trailing_sp; + } + column += cpd.column; + + if (column >= num_trailing_sp) + { + column -= num_trailing_sp; + } + } + output_to_column(column, + false); + ch_cnt = 0; + } + else + { + // Escape a C closure in a CPP comment + if ( esc_close + && ( ( was_star + && text[idx] == '/') + || ( was_slash + && text[idx] == '*'))) + { + add_char(' '); + } + + if ( !in_word + && !unc_isspace(text[idx])) + { + cmt.word_count++; + } + in_word = !unc_isspace(text[idx]); + + add_char(text[idx]); + was_star = (text[idx] == '*'); + was_slash = (text[idx] == '/'); + ch_cnt++; + } + } +} // add_comment_text + + +static void output_cmt_start(cmt_reflow &cmt, Chunk *pc) +{ + cmt.pc = pc; + cmt.column = pc->GetColumn(); + cmt.brace_col = pc->GetColumnIndent(); + cmt.base_col = pc->GetColumnIndent(); + cmt.word_count = 0; + cmt.xtra_indent = 0; + cmt.cont_text.clear(); + cmt.reflow = false; + + // Issue #2752 + log_rule_B("cmt_insert_file_header"); + log_rule_B("cmt_insert_file_footer"); + log_rule_B("cmt_insert_func_header)"); + log_rule_B("cmt_insert_class_header"); + log_rule_B("cmt_insert_oc_msg_header"); + + if ( options::cmt_insert_file_header().size() > 0 + || options::cmt_insert_file_footer().size() > 0 + || options::cmt_insert_func_header().size() > 0 + || options::cmt_insert_class_header().size() > 0 + || options::cmt_insert_oc_msg_header().size() > 0) + { + LOG_FMT(LCONTTEXT, "%s(%d): cmt_insert_file\n", __func__, __LINE__); + do_kw_subst(pc); + } + else + { + LOG_FMT(LCONTTEXT, "%s(%d): no cmt_insert_file\n", __func__, __LINE__); + } + + if (cmt.brace_col == 0) + { + log_rule_B("output_tab_size"); + cmt.brace_col = 1 + (pc->GetBraceLevel() * options::output_tab_size()); + } + // LOG_FMT(LSYS, "%s: line %zd, brace=%zd base=%zd col=%zd orig=%zd aligned=%x\n", + // __func__, pc->GetOrigLine(), cmt.brace_col, cmt.base_col, cmt.column, pc->GetOrigCol(), + // pc->GetFlags() & (PCF_WAS_ALIGNED | PCF_RIGHT_COMMENT)); + + if ( pc->GetParentType() == CT_COMMENT_START + || pc->GetParentType() == CT_COMMENT_WHOLE) + { + log_rule_B("indent_col1_comment"); + + if ( !options::indent_col1_comment() + && pc->GetOrigCol() == 1 + && !pc->TestFlags(PCF_INSERTED)) + { + cmt.column = 1; + cmt.base_col = 1; + cmt.brace_col = 1; + } + } + // tab aligning code + log_rule_B("indent_cmt_with_tabs"); + + if ( options::indent_cmt_with_tabs() + && ( pc->GetParentType() == CT_COMMENT_END + || pc->GetParentType() == CT_COMMENT_WHOLE)) + { + cmt.column = align_tab_column(cmt.column - 1); + // LOG_FMT(LSYS, "%s: line %d, orig:%d new:%d\n", + // __func__, pc->GetOrigLine(), pc->GetColumn(), cmt.column); + pc->SetColumn(cmt.column); + } + cmt.base_col = cmt.column; + + // LOG_FMT(LSYS, "%s: -- brace=%d base=%d col=%d\n", + // __func__, cmt.brace_col, cmt.base_col, cmt.column); + + // Bump out to the column + cmt_output_indent(cmt.brace_col, cmt.base_col, cmt.column); +} // output_cmt_start + + +static bool can_combine_comment(Chunk *pc, cmt_reflow &cmt) +{ + // We can't combine if there is something other than a newline next + if (pc->GetParentType() == CT_COMMENT_START) + { + return(false); + } + + // next is a newline for sure, make sure it is a single newline + if (pc == nullptr) + { + pc = Chunk::NullChunkPtr; + } + Chunk *next = pc->GetNext(); + + if ( next->IsNotNullChunk() + && next->GetNlCount() == 1) + { + // Make sure the comment is the same type at the same column + next = next->GetNext(); + + if ( next->Is(pc->GetType()) + && ( ( next->GetColumn() == 1 + && pc->GetColumn() == 1) + || ( next->GetColumn() == cmt.base_col + && pc->GetColumn() == cmt.base_col) + || ( next->GetColumn() > cmt.base_col + && pc->GetParentType() == CT_COMMENT_END))) + { + return(true); + } + } + return(false); +} // can_combine_comment + + +static Chunk *output_comment_c(Chunk *first) +{ + cmt_reflow cmt; + + output_cmt_start(cmt, first); + log_rule_B("cmt_reflow_mode"); + cmt.reflow = (options::cmt_reflow_mode() != 1); + + // See if we can combine this comment with the next comment + log_rule_B("cmt_c_group"); + + if ( !options::cmt_c_group() + || !can_combine_comment(first, cmt)) + { + // Just add the single comment + log_rule_B("cmt_star_cont"); + cmt.cont_text = options::cmt_star_cont() ? " * " : " "; + LOG_CONTTEXT(); + + log_rule_B("cmt_trailing_single_line_c_to_cpp"); + + if (options::cmt_trailing_single_line_c_to_cpp() && first->IsLastChunkOnLine()) + { + add_text("//"); + + unc_text tmp; + tmp.set(first->GetStr(), 2, first->Len() - 4); + cmt_trim_whitespace(tmp, false); + add_comment_text(tmp, cmt, false); + } + else + { + add_comment_text(first->GetStr(), cmt, false); + } + return(first); + } + log_rule_B("cmt_star_cont"); + cmt.cont_text = options::cmt_star_cont() ? " *" : " "; + LOG_CONTTEXT(); + + add_text("/*"); + + log_rule_B("cmt_c_nl_start"); + + if (options::cmt_c_nl_start()) + { + add_comment_text("\n", cmt, false); + } + Chunk *pc = first; + unc_text tmp; + + while (can_combine_comment(pc, cmt)) + { + LOG_FMT(LCONTTEXT, "%s(%d): Text() is '%s'\n", + __func__, __LINE__, pc->Text()); + tmp.set(pc->GetStr(), 2, pc->Len() - 4); + + if ( cpd.last_char == '*' + && tmp[0] != ' ') // Issue #1908 + { + LOG_FMT(LCONTTEXT, "%s(%d): add_text a " "\n", __func__, __LINE__); + add_text(" "); + } + // In case of reflow, original comment could contain trailing spaces before closing the comment, we don't need them after reflow + LOG_FMT(LCONTTEXT, "%s(%d): trim\n", __func__, __LINE__); + cmt_trim_whitespace(tmp, false); + LOG_FMT(LCONTTEXT, "%s(%d): add_comment_text(tmp is '%s')\n", + __func__, __LINE__, tmp.c_str()); + add_comment_text(tmp, cmt, false); + LOG_FMT(LCONTTEXT, "%s(%d): add_comment_text(newline)\n", + __func__, __LINE__); + add_comment_text("\n", cmt, false); + pc = pc->GetNext(); + pc = pc->GetNext(); + } + tmp.set(pc->GetStr(), 2, pc->Len() - 4); + + if ( cpd.last_char == '*' + && tmp[0] == '/') + { + add_text(" "); + } + // In case of reflow, original comment could contain trailing spaces before closing the comment, we don't need them after reflow + cmt_trim_whitespace(tmp, false); + add_comment_text(tmp, cmt, false); + + log_rule_B("cmt_c_nl_end"); + + if (options::cmt_c_nl_end()) + { + cmt.cont_text = " "; + LOG_CONTTEXT(); + add_comment_text("\n", cmt, false); + } + add_comment_text("*/", cmt, false); + return(pc); +} // output_comment_c + + +static Chunk *output_comment_cpp(Chunk *first) +{ + cmt_reflow cmt; + + output_cmt_start(cmt, first); + log_rule_B("cmt_reflow_mode"); + cmt.reflow = (options::cmt_reflow_mode() != 1); + + unc_text leadin = "//"; // default setting to keep previous behaviour + + // If true, space is added with sp_cmt_cpp_start will be added after doxygen + // sequences like '///', '///<', '//!' and '//!<'. + log_rule_B("sp_cmt_cpp_doxygen"); + + if (options::sp_cmt_cpp_doxygen()) // special treatment for doxygen style comments (treat as unity) + { + const char *sComment = first->Text(); + bool grouping = (sComment[2] == '@'); + size_t brace = 3; + + if ( sComment[2] == '/' + || sComment[2] == '!') // doxygen style found! + { + leadin += sComment[2]; // at least one additional char (either "///" or "//!") + + if (sComment[3] == '<') // and a further one (either "///<" or "//!<") + { + leadin += '<'; + } + else + { + grouping = (sComment[3] == '@'); // or a further one (grouping) + brace = 4; + } + } + + if ( grouping + && ( sComment[brace] == '{' + || sComment[brace] == '}')) + { + leadin += '@'; + leadin += sComment[brace]; + } + } + // Special treatment for Qt translator or meta-data comments (treat as unity) + // If true, space is added with sp_cmt_cpp_start will be added after Qt + // translator or meta-data comments like '//:', '//=', and '//~'. + log_rule_B("sp_cmt_cpp_qttr"); + + if (options::sp_cmt_cpp_qttr()) + { + const int c = first->GetStr()[2]; + + if ( c == ':' + || c == '=' + || c == '~') + { + leadin += c; + } + } + // CPP comments can't be grouped unless they are converted to C comments + log_rule_B("cmt_cpp_to_c"); + + if (!options::cmt_cpp_to_c()) + { + auto const *cmt_text = first->GetStr().c_str() + 2; + // Add or remove space after the opening of a C++ comment, + // i.e. '// A' vs. '//A'. + auto *sp_cmt = &options::sp_cmt_cpp_start; + + cmt.cont_text = leadin; + + // Get start of comment text + while ( *cmt_text != '\0' + && unc_isspace(*cmt_text)) + { + ++cmt_text; + } + + // Determine if we are dealing with a region marker + if ( ( first->GetPrev()->IsNullChunk() + || first->GetPrev()->GetOrigLine() != first->GetOrigLine()) + && ( strncmp(cmt_text, "BEGIN", 5) == 0 + || strncmp(cmt_text, "END", 3) == 0)) + { + // If sp_cmt_cpp_region is not ignore, use that instead of + // sp_cmt_cpp_start + if (options::sp_cmt_cpp_region() != IARF_IGNORE) + { + sp_cmt = &options::sp_cmt_cpp_region; + } + } + // Add or remove space after the opening of a C++ comment, + // i.e. '// A' vs. '//A'. + log_rule_B(sp_cmt->name()); + + if ((*sp_cmt)() != IARF_REMOVE) + { + cmt.cont_text += ' '; + } + LOG_CONTTEXT(); + + // Add or remove space after the opening of a C++ comment, + // i.e. '// A' vs. '//A'. + log_rule_B(sp_cmt->name()); + + if ((*sp_cmt)() == IARF_IGNORE) + { + add_comment_text(first->GetStr(), cmt, false); + } + else + { + size_t iLISz = leadin.size(); + unc_text tmp(first->GetStr(), 0, iLISz); + add_comment_text(tmp, cmt, false); + + tmp.set(first->GetStr(), iLISz, first->Len() - iLISz); + + // Add or remove space after the opening of a C++ comment, + // i.e. '// A' vs. '//A'. + log_rule_B("sp_cmt_cpp_start"); + + if ((*sp_cmt)() & IARF_REMOVE) + { + while ( (tmp.size() > 0) + && unc_isspace(tmp[0])) + { + tmp.pop_front(); + } + } + + if (tmp.size() > 0) + { + // Add or remove space after the opening of a C++ comment, + // i.e. '// A' vs. '//A'. + log_rule_B("sp_cmt_cpp_start"); + + if ((*sp_cmt)() & IARF_ADD) + { + if ( !unc_isspace(tmp[0]) + && (tmp[0] != '/')) + { + add_comment_text(" ", cmt, false); + } + } + add_comment_text(tmp, cmt, false); + } + } + return(first); + } + // We are going to convert the CPP comments to C comments + log_rule_B("cmt_star_cont"); + cmt.cont_text = options::cmt_star_cont() ? " * " : " "; + LOG_CONTTEXT(); + + unc_text tmp; + + // See if we can combine this comment with the next comment + log_rule_B("cmt_cpp_group"); + + if ( !options::cmt_cpp_group() + || !can_combine_comment(first, cmt)) + { + // nothing to group: just output a single line + add_text("/*"); + + // patch # 32, 2012-03-23 + // Add or remove space after the opening of a C++ comment, + // i.e. '// A' vs. '//A'. + log_rule_B("sp_cmt_cpp_start"); + + if ( !unc_isspace(first->GetStr()[2]) + && (options::sp_cmt_cpp_start() & IARF_ADD)) + { + add_char(' '); + } + tmp.set(first->GetStr(), 2, first->Len() - 2); + add_comment_text(tmp, cmt, true); + add_text(" */"); + return(first); + } + add_text("/*"); + + log_rule_B("cmt_cpp_nl_start"); + + if (options::cmt_cpp_nl_start()) + { + add_comment_text("\n", cmt, false); + } + else + { + add_text(" "); + } + Chunk *pc = first; + int offs; + + while (can_combine_comment(pc, cmt)) + { + offs = unc_isspace(pc->GetStr()[2]) ? 1 : 0; + tmp.set(pc->GetStr(), 2 + offs, pc->Len() - (2 + offs)); + + if ( cpd.last_char == '*' + && tmp[0] == '/') + { + add_text(" "); + } + add_comment_text(tmp, cmt, true); + add_comment_text("\n", cmt, false); + pc = pc->GetNext()->GetNext(); + } + offs = unc_isspace(pc->GetStr()[2]) ? 1 : 0; + tmp.set(pc->GetStr(), 2 + offs, pc->Len() - (2 + offs)); + add_comment_text(tmp, cmt, true); + + log_rule_B("cmt_cpp_nl_end"); + + if (options::cmt_cpp_nl_end()) + { + cmt.cont_text = ""; + LOG_CONTTEXT(); + add_comment_text("\n", cmt, false); + } + add_comment_text(" */", cmt, false); + return(pc); +} // output_comment_cpp + + +static void cmt_trim_whitespace(unc_text &line, bool in_preproc) +{ + // Remove trailing whitespace on the line + while ( line.size() > 0 + && ( line.back() == ' ' + || line.back() == '\t')) + { + line.pop_back(); + } + + // Shift back to the comment text, ... + if ( in_preproc // if in a preproc ... + && line.size() > 1 // with a line that holds ... + && line.back() == '\\') // a backslash-newline ... + { + bool do_space = false; + + // If there was any space before the backslash, change it to 1 space + line.pop_back(); + + while ( line.size() > 0 + && ( line.back() == ' ' + || line.back() == '\t')) + { + do_space = true; + line.pop_back(); + } + + if (do_space) + { + line.append(' '); + } + line.append('\\'); + } +} // cmt_trim_whitespace + + +/** + * Return an indexed-map of reflow fold end of line/beginning of line regex pairs read + * from file + */ +static std::map<std::size_t, std::pair<std::wregex, std::wregex> > get_reflow_fold_regex_map() +{ + /** + * TODO: should the following be static to prevent initializing it multiple times? + */ + static std::map<std::size_t, std::pair<std::wregex, std::wregex> > regex_map; + + if (regex_map.empty()) + { + if (!options::cmt_reflow_fold_regex_file().empty()) + { + std::wstring raw_wstring(cpd.reflow_fold_regex.raw.begin(), + cpd.reflow_fold_regex.raw.end()); + + std::wregex criteria(L"\\s*(?:(?:(beg_of_next)|(end_of_prev))_line_regex)" + "\\s*\\[\\s*([0-9]+)\\s*\\]\\s*=\\s*\"(.*)\"\\s*" + "(?=\\r\\n|\\r|\\n|$)"); + std::wsregex_iterator it_regex(raw_wstring.cbegin(), raw_wstring.cend(), criteria); + std::wsregex_iterator it_regex_end = std::wsregex_iterator(); + + while (it_regex != it_regex_end) + { + std::wsmatch match = *it_regex; + + if ( (( match[1].matched + || match[2].matched)) + && match[3].matched + && match[4].matched) + { + auto &&index = std::stoi(match[3].str()); + std::wregex *p_wregex = match[1].matched ? ®ex_map[index].second + : ®ex_map[index].first; + *p_wregex = match[4].str(); + } + ++it_regex; + } + } + else + { + regex_map.emplace(0L, std::make_pair((std::wregex)L"[\\w,\\]\\)]$", (std::wregex)L"^[\\w,\\[\\(]")); + regex_map.emplace(1L, std::make_pair((std::wregex)L"\\.$", (std::wregex)L"^[A-Z]")); + } + } + return(regex_map); +} // get_reflow_fold_regex_map + + +static void output_comment_multi(Chunk *pc) +{ + if (pc == nullptr) + { + return; + } + cmt_reflow cmt; + + char copy[1000]; + + LOG_FMT(LCONTTEXT, "%s(%d): Text() is '%s', type is %s, orig col is %zu, column is %zu\n", + __func__, __LINE__, pc->ElidedText(copy), get_token_name(pc->GetType()), pc->GetOrigCol(), pc->GetColumn()); + + output_cmt_start(cmt, pc); + log_rule_B("cmt_reflow_mode"); + cmt.reflow = (options::cmt_reflow_mode() != 1); + + size_t cmt_col = cmt.base_col; + int col_diff = pc->GetOrigCol() - cmt.base_col; + + calculate_comment_body_indent(cmt, pc->GetStr()); + + log_rule_B("cmt_indent_multi"); + log_rule_B("cmt_star_cont"); + cmt.cont_text = !options::cmt_indent_multi() ? "" : + (options::cmt_star_cont() ? "* " : " "); + LOG_CONTTEXT(); + + std::wstring pc_wstring(pc->GetStr().get().cbegin(), + pc->GetStr().get().cend()); + + size_t doxygen_javadoc_param_name_indent = 0; + size_t doxygen_javadoc_continuation_indent = 0; + size_t reflow_paragraph_continuation_indent = 0; + + calculate_doxygen_javadoc_indent_alignment(pc_wstring, + doxygen_javadoc_param_name_indent, + doxygen_javadoc_continuation_indent); + + size_t line_count = 0; + size_t ccol = pc->GetColumn(); // the col of subsequent comment lines + size_t cmt_idx = 0; + bool nl_end = false; + bool doxygen_javadoc_indent_align = false; + unc_text line; + + /* + * Get a map of regex pairs that define expressions to match at both the end + * of the previous line and the beginning of the next line + */ + auto &&cmt_reflow_regex_map = get_reflow_fold_regex_map(); + + line.clear(); + LOG_FMT(LCONTTEXT, "%s(%d): pc->Len() is %zu\n", + __func__, __LINE__, pc->Len()); + //LOG_FMT(LCONTTEXT, "%s(%d): pc->str is %s\n", + // __func__, __LINE__, pc->str.c_str()); + + /** + * check for enable/disable processing comment strings that may + * both be embedded within the same multi-line comment + */ + auto disable_processing_cmt_idx = find_disable_processing_comment_marker(pc->GetStr()); + auto enable_processing_cmt_idx = find_enable_processing_comment_marker(pc->GetStr()); + + while (cmt_idx < pc->Len()) + { + int ch = pc->GetStr()[cmt_idx]; + cmt_idx++; + + if ( cmt_idx > std::size_t(disable_processing_cmt_idx) + && enable_processing_cmt_idx > disable_processing_cmt_idx) + { + auto length = enable_processing_cmt_idx - disable_processing_cmt_idx; + unc_text verbatim_text(pc->GetStr(), + disable_processing_cmt_idx, + length); + + add_text(verbatim_text); + + cmt_idx = enable_processing_cmt_idx; + + /** + * check for additional enable/disable processing comment strings that may + * both be embedded within the same multi-line comment + */ + disable_processing_cmt_idx = find_disable_processing_comment_marker(pc->GetStr(), + enable_processing_cmt_idx); + enable_processing_cmt_idx = find_enable_processing_comment_marker(pc->GetStr(), + enable_processing_cmt_idx); + + /** + * it's probably necessary to reset the line count to prevent line + * continuation characters from being added to the end of the current line + */ + line_count = 0; + } + + // handle the CRLF and CR endings. convert both to LF + if (ch == '\r') + { + ch = '\n'; + + if ( cmt_idx < pc->Len() + && pc->GetStr()[cmt_idx] == '\n') + { + cmt_idx++; + } + } + + // Find the start column + if (line.size() == 0) + { + nl_end = false; + + if (ch == ' ') + { + ccol++; + continue; + } + else if (ch == '\t') + { + log_rule_B("input_tab_size"); + ccol = calc_next_tab_column(ccol, options::input_tab_size()); + continue; + } + else + { + LOG_FMT(LCONTTEXT, "%s(%d):ch is %d, %c\n", __func__, __LINE__, ch, char(ch)); + } + } + + if ( ch == '@' + && options::cmt_align_doxygen_javadoc_tags()) + { + int start_idx = cmt_idx - 1; + int end_idx = match_doxygen_javadoc_tag(pc_wstring, start_idx); + + if (end_idx > start_idx) + { + doxygen_javadoc_indent_align = true; + + std::string match(pc->GetStr().get().cbegin() + start_idx, + pc->GetStr().get().cbegin() + end_idx); + + match.erase(std::remove_if(match.begin(), + match.end(), + ::isspace), + match.end()); + + /** + * remove whitespace before the '@' + */ + int line_size_before_indent = line.size(); + + while ( line_size_before_indent > 0 + && unc_isspace(line.back())) + { + line.pop_back(); + --line_size_before_indent; + } + log_rule_B("cmt_sp_before_doxygen_javadoc_tags"); + + int indent = options::cmt_sp_before_doxygen_javadoc_tags(); + + while (indent-- > 0) + { + line.append(' '); + } + cmt_idx += (end_idx - start_idx); + line.append(match.c_str()); + + bool is_exception_tag = match.find("@exception") != std::string::npos; + bool is_param_tag = match.find("@param") != std::string::npos; + bool is_throws_tag = match.find("@throws") != std::string::npos; + + if ( is_exception_tag + || is_param_tag + || is_throws_tag) + { + indent = int(doxygen_javadoc_param_name_indent) - int(line.size()); + + while (indent-- > -line_size_before_indent) + { + line.append(' '); + } + + while (true) + { + cmt_idx = eat_line_whitespace(pc->GetStr(), + cmt_idx); + + while ( cmt_idx < pc->Len() + && !unc_isspace(pc->GetStr()[cmt_idx]) + && pc->GetStr()[cmt_idx] != ',') + { + line.append(pc->Str()[cmt_idx++]); + } + + if (!is_param_tag) + { + break; + } + /** + * check for the possibility that comma-separated parameter names are present + */ + cmt_idx = eat_line_whitespace(pc->GetStr(), + cmt_idx); + + if (pc->GetStr()[cmt_idx] != ',') + { + break; + } + ++cmt_idx; + line.append(", "); + } + } + cmt_idx = eat_line_whitespace(pc->GetStr(), + cmt_idx); + indent = int(doxygen_javadoc_continuation_indent) - int(line.size()); + + while (indent-- > -line_size_before_indent) + { + line.append(' '); + } + + while ( cmt_idx < pc->Len() + && !unc_isspace(pc->GetStr()[cmt_idx])) + { + line.append(pc->Str()[cmt_idx++]); + } + continue; + } + } + /* + * Now see if we need/must fold the next line with the current to enable + * full reflow + */ + log_rule_B("cmt_reflow_mode"); + + if ( options::cmt_reflow_mode() == 2 + && ch == '\n' + && cmt_idx < pc->Len()) + { + int next_nonempty_line = -1; + int prev_nonempty_line = -1; + size_t nwidx = line.size(); + + // strip trailing whitespace from the line collected so far + while (nwidx > 0) + { + nwidx--; + + if ( prev_nonempty_line < 0 + && !unc_isspace(line[nwidx]) + && line[nwidx] != '*' // block comment: skip '*' at end of line + && (pc->TestFlags(PCF_IN_PREPROC) + ? ( line[nwidx] != '\\' + || ( line[nwidx + 1] != '\r' + && line[nwidx + 1] != '\n')) + : true)) + { + prev_nonempty_line = nwidx; // last non-whitespace char in the previous line + } + } + + for (size_t nxt_idx = cmt_idx; + ( nxt_idx < pc->Len() + && pc->GetStr()[nxt_idx] != '\r' + && pc->GetStr()[nxt_idx] != '\n'); + nxt_idx++) + { + if ( next_nonempty_line < 0 + && !unc_isspace(pc->GetStr()[nxt_idx]) + && pc->GetStr()[nxt_idx] != '*' + && (pc->TestFlags(PCF_IN_PREPROC) + ? ( pc->GetStr()[nxt_idx] != '\\' + || ( pc->GetStr()[nxt_idx + 1] != '\r' + && pc->GetStr()[nxt_idx + 1] != '\n')) + : true)) + { + next_nonempty_line = nxt_idx; // first non-whitespace char in the next line + } + } + + if ( options::cmt_reflow_indent_to_paragraph_start() + && next_nonempty_line >= 0 + && ( prev_nonempty_line <= 0 + || doxygen_javadoc_indent_align)) + { + log_rule_B("cmt_reflow_indent_to_paragraph_start"); + + int cmt_star_indent = 0; + + while ( next_nonempty_line > cmt_star_indent + && pc->GetStr()[next_nonempty_line - cmt_star_indent - 1] != '*') + { + ++cmt_star_indent; + } + reflow_paragraph_continuation_indent = size_t(cmt_star_indent); + } + + /* + * see if we should fold up; usually that'd be a YES, but there are a few + * situations where folding/reflowing by merging lines is frowned upon: + * + * - ASCII art in the comments (most often, these are drawings done in +-\/|.,*) + * + * - Doxygen/JavaDoc/etc. parameters: these often start with \ or @, at least + * something clearly non-alphanumeric (you see where we're going with this?) + * + * - bullet lists that are closely spaced: bullets are always non-alphanumeric + * characters, such as '-' or '+' (or, oh horror, '*' - that's bloody ambiguous + * to parse :-( ... with or without '*' comment start prefix, that's the + * question, then.) + * + * - semi-HTML formatted code, e.g. <pre>...</pre> comment sections (NDoc, etc.) + * + * - New lines which form a new paragraph without there having been added an + * extra empty line between the last sentence and the new one. + * A bit like this, really; so it is opportune to check if the last line ended + * in a terminal (that would be the set '.:;!?') and the new line starts with + * a capital. + * Though new lines starting with comment delimiters, such as '(', should be + * pulled up. + * + * So it bores down to this: the only folding (& reflowing) that's going to happen + * is when the next line starts with an alphanumeric character AND the last + * line didn't end with an non-alphanumeric character, except: ',' AND the next + * line didn't start with a '*' all of a sudden while the previous one didn't + * (the ambiguous '*'-for-bullet case!) + */ + if ( prev_nonempty_line >= 0 + && next_nonempty_line >= int(cmt_idx)) + { + std::wstring prev_line(line.get().cbegin(), + line.get().cend()); + std::wstring next_line(pc->GetStr().get().cbegin() + next_nonempty_line, + pc->GetStr().get().cend()); + + for (auto &&cmt_reflow_regex_map_entry : cmt_reflow_regex_map) + { + auto &&cmt_reflow_regex_pair = cmt_reflow_regex_map_entry.second; + auto &&end_of_prev_line_regex = cmt_reflow_regex_pair.first; + auto &&beg_of_next_line_regex = cmt_reflow_regex_pair.second; + std::wsmatch match[2]; + + if ( std::regex_search(prev_line, match[0], end_of_prev_line_regex) + && match[0].position(0) + match[0].length(0) == std::wsmatch::difference_type(line.size()) + && std::regex_search(next_line, match[1], beg_of_next_line_regex) + && match[1].position(0) == 0) + { + // rewind the line to the last non-alpha: + line.resize(prev_nonempty_line + 1); + + // roll the current line forward to the first non-alpha: + cmt_idx = next_nonempty_line; + // override the NL and make it a single whitespace: + ch = ' '; + + break; + } + } + } + } + + if (ch == '\n') + { + LOG_FMT(LCONTTEXT, "%s(%d):ch is newline\n", __func__, __LINE__); + } + else + { + LOG_FMT(LCONTTEXT, "%s(%d):ch is %d, %c\n", __func__, __LINE__, ch, char(ch)); + } + line.append(ch); + + // If we just hit an end of line OR we just hit end-of-comment... + if ( ch == '\n' + || cmt_idx == pc->Len()) + { + if (ch == '\n') + { + LOG_FMT(LCONTTEXT, "%s(%d):ch is newline\n", __func__, __LINE__); + } + else + { + LOG_FMT(LCONTTEXT, "%s(%d):ch is %d, %c\n", __func__, __LINE__, ch, char(ch)); + } + line_count++; + LOG_FMT(LCONTTEXT, "%s(%d):line_count is %zu\n", __func__, __LINE__, line_count); + + // strip trailing tabs and spaces before the newline + if (ch == '\n') + { + nl_end = true; + line.pop_back(); + cmt_trim_whitespace(line, pc->TestFlags(PCF_IN_PREPROC)); + } + + if (line_count == 1) + { + // this is the first line - add unchanged + add_comment_text(line, cmt, false); + + if (nl_end) + { + add_char('\n'); + } + } + else + { + /* + * This is not the first line, so we need to indent to the + * correct column. Each line is indented 0 or more spaces. + */ + // Ensure ccol is not negative + if (static_cast<int>(ccol) >= col_diff) + { + ccol -= col_diff; + } + + if (ccol < (cmt_col + 3)) + { + ccol = cmt_col + 3; + } + + if (line.size() == 0) + { + // Empty line - just a '\n' + log_rule_B("cmt_star_cont"); + + if (options::cmt_star_cont()) + { + // The number of spaces to insert at the start of subsequent comment lines. + log_rule_B("cmt_sp_before_star_cont"); + cmt.column = cmt_col + options::cmt_sp_before_star_cont(); + cmt_output_indent(cmt.brace_col, cmt.base_col, cmt.column); + + if (cmt.xtra_indent > 0) + { + add_char(' '); + } + // multiline comments can have empty lines with some spaces in them for alignment + // while adding * symbol and aligning them we don't want to keep these trailing spaces + unc_text tmp = unc_text(cmt.cont_text); + cmt_trim_whitespace(tmp, false); + add_text(tmp); + } + add_char('\n'); + } + else + { + /* + * If this doesn't start with a '*' or '|'. + * '\name' is a common parameter documentation thing. + */ + log_rule_B("cmt_indent_multi"); + + if ( options::cmt_indent_multi() + && line[0] != '*' + && line[0] != '|' + && line[0] != '#' + && ( line[0] != '\\' + || unc_isalpha(line[1])) + && line[0] != '+') + { + // The number of spaces to insert at the start of subsequent comment lines. + log_rule_B("cmt_sp_before_star_cont"); + size_t start_col = cmt_col + options::cmt_sp_before_star_cont(); + + log_rule_B("cmt_star_cont"); + + if (options::cmt_star_cont()) + { + cmt.column = start_col; + cmt_output_indent(cmt.brace_col, cmt.base_col, cmt.column); + + if (cmt.xtra_indent > 0) + { + add_char(' '); + } + add_text(cmt.cont_text); + // The number of spaces to insert after the star on subsequent comment lines. + log_rule_B("cmt_sp_after_star_cont"); + output_to_column(ccol + options::cmt_sp_after_star_cont(), false); + } + else + { + cmt.column = ccol; + cmt_output_indent(cmt.brace_col, cmt.base_col, cmt.column); + } + } + else + { + // The number of spaces to insert at the start of subsequent comment lines. + log_rule_B("cmt_sp_before_star_cont"); + cmt.column = cmt_col + options::cmt_sp_before_star_cont(); + cmt_output_indent(cmt.brace_col, cmt.base_col, cmt.column); + + if (cmt.xtra_indent > 0) + { + add_char(' '); + } + size_t idx; + + // Checks for and updates the lead chars. + // @return 0=not present, >0=number of chars that are part of the lead + idx = cmt_parse_lead(line, (cmt_idx == pc->Len())); + + if (idx > 0) + { + // >0=number of chars that are part of the lead + cmt.cont_text.set(line, 0, idx); + LOG_CONTTEXT(); + + if ( (line.size() >= 2) + && (line[0] == '*') + && unc_isalnum(line[1])) + { + line.insert(1, ' '); + } + } + else + { + // bug #653 + if (language_is_set(LANG_D)) + { + // 0=no lead char present + add_text(cmt.cont_text); + } + } + } + size_t continuation_indent = 0; + + if (doxygen_javadoc_indent_align) + { + continuation_indent = doxygen_javadoc_continuation_indent; + } + else if (reflow_paragraph_continuation_indent > 0) + { + continuation_indent = reflow_paragraph_continuation_indent; + } + add_comment_text(line, + cmt, + false, + continuation_indent); + + if (nl_end) + { + add_text("\n"); + } + } + } + line.clear(); + doxygen_javadoc_indent_align = false; + ccol = 1; + } + } +} // output_comment_multi + + +static bool kw_fcn_filename(Chunk *cmt, unc_text &out_txt) +{ + UNUSED(cmt); + out_txt.append(path_basename(cpd.filename.c_str())); + return(true); +} + + +static bool kw_fcn_class(Chunk *cmt, unc_text &out_txt) +{ + Chunk *tmp = Chunk::NullChunkPtr; + + if (language_is_set(LANG_CPP | LANG_OC)) + { + Chunk *fcn = get_next_function(cmt); + + if ( fcn != nullptr + && fcn->Is(CT_OC_MSG_DECL)) + { + tmp = get_prev_oc_class(cmt); + } + else + { + tmp = get_next_class(cmt); + } + } + else if (language_is_set(LANG_OC)) + { + tmp = get_prev_oc_class(cmt); + } + + if (tmp->IsNullChunk()) + { + tmp = get_next_class(cmt); + } + + if (tmp->IsNotNullChunk()) + { + out_txt.append(tmp->GetStr()); + + while ((tmp = tmp->GetNext())->IsNotNullChunk()) + { + if (tmp->IsNot(CT_DC_MEMBER)) + { + break; + } + tmp = tmp->GetNext(); + + if (tmp->IsNotNullChunk()) + { + out_txt.append("::"); + out_txt.append(tmp->GetStr()); + } + } + return(true); + } + return(false); +} // kw_fcn_class + + +static bool kw_fcn_message(Chunk *cmt, unc_text &out_txt) +{ + Chunk *fcn = get_next_function(cmt); + + if (fcn == nullptr) + { + return(false); + } + out_txt.append(fcn->GetStr()); + + Chunk *tmp = fcn->GetNextNcNnl(); + Chunk *word = Chunk::NullChunkPtr; + + while (tmp->IsNotNullChunk()) + { + if ( tmp->Is(CT_BRACE_OPEN) + || tmp->Is(CT_SEMICOLON)) + { + break; + } + + if (tmp->Is(CT_OC_COLON)) + { + if (word->IsNotNullChunk()) + { + out_txt.append(word->GetStr()); + word = Chunk::NullChunkPtr; + } + out_txt.append(":"); + } + + if (tmp->Is(CT_WORD)) + { + word = tmp; + } + tmp = tmp->GetNextNcNnl(); + } + return(true); +} // kw_fcn_message + + +static bool kw_fcn_category(Chunk *cmt, unc_text &out_txt) +{ + Chunk *category = get_prev_category(cmt); + + if (category->IsNotNullChunk()) + { + out_txt.append('('); + out_txt.append(category->GetStr()); + out_txt.append(')'); + } + return(true); +} // kw_fcn_category + + +static bool kw_fcn_scope(Chunk *cmt, unc_text &out_txt) +{ + Chunk *scope = get_next_scope(cmt); + + if (scope->IsNotNullChunk()) + { + out_txt.append(scope->GetStr()); + return(true); + } + return(false); +} // kw_fcn_scope + + +static bool kw_fcn_function(Chunk *cmt, unc_text &out_txt) +{ + Chunk *fcn = get_next_function(cmt); + + if (fcn != nullptr) + { + if (fcn->GetParentType() == CT_OPERATOR) + { + out_txt.append("operator "); + } + + if (fcn->GetPrev()->GetType() == CT_DESTRUCTOR) + { + out_txt.append('~'); + } + out_txt.append(fcn->GetStr()); + return(true); + } + return(false); +} + + +static bool kw_fcn_javaparam(Chunk *cmt, unc_text &out_txt) +{ + Chunk *fcn = get_next_function(cmt); + + if (fcn == nullptr) + { + return(false); + } + Chunk *fpo; + Chunk *fpc; + bool has_param = true; + bool need_nl = false; + + if (fcn->Is(CT_OC_MSG_DECL)) + { + Chunk *tmp = fcn->GetNextNcNnl(); + has_param = false; + + while (tmp->IsNotNullChunk()) + { + if ( tmp->Is(CT_BRACE_OPEN) + || tmp->Is(CT_SEMICOLON)) + { + break; + } + + if (has_param) + { + if (need_nl) + { + out_txt.append("\n"); + } + need_nl = true; + out_txt.append("@param"); + out_txt.append(" "); + out_txt.append(tmp->GetStr()); + out_txt.append(" TODO"); + } + has_param = false; + + if (tmp->Is(CT_PAREN_CLOSE)) + { + has_param = true; + } + tmp = tmp->GetNextNcNnl(); + } + fpo = fpc = Chunk::NullChunkPtr; + } + else + { + fpo = fcn->GetNextType(CT_FPAREN_OPEN, fcn->GetLevel()); + + if (fpo->IsNullChunk()) + { + return(true); + } + fpc = fpo->GetNextType(CT_FPAREN_CLOSE, fcn->GetLevel()); + + if (fpc->IsNullChunk()) + { + return(true); + } + } + Chunk *tmp; + + // Check for 'foo()' and 'foo(void)' + if (fpo->IsNotNullChunk()) + { + if (fpo->GetNextNcNnl() == fpc) + { + has_param = false; + } + else + { + tmp = fpo->GetNextNcNnl(); + + if ( (tmp == fpc->GetPrevNcNnl()) + && tmp->IsString("void")) + { + has_param = false; + } + } + } + + if (has_param) + { + Chunk *prev = Chunk::NullChunkPtr; + tmp = fpo; + + while ((tmp = tmp->GetNext())->IsNotNullChunk()) + { + if ( tmp->Is(CT_COMMA) + || tmp == fpc) + { + if (need_nl) + { + out_txt.append("\n"); + } + need_nl = true; + out_txt.append("@param"); + + if (prev->IsNotNullChunk()) + { + out_txt.append(" "); + out_txt.append(prev->GetStr()); + out_txt.append(" TODO"); + } + prev = Chunk::NullChunkPtr; + + if (tmp == fpc) + { + break; + } + } + + if (tmp->Is(CT_WORD)) + { + prev = tmp; + } + } + } + // Do the return stuff + tmp = fcn->GetPrevNcNnl(); + + // For Objective-C we need to go to the previous chunk + if ( tmp->IsNotNullChunk() + && tmp->GetParentType() == CT_OC_MSG_DECL + && tmp->Is(CT_PAREN_CLOSE)) + { + tmp = tmp->GetPrevNcNnl(); + } + + if ( tmp->IsNotNullChunk() + && !tmp->IsString("void")) + { + if (need_nl) + { + out_txt.append("\n"); + } + out_txt.append("@return TODO"); + } + return(true); +} // kw_fcn_javaparam + + +static bool kw_fcn_fclass(Chunk *cmt, unc_text &out_txt) +{ + Chunk *fcn = get_next_function(cmt); + + if (!fcn) + { + return(false); + } + + if (fcn->TestFlags(PCF_IN_CLASS)) + { + // if inside a class, we need to find to the class name + Chunk *tmp = fcn->GetPrevType(CT_BRACE_OPEN, fcn->GetLevel() - 1); + tmp = tmp->GetPrevType(CT_CLASS, tmp->GetLevel()); + + if (tmp->IsNullChunk()) + { + tmp = Chunk::NullChunkPtr; + } + else + { + tmp = tmp->GetNextNcNnl(); + } + + while ( tmp->IsNotNullChunk() + && tmp->GetNextNcNnl()->Is(CT_DC_MEMBER)) + { + tmp = tmp->GetNextNcNnl(); + tmp = tmp->GetNextNcNnl(); + } + + if (tmp->IsNotNullChunk()) + { + out_txt.append(tmp->GetStr()); + return(true); + } + } + else + { + // if outside a class, we expect "CLASS::METHOD(...)" + Chunk *tmp = fcn->GetPrevNcNnl(); + + if (tmp->Is(CT_OPERATOR)) + { + tmp = tmp->GetPrevNcNnl(); + } + + if ( tmp->IsNotNullChunk() + && ( tmp->Is(CT_DC_MEMBER) + || tmp->Is(CT_MEMBER))) + { + tmp = tmp->GetPrevNcNnl(); + out_txt.append(tmp->GetStr()); + return(true); + } + } + return(false); +} // kw_fcn_fclass + + +static bool kw_fcn_year(Chunk *cmt, unc_text &out_txt) +{ + UNUSED(cmt); + time_t now = time(nullptr); + + out_txt.append(std::to_string(1900 + localtime(&now)->tm_year)); + return(true); +} + + +struct kw_subst_t +{ + const char *tag; + bool (*func)(Chunk *cmt, unc_text &out_txt); +}; + + +static const kw_subst_t kw_subst_table[] = +{ + { "$(filename)", kw_fcn_filename }, + { "$(class)", kw_fcn_class }, + { "$(message)", kw_fcn_message }, + { "$(category)", kw_fcn_category }, + { "$(scope)", kw_fcn_scope }, + { "$(function)", kw_fcn_function }, + { "$(javaparam)", kw_fcn_javaparam }, + { "$(fclass)", kw_fcn_fclass }, + { "$(year)", kw_fcn_year }, +}; + + +static void do_kw_subst(Chunk *pc) +{ + for (const auto &kw : kw_subst_table) + { + int idx = pc->GetStr().find(kw.tag); + + if (idx < 0) + { + continue; + } + unc_text tmp_txt; + tmp_txt.clear(); + + if (kw.func(pc, tmp_txt)) + { + // if the replacement contains '\n' we need to fix the lead + if (tmp_txt.find("\n") >= 0) + { + size_t nl_idx = pc->GetStr().rfind("\n", idx); + + if (nl_idx > 0) + { + // idx and nl_idx are both positive + unc_text nl_txt; + nl_txt.append("\n"); + nl_idx++; + + while ( (nl_idx < static_cast<size_t>(idx)) + && !unc_isalnum(pc->GetStr()[nl_idx])) + { + nl_txt.append(pc->Str()[nl_idx++]); + } + tmp_txt.replace("\n", nl_txt); + } + } + pc->Str().replace(kw.tag, tmp_txt); + } + } +} // do_kw_subst + + +static void output_comment_multi_simple(Chunk *pc) +{ + if ( pc == nullptr + && pc->IsNotNullChunk()) + { + return; + } + cmt_reflow cmt; + + LOG_FMT(LCONTTEXT, "%s(%d): Text() is '%s', type is %s, orig col is %zu, column is %zu\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType()), pc->GetOrigCol(), pc->GetColumn()); + + output_cmt_start(cmt, pc); + + // The multiline comment is saved inside one chunk. If the comment is + // shifted all lines of the comment need to be shifted by the same amount. + // Save the difference of initial and current position to apply it on every + // line_column + const int col_diff = [pc]() + { + int diff = 0; + + if (pc->GetPrev()->IsNewline()) + { + // The comment should be indented correctly + diff = pc->GetColumn() - pc->GetOrigCol(); + } + return(diff); + }(); + + /** + * check for enable/disable processing comment strings that may + * both be embedded within the same multi-line comment + */ + auto disable_processing_cmt_idx = find_disable_processing_comment_marker(pc->GetStr()); + auto enable_processing_cmt_idx = find_enable_processing_comment_marker(pc->GetStr()); + + unc_text line; + size_t line_count = 0; + size_t line_column = pc->GetColumn(); + size_t cmt_idx = 0; + + while (cmt_idx < pc->Len()) + { + int ch = pc->GetStr()[cmt_idx]; + cmt_idx++; + + if ( cmt_idx > std::size_t(disable_processing_cmt_idx) + && enable_processing_cmt_idx > disable_processing_cmt_idx) + { + auto length = enable_processing_cmt_idx - disable_processing_cmt_idx; + unc_text verbatim_text(pc->GetStr(), + disable_processing_cmt_idx, + length); + + add_text(verbatim_text); + + cmt_idx = enable_processing_cmt_idx; + + /** + * check for additional enable/disable processing comment strings that may + * both be embedded within the same multi-line comment + */ + disable_processing_cmt_idx = find_disable_processing_comment_marker(pc->GetStr(), + enable_processing_cmt_idx); + enable_processing_cmt_idx = find_enable_processing_comment_marker(pc->GetStr(), + enable_processing_cmt_idx); + + line.clear(); + + continue; + } + // 1: step through leading tabs and spaces to find the start column + log_rule_B("cmt_convert_tab_to_spaces"); + + if ( line.size() == 0 + && ( line_column < cmt.base_col + || options::cmt_convert_tab_to_spaces())) + { + if (ch == ' ') + { + line_column++; + continue; + } + else if (ch == '\t') + { + log_rule_B("input_tab_size"); + line_column = calc_next_tab_column(line_column, options::input_tab_size()); + continue; + } + else + { + LOG_FMT(LCONTTEXT, "%s(%d):ch is %d, %c\n", __func__, __LINE__, ch, char(ch)); + } + } + + // 2: add chars to line, handle the CRLF and CR endings (convert both to LF) + if (ch == '\r') + { + ch = '\n'; + + if ( (cmt_idx < pc->Len()) + && (pc->GetStr()[cmt_idx] == '\n')) + { + cmt_idx++; + } + } + LOG_FMT(LCONTTEXT, "%s(%d):Line is %s\n", __func__, __LINE__, line.c_str()); + line.append(ch); + LOG_FMT(LCONTTEXT, "%s(%d):Line is %s\n", __func__, __LINE__, line.c_str()); + + // If we just hit an end of line OR we just hit end-of-comment... + if ( ch == '\n' + || cmt_idx == pc->Len()) + { + line_count++; + LOG_FMT(LCONTTEXT, "%s(%d):line_count is %zu\n", __func__, __LINE__, line_count); + + // strip trailing tabs and spaces before the newline + if (ch == '\n') + { + line.pop_back(); + + // Say we aren't in a preproc to prevent changing any bs-nl + cmt_trim_whitespace(line, false); + + line.append('\n'); + } + + if (line.size() > 0) + { + // unless line contains only a single newline char, indent if the + // line consists of either: + if ( line.size() > 1 // more than a single newline char or + || ch != '\n') // (end-of-comment) a single non newline char + { + if (line_count > 1) + { + // apply comment column shift without underflowing + line_column = (col_diff<0 + && (size_t)(abs(col_diff))> line_column) + ? 0 : line_column + col_diff; + } + cmt.column = line_column; + cmt_output_indent(cmt.brace_col, cmt.base_col, cmt.column); + } + add_text(line); + + line.clear(); + } + line_column = 1; + } + } +} // output_comment_multi_simple + + +static void generate_if_conditional_as_text(unc_text &dst, Chunk *ifdef) +{ + int column = -1; + + dst.clear(); + + for (Chunk *pc = ifdef; pc != nullptr && pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if (column == -1) + { + column = pc->GetColumn(); + } + + if ( pc->Is(CT_NEWLINE) + || pc->Is(CT_COMMENT_MULTI) + || pc->Is(CT_COMMENT_CPP)) + { + break; + } + else if (pc->Is(CT_NL_CONT)) + { + dst += ' '; + column = -1; + } + else if ( pc->Is(CT_COMMENT) + || pc->Is(CT_COMMENT_EMBED)) + { + } + else // if (pc->Is(CT_JUNK)) || else + { + for (int spacing = pc->GetColumn() - column; spacing > 0; spacing--) + { + dst += ' '; + column++; + } + + dst.append(pc->GetStr()); + column += pc->Len(); + } + } +} // generate_if_conditional_as_text + + +void add_long_preprocessor_conditional_block_comment() +{ + Chunk *pp_start = nullptr; + Chunk *pp_end = nullptr; + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + // just track the preproc level: + if (pc->Is(CT_PREPROC)) + { + pp_end = pp_start = pc; + } + + if ( pc->IsNot(CT_PP_IF) + || !pp_start) + { + continue; + } +#if 0 + if (pc->TestFlags(PCF_IN_PREPROC)) + { + continue; + } +#endif + + Chunk *br_close; + Chunk *br_open = pc; + size_t nl_count = 0; + + Chunk *tmp = pc; + + while ((tmp = tmp->GetNext())->IsNotNullChunk()) + { + // just track the preproc level: + if (tmp->Is(CT_PREPROC)) + { + pp_end = tmp; + } + + if (tmp->IsNewline()) + { + nl_count += tmp->GetNlCount(); + } + else if ( pp_end->GetPpLevel() == pp_start->GetPpLevel() + && ( tmp->Is(CT_PP_ENDIF) + || ((br_open->Is(CT_PP_IF)) ? (tmp->Is(CT_PP_ELSE)) : 0))) + { + br_close = tmp; + + LOG_FMT(LPPIF, "found #if / %s section on lines %zu and %zu, new line count=%zu\n", + (tmp->Is(CT_PP_ENDIF) ? "#endif" : "#else"), + br_open->GetOrigLine(), br_close->GetOrigLine(), nl_count); + + // Found the matching #else or #endif - make sure a newline is next + tmp = tmp->GetNext(); + + LOG_FMT(LPPIF, "next item type %d (is %s)\n", + (tmp ? tmp->GetType() : -1), (tmp ? tmp->IsNewline() ? "newline" + : tmp->IsComment() ? "comment" : "other" : "---")); + + if ( tmp->IsNullChunk() + || tmp->Is(CT_NEWLINE)) // tmp->IsNewline()) + { + size_t nl_min; + + if (br_close->Is(CT_PP_ENDIF)) + { + log_rule_B("mod_add_long_ifdef_endif_comment"); + nl_min = options::mod_add_long_ifdef_endif_comment(); + } + else + { + log_rule_B("mod_add_long_ifdef_else_comment"); + nl_min = options::mod_add_long_ifdef_else_comment(); + } + const char *txt = !tmp ? "EOF" : ((tmp->Is(CT_PP_ENDIF)) ? "#endif" : "#else"); + LOG_FMT(LPPIF, "#if / %s section candidate for augmenting when over NL threshold %zu != 0 (new line count=%zu)\n", + txt, nl_min, nl_count); + + if ( nl_min > 0 + && nl_count > nl_min) // nl_count is 1 too large at all times as #if line was counted too + { + // determine the added comment style + E_Token style = (language_is_set(LANG_CPP)) ? + CT_COMMENT_CPP : CT_COMMENT; + + unc_text str; + generate_if_conditional_as_text(str, br_open); + + LOG_FMT(LPPIF, "#if / %s section over threshold %zu (new line count=%zu) --> insert comment after the %s: %s\n", + txt, nl_min, nl_count, txt, str.c_str()); + + // Add a comment after the close brace + insert_comment_after(br_close, style, str); + } + } + + // checks both the #else and #endif for a given level, only then look further in the main loop + if (br_close->Is(CT_PP_ENDIF)) + { + break; + } + } + } + } +} // add_long_preprocessor_conditional_block_comment diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/output.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/output.h new file mode 100644 index 00000000..f3f6026e --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/output.h @@ -0,0 +1,50 @@ +/** + * @file output.h + * prototypes for output.c + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef OUTPUT_H_INCLUDED +#define OUTPUT_H_INCLUDED + +#include "unc_text.h" + +#include <stdio.h> + + +//! This renders the chunk list to a file. +void output_parsed(FILE *pfile, bool withOptions = true); + + +//! This renders the chunk list to a file formatted as csv. +void output_parsed_csv(FILE *pfile); + + +//! This renders the chunk list to a file. +void output_text(FILE *pfile); + + +//! This save the next formatting step to a file +void dump_step(const char *filename, const char *description); + + +/** + * See also it's preprocessor counterpart + * add_long_closebrace_comment + * in braces.cpp + * + * Note: since this concerns itself with the preprocessor -- which is line-oriented -- + * it turns out that just looking at pc->GetPpLevel() is NOT the right thing to do. + * See a --parsed dump if you don't believe this: an '#endif' will be one level + * UP from the corresponding #ifdef when you look at the tokens 'ifdef' versus 'endif', + * but it's a whole another story when you look at their CT_PREPROC ('#') tokens! + * + * Hence we need to track and seek matching CT_PREPROC pp_levels here, which complicates + * things a little bit, but not much. + */ +void add_long_preprocessor_conditional_block_comment(); + + +#endif /* OUTPUT_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parameter_pack_cleanup.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parameter_pack_cleanup.cpp new file mode 100644 index 00000000..12992ff3 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parameter_pack_cleanup.cpp @@ -0,0 +1,65 @@ +/** + * @file parameter_pack_cleanup.cpp + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#include "parameter_pack_cleanup.h" + +#include "chunk.h" +#include "uncrustify.h" + + +void parameter_pack_cleanup() +{ + LOG_FUNC_ENTRY(); + + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + LOG_CHUNK(LTOK, pc); + + // look for template + if (pc->Is(CT_TEMPLATE)) // Issue #3309 + { + Chunk *template_end = pc->GetNextType(CT_SEMICOLON, pc->GetLevel()); + + // look for a parameter pack + while (pc->IsNotNullChunk()) + { + LOG_CHUNK(LTOK, pc); + + if (pc->Is(CT_PARAMETER_PACK)) + { + Chunk *parameter_pack = pc; + + // look for a token with the same text + while (pc->IsNotNullChunk()) + { + LOG_CHUNK(LTOK, pc); + + if (pc == template_end) + { + break; + } + + if (strcmp(pc->Text(), parameter_pack->Text()) == 0) + { + pc->SetType(CT_PARAMETER_PACK); + } + pc = pc->GetNext(); + } + } + pc = pc->GetNext(); + + if (pc == template_end) + { + break; + } + } + } + pc = pc->GetNext(); + } +} // parameter_pack_cleanup diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parameter_pack_cleanup.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parameter_pack_cleanup.h new file mode 100644 index 00000000..e3aa31ac --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parameter_pack_cleanup.h @@ -0,0 +1,15 @@ +/** + * @file parameter_pack_cleanup.h + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#ifndef PARAMETER_PACK_CLEANUP_H_INCLUDED +#define PARAMETER_PACK_CLEANUP_H_INCLUDED + +#include "uncrustify_types.h" + +void parameter_pack_cleanup(); + +#endif /* PARAMETER_PACK_CLEANUP_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parens.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parens.cpp new file mode 100644 index 00000000..67d75a6e --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parens.cpp @@ -0,0 +1,349 @@ +/** + * @file parens.cpp + * Adds or removes parens. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "parens.h" + +#include "log_rules.h" + +using namespace uncrustify; + + +//! Add an open parenthesis after first and add a close parenthesis before the last +static void add_parens_between(Chunk *first, Chunk *last); + + +/** + * Scans between two parens and adds additional parens if needed. + * This function is recursive. If it hits another open paren, it'll call itself + * with the new bounds. + * + * Adds optional parens in an IF or SWITCH conditional statement. + * + * This basically just checks for a CT_COMPARE that isn't surrounded by parens. + * The edges for the compare are the open, close and any CT_BOOL tokens. + * + * This only handles VERY simple patterns: + * (!a && b) => (!a && b) -- no change + * (a && b == 1) => (a && (b == 1)) + * (a == 1 || b > 2) => ((a == 1) || (b > 2)) + * + * FIXME: we really should bail if we transition between a preprocessor and + * a non-preprocessor + */ +static void check_bool_parens(Chunk *popen, Chunk *pclose, int nest); + + +void do_parens() +{ + constexpr static auto LCURRENT = LPARADD; + + LOG_FUNC_ENTRY(); + + log_rule_B("mod_full_paren_if_bool"); + + if (options::mod_full_paren_if_bool()) + { + Chunk *pc = Chunk::GetHead(); + + while ( (pc = pc->GetNextNcNnl()) != nullptr + && pc->IsNotNullChunk()) + { + if ( pc->IsNot(CT_SPAREN_OPEN) + || ( pc->GetParentType() != CT_IF + && pc->GetParentType() != CT_ELSEIF + && pc->GetParentType() != CT_SWITCH)) + { + continue; + } + // Grab the close sparen + Chunk *pclose = pc->GetNextType(CT_SPAREN_CLOSE, pc->GetLevel(), E_Scope::PREPROC); + + if (pclose->IsNotNullChunk()) + { + check_bool_parens(pc, pclose, 0); + pc = pclose; + } + } + } +} // do_parens + + +void do_parens_assign() // Issue #3316 +{ + constexpr static auto LCURRENT = LPARADD; + + LOG_FUNC_ENTRY(); + + log_rule_B("mod_full_paren_assign_bool"); + + if (options::mod_full_paren_assign_bool()) + { + Chunk *pc = Chunk::GetHead(); + + while ( (pc = pc->GetNextNcNnl()) != nullptr + && pc->IsNotNullChunk()) + { + if (pc->Is(CT_ASSIGN)) + { + LOG_FMT(LPARADD, "%s(%d): orig line is %zu, text is '%s', level is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->Text(), pc->GetLevel()); + // look before for a open sparen + size_t check_level = pc->GetLevel(); + Chunk *p = pc->GetPrevNc(E_Scope::PREPROC); + + while (p->IsNotNullChunk()) + { + LOG_FMT(LPARADD, "%s(%d): orig line is %zu, text is '%s', level is %zu, type is %s\n", + __func__, __LINE__, p->GetOrigLine(), p->Text(), p->GetLevel(), get_token_name(p->GetType())); + + //log_pcf_flags(LPARADD, p->GetFlags()); + if (p->TestFlags(PCF_STMT_START)) + { + break; + } + + if (p->Is(CT_PAREN_OPEN)) + { + check_level--; + } + + if (p->Is(CT_SPAREN_OPEN)) + { + break; + } + p = p->GetPrevNc(E_Scope::PREPROC); + + if (p->GetLevel() < check_level - 1) + { + break; + } + } + LOG_FMT(LPARADD, "%s(%d): orig line is %zu, text is '%s', level is %zu, type is %s\n", + __func__, __LINE__, p->GetOrigLine(), p->Text(), p->GetLevel(), get_token_name(p->GetType())); + + if (p->GetParentType() == CT_WHILE) + { + continue; + } + // Grab the semicolon + Chunk *semicolon = pc->GetNextType(CT_SEMICOLON, pc->GetLevel(), E_Scope::PREPROC); + + if (semicolon->IsNotNullChunk()) + { + check_bool_parens(pc, semicolon, 0); + pc = semicolon; + } + } + } + } +} // do_parens_assign + + +void do_parens_return() // Issue #3316 +{ + constexpr static auto LCURRENT = LPARADD; + + LOG_FUNC_ENTRY(); + + log_rule_B("mod_full_paren_return_bool"); + + if (options::mod_full_paren_return_bool()) + { + Chunk *pc = Chunk::GetHead(); + + while ( (pc = pc->GetNextNcNnl()) != nullptr + && pc->IsNotNullChunk()) + { + if (pc->Is(CT_RETURN)) + { + LOG_FMT(LPARADD, "%s(%d): orig line is %zu, text is '%s', level is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->Text(), pc->GetLevel()); + // look before for a open sparen + size_t check_level = pc->GetLevel(); + Chunk *p = pc->GetPrevNc(E_Scope::PREPROC); + + while (p->IsNotNullChunk()) + { + LOG_FMT(LPARADD, "%s(%d): orig line is %zu, text is '%s', level is %zu, type is %s\n", + __func__, __LINE__, p->GetOrigLine(), p->Text(), p->GetLevel(), get_token_name(p->GetType())); + + //log_pcf_flags(LPARADD, p->GetFlags()); + if (p->TestFlags(PCF_STMT_START)) + { + break; + } + + if (p->Is(CT_PAREN_OPEN)) + { + check_level--; + } + + if (p->Is(CT_SPAREN_OPEN)) + { + break; + } + p = p->GetPrevNc(E_Scope::PREPROC); + + if (p->GetLevel() < check_level - 1) + { + break; + } + } + LOG_FMT(LPARADD, "%s(%d): orig line is %zu, text is '%s', level is %zu, type is %s\n", + __func__, __LINE__, p->GetOrigLine(), p->Text(), p->GetLevel(), get_token_name(p->GetType())); + + if (p->GetParentType() == CT_WHILE) + { + continue; + } + // Grab the semicolon + Chunk *semicolon = pc->GetNextType(CT_SEMICOLON, pc->GetLevel(), E_Scope::PREPROC); + + if (semicolon->IsNotNullChunk()) + { + check_bool_parens(pc, semicolon, 0); + pc = semicolon; + } + } + } + } +} // do_parens_return + + +static void add_parens_between(Chunk *first, Chunk *last) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LPARADD, "%s(%d): line %zu, between '%s' [lvl is %zu] and '%s' [lvl is %zu]\n", + __func__, __LINE__, first->GetOrigLine(), + first->Text(), first->GetLevel(), + last->Text(), last->GetLevel()); + + // Don't do anything if we have a bad sequence, ie "&& )" + Chunk *first_n = first->GetNextNcNnl(); + + if (first_n == last) + { + return; + } + Chunk pc; + + pc.SetType(CT_PAREN_OPEN); + pc.SetOrigLine(first_n->GetOrigLine()); + pc.SetOrigCol(first_n->GetOrigCol()); + pc.Str() = "("; + pc.SetFlags(first_n->GetFlags() & PCF_COPY_FLAGS); + pc.SetLevel(first_n->GetLevel()); + pc.SetPpLevel(first_n->GetPpLevel()); + pc.SetBraceLevel(first_n->GetBraceLevel()); + + pc.CopyAndAddBefore(first_n); + + Chunk *last_p = last->GetPrevNcNnl(E_Scope::PREPROC); + + pc.SetType(CT_PAREN_CLOSE); + pc.SetOrigLine(last_p->GetOrigLine()); + pc.SetOrigCol(last_p->GetOrigCol()); + pc.Str() = ")"; + pc.SetFlags(last_p->GetFlags() & PCF_COPY_FLAGS); + pc.SetLevel(last_p->GetLevel()); + pc.SetPpLevel(last_p->GetPpLevel()); + pc.SetBraceLevel(last_p->GetBraceLevel()); + + pc.CopyAndAddAfter(last_p); + + for (Chunk *tmp = first_n; + tmp != last_p; + tmp = tmp->GetNextNcNnl()) + { + tmp->SetLevel(tmp->GetLevel() + 1); + } + + last_p->SetLevel(last_p->GetLevel() + 1); +} // add_parens_between + + +static void check_bool_parens(Chunk *popen, Chunk *pclose, int nest) +{ + LOG_FUNC_ENTRY(); + + Chunk *ref = popen; + bool hit_compare = false; + + LOG_FMT(LPARADD, "%s(%d): nest is %d, popen on line %zu, orig col is %zu, pclose on line %zu, orig col is %zu, level is %zu\n", + __func__, __LINE__, nest, + popen->GetOrigLine(), popen->GetOrigCol(), + pclose->GetOrigLine(), pclose->GetOrigCol(), + popen->GetLevel()); + + Chunk *pc = popen; + + while ( (pc = pc->GetNextNcNnl()) != nullptr + && pc->IsNotNullChunk() + && pc != pclose) + { + if (pc->TestFlags(PCF_IN_PREPROC)) + { + LOG_FMT(LPARADD2, " -- bail on PP %s [%s] at line %zu col %zu, level %zu\n", + get_token_name(pc->GetType()), + pc->Text(), pc->GetOrigLine(), pc->GetOrigCol(), pc->GetLevel()); + return; + } + + if ( pc->Is(CT_BOOL) + || pc->Is(CT_QUESTION) + || pc->Is(CT_COND_COLON) + || pc->Is(CT_COMMA)) + { + LOG_FMT(LPARADD2, " -- %s [%s] at line %zu col %zu, level %zu\n", + get_token_name(pc->GetType()), + pc->Text(), pc->GetOrigLine(), pc->GetOrigCol(), pc->GetLevel()); + + if (hit_compare) + { + hit_compare = false; + + if (!language_is_set(LANG_CS)) + { + add_parens_between(ref, pc); + } + } + ref = pc; + } + else if (pc->Is(CT_COMPARE)) + { + LOG_FMT(LPARADD2, " -- compare '%s' at line %zu, orig col is %zu, level is %zu\n", + pc->Text(), pc->GetOrigLine(), pc->GetOrigCol(), pc->GetLevel()); + hit_compare = true; + } + else if (pc->IsParenOpen()) + { + Chunk *next = pc->GetClosingParen(); + + if (next->IsNotNullChunk()) + { + check_bool_parens(pc, next, nest + 1); + pc = next; + } + } + else if ( pc->Is(CT_BRACE_OPEN) + || pc->Is(CT_SQUARE_OPEN) + || pc->Is(CT_ANGLE_OPEN)) + { + // Skip [], {}, and <> + pc = pc->GetClosingParen(); + } + } + + if ( hit_compare + && ref != popen + && !language_is_set(LANG_CS)) + { + add_parens_between(ref, pclose); + } +} // check_bool_parens diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parens.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parens.h new file mode 100644 index 00000000..cfcb9501 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parens.h @@ -0,0 +1,24 @@ +/** + * @file parens.h + * prototypes for parens.c + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef PARENS_H_INCLUDED +#define PARENS_H_INCLUDED + +#include "uncrustify_types.h" + + +//! add parenthesis +void do_parens(); + + +void do_parens_assign(); + + +void do_parens_return(); + + +#endif /* PARENS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parent_for_pp.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parent_for_pp.cpp new file mode 100644 index 00000000..f731b9f7 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parent_for_pp.cpp @@ -0,0 +1,54 @@ +/** + * @file parent_for_pp.cpp + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#include "parent_for_pp.h" + +#include "chunk.h" + + +void do_parent_for_pp() +{ + LOG_FUNC_ENTRY(); + + vector<Chunk *> viz; + + Chunk *pc = Chunk::GetHead()->GetNextNcNnl(); + + while (pc->IsNotNullChunk()) + { + // CT_PP_IF, // #if, #ifdef, or #ifndef + // CT_PP_ELSE, // #else or #elif + // CT_PP_ENDIF, // #endif + if (pc->Is(CT_PP_IF)) + { + LOG_FMT(LMCB, "%s(%d): IF: orig line %zu, orig col is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_pcf_flags(LMCB, pc->GetFlags()); + viz.push_back(pc); + } + else if (pc->Is(CT_PP_ELSE)) + { + LOG_FMT(LMCB, "%s(%d): ELSE: orig line %zu, orig col is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_pcf_flags(LMCB, pc->GetFlags()); + size_t level = pc->GetPpLevel(); + Chunk *a = viz.at(level - 1); + pc->SetParent(a); + } + else if (pc->Is(CT_PP_ENDIF)) + { + LOG_FMT(LMCB, "%s(%d): ENDIF: orig line %zu, orig col is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_pcf_flags(LMCB, pc->GetFlags()); + size_t level = pc->GetPpLevel(); + Chunk *a = viz.at(level); + pc->SetParent(a); + viz.pop_back(); + } + pc = pc->GetNextNcNnl(); + } +} // do_parent_for_pp diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parent_for_pp.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parent_for_pp.h new file mode 100644 index 00000000..7e77700a --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/parent_for_pp.h @@ -0,0 +1,17 @@ +/** + * @file parent_for_pp.h + * prototype for parent_for_pp.cpp + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#ifndef PARENT_FOR_PP_H_INCLUDED +#define PARENT_FOR_PP_H_INCLUDED + + +// mark the parent +void do_parent_for_pp(); + + +#endif /* PARENT_FOR_PP_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/pcf_flags.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/pcf_flags.cpp new file mode 100644 index 00000000..da0a9461 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/pcf_flags.cpp @@ -0,0 +1,108 @@ +/** + * @file pcf_flags.cpp + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#include "pcf_flags.h" + +static const char *pcf_names[] = +{ + "IN_PREPROC", // 0 + "IN_STRUCT", // 1 + "IN_ENUM", // 2 + "IN_FCN_DEF", // 3 + "IN_FCN_CALL", // 4 + "IN_SPAREN", // 5 + "IN_TEMPLATE", // 6 + "IN_TYPEDEF", // 7 + "IN_CONST_ARGS", // 8 + "IN_ARRAY_ASSIGN", // 9 + "IN_CLASS", // 10 + "IN_CLASS_BASE", // 11 + "IN_NAMESPACE", // 12 + "IN_FOR", // 13 + "IN_OC_MSG", // 14 + "IN_WHERE_SPEC", // 15 + "IN_DECLTYPE", // 16 + "FORCE_SPACE", // 17 + "STMT_START", // 18 + "EXPR_START", // 19 + "DONT_INDENT", // 20 + "ALIGN_START", // 21 + "WAS_ALIGNED", // 22 + "VAR_TYPE", // 23 + "VAR_DEF", // 24 + "VAR_1ST", // 25 + "VAR_INLINE", // 26 + "RIGHT_COMMENT", // 27 + "OLD_FCN_PARAMS", // 28 + "LVALUE", // 29 + "ONE_LINER", // 30 + "EMPTY_BODY", // 31 + "ANCHOR", // 32 + "PUNCTUATOR", // 33 + "INSERTED", // 34 + "LONG_BLOCK", // 35 + "OC_BOXED", // 36 + "KEEP_BRACE", // 37 + "OC_RTYPE", // 38 + "OC_ATYPE", // 39 + "WF_ENDIF", // 40 + "IN_QT_MACRO", // 41 + "IN_FCN_CTOR", // 42 Issue #2152 + "IN_TRY_BLOCK", // 43 Issue #1734 + "INCOMPLETE", // 44 + "IN_LAMBDA", // 45 + "WF_IF", // 46 + "NOT_POSSIBLE", // 47 + "IN_CONDITIONAL", // 48 Issue #3558 + "PCF_OC_IN_BLOCK", // 49 +}; + + +std::string pcf_flags_str(T_PcfFlags flags) +{ + char buffer[64]; + + // Generate hex representation first +#ifdef WIN32 + snprintf(buffer, 63, "["); +#else // not WIN32 + snprintf(buffer, 63, "[0x%llx:", (long long unsigned int)(flags)); +#endif // ifdef WIN32 + + // Add human-readable names + auto out = std::string{ buffer }; + auto first = true; + + for (size_t i = 0; i < ARRAY_SIZE(pcf_names); ++i) + { + if (flags & static_cast<E_PcfFlag>(pcf_bit(i))) + { + if (first) + { + first = false; + } + else + { + out += ','; + } + out += pcf_names[i]; + } + } + + out += ']'; + return(out); +} + + +void log_pcf_flags(log_sev_t sev, T_PcfFlags flags) +{ + if (!log_sev_on(sev)) + { + return; + } + log_fmt(sev, "%s\n", pcf_flags_str(flags).c_str()); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/pcf_flags.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/pcf_flags.h new file mode 100644 index 00000000..02e0b57c --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/pcf_flags.h @@ -0,0 +1,98 @@ +/** + * @file pcf_flags.h + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#ifndef PCF_FLAGS_STR_INCLUDED +#define PCF_FLAGS_STR_INCLUDED + +#include "enum_flags.h" +#include "logger.h" + +// and the ever-so-important array size macro +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +using namespace std; + + +constexpr auto pcf_bit(size_t b) -> decltype(0ULL) +{ + return(1ULL << b); +} + +enum E_PcfFlag : decltype ( 0ULL ) +{ +// Copy flags are in the lower 17 bits + PCF_NONE = 0ULL, + PCF_COPY_FLAGS = 0x0001ffffULL, + PCF_IN_PREPROC = pcf_bit(0), //! in a preprocessor + PCF_IN_STRUCT = pcf_bit(1), //! in a struct + PCF_IN_ENUM = pcf_bit(2), //! in enum + PCF_IN_FCN_DEF = pcf_bit(3), //! inside function def parens + PCF_IN_FCN_CALL = pcf_bit(4), //! inside function call parens + PCF_IN_SPAREN = pcf_bit(5), //! inside for/if/while/switch parens + PCF_IN_TEMPLATE = pcf_bit(6), + PCF_IN_TYPEDEF = pcf_bit(7), + PCF_IN_CONST_ARGS = pcf_bit(8), + PCF_IN_ARRAY_ASSIGN = pcf_bit(9), + PCF_IN_CLASS = pcf_bit(10), + PCF_IN_CLASS_BASE = pcf_bit(11), + PCF_IN_NAMESPACE = pcf_bit(12), + PCF_IN_FOR = pcf_bit(13), + PCF_IN_OC_MSG = pcf_bit(14), + PCF_IN_WHERE_SPEC = pcf_bit(15), /* inside C# 'where' constraint clause on class or function def */ + PCF_IN_DECLTYPE = pcf_bit(16), + +// Non-Copy flags are in the upper 47 bits + PCF_FORCE_SPACE = pcf_bit(17), //! must have a space after this token + PCF_STMT_START = pcf_bit(18), //! marks the start of a statement + PCF_EXPR_START = pcf_bit(19), + PCF_DONT_INDENT = pcf_bit(20), //! already aligned! + PCF_ALIGN_START = pcf_bit(21), + PCF_WAS_ALIGNED = pcf_bit(22), + PCF_VAR_TYPE = pcf_bit(23), //! part of a variable def type + PCF_VAR_DEF = pcf_bit(24), //! variable name in a variable def + PCF_VAR_1ST = pcf_bit(25), //! 1st variable def in a statement + PCF_VAR_1ST_DEF = (PCF_VAR_DEF | PCF_VAR_1ST), + PCF_VAR_INLINE = pcf_bit(26), //! type was an inline struct/enum/union + PCF_RIGHT_COMMENT = pcf_bit(27), + PCF_OLD_FCN_PARAMS = pcf_bit(28), + PCF_LVALUE = pcf_bit(29), //! left of assignment + PCF_ONE_LINER = pcf_bit(30), + PCF_ONE_CLASS = (PCF_ONE_LINER | PCF_IN_CLASS), + PCF_EMPTY_BODY = pcf_bit(31), + PCF_ANCHOR = pcf_bit(32), //! aligning anchor + PCF_PUNCTUATOR = pcf_bit(33), + PCF_INSERTED = pcf_bit(34), //! chunk was inserted from another file + PCF_LONG_BLOCK = pcf_bit(35), //! the block is 'long' by some measure + PCF_OC_BOXED = pcf_bit(36), //! inside OC boxed expression + PCF_KEEP_BRACE = pcf_bit(37), //! do not remove brace + PCF_OC_RTYPE = pcf_bit(38), //! inside OC return type + PCF_OC_ATYPE = pcf_bit(39), //! inside OC arg type + PCF_WF_ENDIF = pcf_bit(40), //! #endif for whole file ifdef + PCF_IN_QT_MACRO = pcf_bit(41), //! in a QT-macro, i.e. SIGNAL, SLOT + PCF_IN_FCN_CTOR = pcf_bit(42), //! inside function constructor + PCF_IN_TRY_BLOCK = pcf_bit(43), //! inside Function-try-block + PCF_INCOMPLETE = pcf_bit(44), //! class/struct forward declaration + PCF_IN_LAMBDA = pcf_bit(45), //! inside a lambda expression + PCF_WF_IF = pcf_bit(46), //! #if for a whole file ifdef + PCF_NOT_POSSIBLE = pcf_bit(47), //! it is not possible to make an one_liner + //! because the line would be too long + PCF_IN_CONDITIONAL = pcf_bit(48), //! inside a conditional ternary expression + PCF_OC_IN_BLOCK = pcf_bit(49), //! inside OC block function +}; + +UNC_DECLARE_FLAGS(T_PcfFlags, E_PcfFlag); +UNC_DECLARE_OPERATORS_FOR_FLAGS(T_PcfFlags); + +std::string pcf_flags_str(T_PcfFlags flags); + + +void log_pcf_flags(log_sev_t sev, T_PcfFlags flags); + + +#endif /* PCF_FLAGS_STR_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/pragma_cleanup.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/pragma_cleanup.cpp new file mode 100644 index 00000000..336a1272 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/pragma_cleanup.cpp @@ -0,0 +1,98 @@ +/** + * @file pragma_cleanup.cpp + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#include "pragma_cleanup.h" + +#include "chunk.h" +#include "unc_tools.h" + + +void pragma_cleanup() +{ + LOG_FUNC_ENTRY(); + + bool preproc_found = false; + bool pragma_found = false; + bool parameter_found = false; + + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + LOG_CHUNK(LTOK, pc); + + if (!preproc_found) + { + if (pc->Is(CT_PREPROC)) + { + LOG_FMT(LMCB, "%s(%d): PREPROC found: orig line %zu, orig col is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_pcf_flags(LMCB, pc->GetFlags()); + preproc_found = true; + } + } + else + { + if (!pragma_found) + { + if (pc->Is(CT_PP_PRAGMA)) + { + LOG_FMT(LMCB, "%s(%d): PP_PRAGMA found: orig line %zu, orig col is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_pcf_flags(LMCB, pc->GetFlags()); + pragma_found = true; + } + } + else + { + if (!parameter_found) + { + LOG_FMT(LMCB, "%s(%d): PARAMETER found: orig line %zu, orig col is %zu, Text is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + log_pcf_flags(LMCB, pc->GetFlags()); + + if (strcmp(pc->Text(), "endasm") == 0) + { + pc->SetType(CT_PP_ENDASM); + } + else if (strcmp(pc->Text(), "region") == 0) + { + pc->SetType(CT_PP_REGION); + } + //else if (strcmp(pc->Text(), "comment") == 0) + //{ + // pc->SetType(CT_PP_COMMENT); + //} + else + { + pc->SetType(CT_PP_PRAGMA); + } + parameter_found = true; + } + else + { + LOG_FMT(LMCB, "%s(%d): orig line is %zu, orig col is %zu, Text is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + + if (pc->IsNewline()) + { + // reset + preproc_found = false; + pragma_found = false; + parameter_found = false; + } + else + { + pc->SetType(CT_PP_IGNORE); + } + } + } + } + pc = pc->GetNext(); + } + //prot_the_line(__func__, __LINE__, 3, 0); +} // pragma_cleanup diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/pragma_cleanup.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/pragma_cleanup.h new file mode 100644 index 00000000..47a3a03d --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/pragma_cleanup.h @@ -0,0 +1,16 @@ +/** + * @file pragma_cleanup.h + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#ifndef PRAGMA_CLEANUP_H_INCLUDED +#define PRAGMA_CLEANUP_H_INCLUDED + + +// cleanup the pagma line(s) +void pragma_cleanup(); + + +#endif /* PRAGMA_CLEANUP_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/prototypes.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/prototypes.h new file mode 100644 index 00000000..55fe35b6 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/prototypes.h @@ -0,0 +1,64 @@ +/** + * @file prototypes.h + * Big jumble of prototypes used in Uncrustify. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef C_PARSE_PROTOTYPES_H_INCLUDED +#define C_PARSE_PROTOTYPES_H_INCLUDED + +#include "chunk.h" +#include "log_rules.h" +#include "uncrustify_types.h" + +#include <deque> +#include <string> + + +/** + * Advances to the next tab stop. + * Column 1 is the left-most column. + * + * @param col The current column + * @param tabsize The tabsize + * @return the next tabstop column + */ +static inline size_t calc_next_tab_column(size_t col, size_t tabsize) +{ + if (col == 0) + { + col = 1; + } + + if (cpd.frag_cols > 0) + { + col += cpd.frag_cols - 1; + } + col = 1 + ((((col - 1) / tabsize) + 1) * tabsize); + + if (cpd.frag_cols > 0) + { + col -= cpd.frag_cols - 1; + } + return(col); +} + + +/** + * Advances to the next tab stop for output. + * + * @param col The current column + * @return the next tabstop column + */ +static inline size_t next_tab_column(size_t col) +{ + constexpr static auto LCURRENT = LINDENT; + + log_rule_B("output_tab_size"); + return(calc_next_tab_column(col, uncrustify::options::output_tab_size())); +} + + +#endif /* C_PARSE_PROTOTYPES_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/punctuators.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/punctuators.cpp new file mode 100644 index 00000000..6c9c41f4 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/punctuators.cpp @@ -0,0 +1,85 @@ +/** + * @file punctuators.cpp + * Manages the table of punctuators. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "punctuators.h" + +//#include "log_rules.h" +#include "prototypes.h" + +#include <algorithm> + +constexpr static auto LCURRENT = LOTHER; + +using namespace std; +using namespace uncrustify; + + +/** + * + * The file "punctuator_table.h" was generated by punc.py from this file. + * If you change one of the below symbol tables, re-run punc.py. + * $ python scripts/punc.py > src/punctuator_table.h + * now automatically with CMakeLists.txt + * + * NOTE: the tables below do not need to be sorted. + */ + +#include "symbols_table.h" +// must be positioned here, after all symbolsX[], because punc_table uses them +#include "punctuator_table.h" + + +const chunk_tag_t *find_punctuator(const char *str, int lang_flags) +{ + if ( str == nullptr + || str[0] == '\0') + { + return(nullptr); + } + const auto binary_find = [](const lookup_entry_t *first, const lookup_entry_t *last, const char &value) + { + const auto tmp = std::lower_bound(first, last, value, + lookup_entry_t::comperator()); + + return((value == tmp->ch) ? tmp : nullptr); + }; + + const chunk_tag_t *match = nullptr; + const auto *parent = punc_table; //!< graph in table form, initially point at first entry + auto ch_idx = int{}; + + while ( ch_idx < 6 + && str[ch_idx] != '\0') //!< symbols6: max punc len = 6 + { + // search for next parent node in all current child nodes + parent = binary_find(parent, next(parent, parent->left_in_group), str[ch_idx]); + + if (parent == nullptr) + { + break; // no nodes found with the searched char + } + log_rule_B("enable_digraphs"); + + if ( parent->tag != nullptr + && (parent->tag->lang_flags & lang_flags) != 0 // punctuator lang and processing lang match + && ( (parent->tag->lang_flags & FLAG_DIG) == 0 // punctuator is not a di/tri-graph + || options::enable_digraphs())) // or di/tri-graph processing is enabled + { + match = parent->tag; + } + + if (parent->next_idx == 0) + { + break; // no child nodes, leaf reached + } + parent = &punc_table[parent->next_idx]; // point at the first child node + ch_idx++; + continue; + } + return(match); +} // find_punctuator diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/punctuators.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/punctuators.h new file mode 100644 index 00000000..ed4c3fa5 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/punctuators.h @@ -0,0 +1,52 @@ +/** + * @file punctuators.h + */ + +#ifndef PUNCTUATORS_H_INCLUDED +#define PUNCTUATORS_H_INCLUDED + +#include "uncrustify_types.h" + + +struct lookup_entry_t +{ + char ch; + char left_in_group; + UINT16 next_idx; + const chunk_tag_t *tag; + + struct comperator + { + static char get_char(const lookup_entry_t &v) + { + return(v.ch); + } + + + static char get_char(char t) + { + return(t); + } + + template<typename T1, typename T2> + bool operator()(T1 const &t1, T2 const &t2) + { + return(get_char(t1) < get_char(t2)); + } + }; +}; + + +/** + * Checks if the first max. 6 chars of a given string match a punctuator + * + * @param str string that will be checked, can be shorter than 6 chars + * @param lang_flags specifies from which language punctuators will be considered + * + * @retval chunk tag of the found punctuator + * @retval nullptr if nothing found + */ +const chunk_tag_t *find_punctuator(const char *str, int lang_flags); + + +#endif /* PUNCTUATORS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/quick_align_again.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/quick_align_again.cpp new file mode 100644 index 00000000..5cc8bcd6 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/quick_align_again.cpp @@ -0,0 +1,53 @@ +/** + * @file quick_align_again.cpp + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "quick_align_again.h" + +#include "align_stack.h" +#include "chunk.h" + + +void quick_align_again() +{ + LOG_FUNC_ENTRY(); + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + char copy[1000]; + LOG_FMT(LALAGAIN, "%s(%d): orig line is %zu, orig col is %zu, column is %zu, Text() '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->GetColumn(), pc->ElidedText(copy)); + + if ( pc->GetAlignmentData().next != nullptr + && pc->TestFlags(PCF_ALIGN_START)) + { + AlignStack as; + as.Start(100, 0); + as.m_right_align = pc->GetAlignmentData().right_align; + as.m_star_style = static_cast<AlignStack::StarStyle>(pc->GetAlignmentData().star_style); + as.m_amp_style = static_cast<AlignStack::StarStyle>(pc->GetAlignmentData().amp_style); + as.m_gap = pc->GetAlignmentData().gap; + + LOG_FMT(LALAGAIN, "%s(%d): pc->Text() is '%s', orig line is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine()); + as.Add(pc->GetAlignmentData().start); + pc->SetFlagBits(PCF_WAS_ALIGNED); + + for (Chunk *tmp = pc->GetAlignmentData().next; tmp != nullptr; tmp = tmp->GetAlignmentData().next) + { + tmp->SetFlagBits(PCF_WAS_ALIGNED); + as.Add(tmp->GetAlignmentData().start); + LOG_FMT(LALAGAIN, "%s(%d): => tmp->Text() is '%s', orig line is %zu\n", + __func__, __LINE__, tmp->Text(), tmp->GetOrigLine()); + } + + LOG_FMT(LALAGAIN, "\n"); + as.End(); + } + } +} // quick_align_again diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/quick_align_again.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/quick_align_again.h new file mode 100644 index 00000000..c370c612 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/quick_align_again.h @@ -0,0 +1,17 @@ +/** + * @file quick_align_again.h + * + * @author Guy Maurel + * split from align.cpp + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef QUICK_ALIGN_AGAIN_H_INCLUDED +#define QUICK_ALIGN_AGAIN_H_INCLUDED + +#include "uncrustify_types.h" + +void quick_align_again(); + +#endif /* QUICK_ALIGN_AGAIN_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/remove_duplicate_include.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/remove_duplicate_include.cpp new file mode 100644 index 00000000..e06029f1 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/remove_duplicate_include.cpp @@ -0,0 +1,94 @@ +/** + * @file remove_duplicate_include.cpp + * + * @author Guy Maurel + * October 2015, 2016 + * @license GPL v2+ + */ + +#include "remove_duplicate_include.h" + +#include "chunk.h" +#include "uncrustify.h" + +using std::vector; + + +void remove_duplicate_include() +{ + LOG_FUNC_ENTRY(); + + vector<Chunk *> includes; + + Chunk *preproc = Chunk::NullChunkPtr; + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + //LOG_FMT(LRMRETURN, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s', type is %s, parent type is %s\n", + // __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), + // get_token_name(pc->GetType()), get_token_name(pc->GetParentType())); + + if (pc->Is(CT_PREPROC)) + { + preproc = pc; + } + else if (pc->Is(CT_PP_INCLUDE)) + { + Chunk *next = pc->GetNext(); + + //LOG_FMT(LRMRETURN, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s', type is %s, parent type is %s\n", + // __func__, __LINE__, next->GetOrigLine(), next->GetOrigCol(), next->Text(), + // get_token_name(next->GetType()), get_token_name(next->GetParentType())); + if (includes.empty()) + { + includes.push_back(next); + // goto next newline + pc = next->GetNextNl(); + } + else + { + //LOG_FMT(LRMRETURN, "%s(%d): size is %zu\n", + // __func__, __LINE__, includes.size()); + // look for duplicate + auto ite = includes.end(); + + for (auto itc = includes.begin(); itc != ite; ++itc) + { + Chunk *current = *itc; + + //LOG_FMT(LRMRETURN, "%s(%d): next->Text() is '%s'\n", + // __func__, __LINE__, next->Text()); + //LOG_FMT(LRMRETURN, "%s(%d): current->Text() is '%s'\n", + // __func__, __LINE__, current->Text()); + if (std::strcmp(next->Text(), current->Text()) == 0) + { + // erase the statement + Chunk *temp = pc; + Chunk *comment = next->GetNext(); + Chunk *eol = next->GetNextNl(); + pc = preproc->GetPrev(); + Chunk::Delete(preproc); + Chunk::Delete(temp); + Chunk::Delete(next); + + if (comment != eol) + { + Chunk::Delete(comment); + } + Chunk::Delete(eol); + break; + } + else + { + // goto next newline + pc = next->GetNextNl(); + // and still look for duplicate + } + } // for (auto itc = includes.begin(); + } // if (includes.empty()) + } // else if (pc->Is(CT_PP_INCLUDE)) + // get the next token + pc = pc->GetNext(); + } +} // remove_duplicate_include diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/remove_duplicate_include.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/remove_duplicate_include.h new file mode 100644 index 00000000..c58416c2 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/remove_duplicate_include.h @@ -0,0 +1,20 @@ +/** + * @file remove_duplicate_include.h + * prototypes for remove_duplicate_include.cpp + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#ifndef REMOVE_DUPLICATE_INCLUDE_H_INCLUDED +#define REMOVE_DUPLICATE_INCLUDE_H_INCLUDED + +#include "chunk.h" + +/** + * @brief Remove duplicate include + */ +void remove_duplicate_include(); + + +#endif /* REMOVE_DUPLICATE_INCLUDE_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/remove_extra_returns.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/remove_extra_returns.cpp new file mode 100644 index 00000000..da7c9ba1 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/remove_extra_returns.cpp @@ -0,0 +1,84 @@ +/** + * @file remove_extra_returns.cpp + * + * @author Guy Maurel + * October 2015, 2016 + * @license GPL v2+ + * extract from combine.cpp + */ + +#include "remove_extra_returns.h" + +#include "chunk.h" +#include "uncrustify.h" + + +void remove_extra_returns() +{ + LOG_FUNC_ENTRY(); + + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + LOG_FMT(LRMRETURN, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s', type is %s, parent type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), + get_token_name(pc->GetType()), get_token_name(pc->GetParentType())); + + if ( pc->Is(CT_RETURN) + && !pc->TestFlags(PCF_IN_PREPROC)) + { + // we might be in a class, check it Issue #2705 + // look for a closing brace + bool remove_it = false; + Chunk *closing_brace = pc->GetNextType(CT_BRACE_CLOSE, 1); + LOG_FMT(LRMRETURN, "%s(%d): on orig line %zu, level is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetLevel()); + + if (closing_brace->IsNotNullChunk()) + { + if (closing_brace->GetParentType() == CT_FUNC_CLASS_DEF) + { + // we have a class. Do nothing + } + else if ( closing_brace->GetParentType() == CT_FUNC_DEF + && pc->GetLevel() < 2) + { + remove_it = true; + } + } + else + { + // it is not a class + // look for a closing brace + closing_brace = pc->GetNextType(CT_BRACE_CLOSE, 0); + LOG_FMT(LRMRETURN, "%s(%d): on orig line %zu, level is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetLevel()); + + if (closing_brace->IsNotNullChunk()) + { + if (closing_brace->GetParentType() == CT_FUNC_DEF) + { + remove_it = true; + } + } + } + + if (remove_it) + { + Chunk *semicolon = pc->GetNextNcNnl(); + + if ( semicolon->IsNotNullChunk() + && semicolon->Is(CT_SEMICOLON)) + { + LOG_FMT(LRMRETURN, "%s(%d): Removed 'return;' on orig line %zu\n", + __func__, __LINE__, pc->GetOrigLine()); + Chunk::Delete(pc); + Chunk::Delete(semicolon); + pc = closing_brace; + } + } + } + pc = pc->GetNext(); + } +} // remove_extra_returns diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/remove_extra_returns.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/remove_extra_returns.h new file mode 100644 index 00000000..85fc6429 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/remove_extra_returns.h @@ -0,0 +1,21 @@ +/** + * @file remove_extra_returns.h + * prototypes for remove_extra_returns.cpp + * + * @author Guy Maurel + * @license GPL v2+ + * extract from combine.h + */ + +#ifndef REMOVE_EXTRA_RETURNS_H_INCLUDED +#define REMOVE_EXTRA_RETURNS_H_INCLUDED + + +/** + * @brief Remove unnecessary returns + * that is remove 'return;' that appears as the last statement in a function + */ +void remove_extra_returns(); + + +#endif /* REMOVE_EXTRA_RETURNS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/rewrite_infinite_loops.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/rewrite_infinite_loops.cpp new file mode 100644 index 00000000..6b97ea7d --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/rewrite_infinite_loops.cpp @@ -0,0 +1,345 @@ +/** + * @file rewrite_infinite_loops.cpp + * + * @author Alex Henrie + * @license GPL v2+ + */ + +#include "rewrite_infinite_loops.h" + +#include "chunk.h" +#include "newlines.h" +#include "uncrustify.h" + + +using namespace uncrustify; + + +static bool for_needs_rewrite(Chunk *pc, E_Token desired_type) +{ + // The 'for' statement needs to be rewritten if `for(;;)` is not the + // preferred syntax for infinite loops and this 'for' is an infinite loop + // with no extra tokens (such as inline comments). + + if (desired_type == CT_FOR) + { + return(false); + } + pc = pc->GetNext(); + + if (!pc->Is(CT_SPAREN_OPEN)) + { + return(false); + } + pc = pc->GetNext(); + + if (!pc->Is(CT_SEMICOLON)) + { + return(false); + } + pc = pc->GetNext(); + + if (!pc->Is(CT_SEMICOLON)) + { + return(false); + } + pc = pc->GetNext(); + + if (!pc->Is(CT_SPAREN_CLOSE)) + { + return(false); + } + return(true); +} + + +static bool while_needs_rewrite(Chunk *keyword, E_Token desired_type, const char *desired_condition) +{ + // The 'while' statement needs to be rewritten if it has only the tokens that + // are strictly necessary (keyword, condition, two parentheses, and semicolon + // if do-while) and either the keyword or the condition needs to be changed. + + Chunk *oparen = keyword->GetNext(); + Chunk *condition = oparen->GetNext(); + Chunk *cparen = condition->GetNext(); + + if (!oparen->Is(CT_SPAREN_OPEN)) + { + return(false); + } + + if ( strcmp(condition->Text(), "true") != 0 + && strcmp(condition->Text(), "1") != 0) + { + return(false); + } + + if (!cparen->Is(CT_SPAREN_CLOSE)) + { + return(false); + } + + if (keyword->Is(CT_WHILE_OF_DO)) + { + Chunk *semicolon = cparen->GetNext(); + + if (!semicolon->Is(CT_SEMICOLON)) + { + return(false); + } + } + + if (!keyword->Is(desired_type)) + { + return(true); + } + + if ( strcmp(condition->Text(), "true") == 0 + && strcmp(desired_condition, "true") != 0) + { + return(true); + } + + if ( strcmp(condition->Text(), "1") == 0 + && strcmp(desired_condition, "1") != 0) + { + return(true); + } + return(false); +} // while_needs_rewrite + + +void rewrite_loop_keyword(Chunk *keyword, E_Token new_type) +{ + keyword->SetType(new_type); + + switch (new_type) + { + case CT_DO: + keyword->SetOrigColEnd(keyword->GetOrigColEnd() + strlen("do") - keyword->Len()); + keyword->Str() = "do"; + break; + + case CT_WHILE: + case CT_WHILE_OF_DO: + keyword->SetOrigColEnd(keyword->GetOrigColEnd() + strlen("while") - keyword->Len()); + keyword->Str() = "while"; + break; + + case CT_FOR: + keyword->SetOrigColEnd(keyword->GetOrigColEnd() + strlen("for") - keyword->Len()); + keyword->Str() = "for"; + break; + + default: + break; + } +} + + +static void move_one_token(Chunk * &source, Chunk * &destination, E_Token parent_type) +{ + Chunk *next_source = source->GetNext(); + + // Place the source token immediately after the destination token, without + // any whitespace. + + source->MoveAfter(destination); + source->SetColumn(destination->GetColumn() + destination->Len()); + source->SetOrigCol(destination->GetOrigCol() + destination->Len()); + source->SetOrigColEnd(source->GetOrigColEnd() + source->Len()); + source->SetOrigPrevSp(0); + source->SetParentType(parent_type); + + destination = source; + source = next_source; +} + + +static void rewrite_loop_condition(Chunk * &source, Chunk * &destination, + E_Token desired_type, const char *desired_condition) +{ + // Move the opening parenthesis + move_one_token(source, destination, desired_type); + + // Move the condition + if (desired_type == CT_FOR) + { + source->SetType(CT_SEMICOLON); + source->SetParentType(CT_FOR); + source->Str() = ";"; + move_one_token(source, destination, desired_type); + destination = (destination)->CopyAndAddAfter(destination); + } + else + { + source->SetType(CT_WORD); + source->Str() = desired_condition; + move_one_token(source, destination, desired_type); + } + + // If converting a 'for' to a 'while', delete the second semicolon + if (source->Is(CT_SEMICOLON)) + { + Chunk *next_source = source->GetNext(); + Chunk::Delete(source); + source = next_source; + } + // Move the closing parenthesis + move_one_token(source, destination, desired_type); +} + + +void rewrite_loop_in_place(Chunk *keyword, E_Token desired_type, const char *desired_condition) +{ + Chunk *top = keyword->GetNext(); + Chunk *bottom = keyword; + + rewrite_loop_keyword(keyword, desired_type); + rewrite_loop_condition(top, bottom, desired_type, desired_condition); +} + + +static Chunk *find_start_brace(Chunk *pc) +{ + while (!pc->IsBraceOpen()) + { + pc = pc->GetNextNcNnl(); + } + return(pc); +} + + +void rewrite_infinite_loops() +{ + LOG_FUNC_ENTRY(); + + E_Token desired_type; + const char *desired_condition; + + switch (options::mod_infinite_loop()) + { + case 1: // for(;;) + desired_type = CT_FOR; + desired_condition = nullptr; + break; + + case 2: // while(true) + desired_type = CT_WHILE; + desired_condition = "true"; + break; + + case 3: // do...while(true) + desired_type = CT_WHILE_OF_DO; + desired_condition = "true"; + break; + + case 4: // while(1) + desired_type = CT_WHILE; + desired_condition = "1"; + break; + + case 5: // do...while(1) + desired_type = CT_WHILE_OF_DO; + desired_condition = "1"; + break; + + default: + return; + } + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + if (pc->Is(CT_DO)) + { + Chunk *start_brace = find_start_brace(pc); + Chunk *end_brace = start_brace->GetClosingParen(); + Chunk *while_keyword = end_brace->GetNextNcNnl(); + + if ( !while_keyword->Is(CT_WHILE_OF_DO) + || !while_needs_rewrite(while_keyword, desired_type, desired_condition)) + { + continue; + } + + if (desired_type == CT_WHILE_OF_DO) + { + // Change the loop condition + rewrite_loop_in_place(while_keyword, desired_type, desired_condition); + + // Update the braces' parent types + start_brace->SetParentType(CT_DO); + end_brace->SetParentType(CT_DO); + } + else + { + Chunk *top = pc; + Chunk *bottom = while_keyword->GetNext(); + + // Change the 'do' at the top of the loop to a 'for' or a 'while' + rewrite_loop_keyword(top, desired_type); + + // Delete the 'while' at the bottom of the loop + Chunk::Delete(while_keyword); + + // Move the rest of the tokens from the bottom to the top + rewrite_loop_condition(bottom, top, desired_type, desired_condition); + + // Delete the final semicolon + Chunk::Delete(bottom); + + // Update the braces' parent types + start_brace->SetParentType(desired_type); + end_brace->SetParentType(desired_type); + } + } + else if ( ( pc->Is(CT_WHILE) + && while_needs_rewrite(pc, desired_type, desired_condition)) + || ( pc->Is(CT_FOR) + && for_needs_rewrite(pc, desired_type))) + { + Chunk *start_brace = find_start_brace(pc); + Chunk *end_brace = start_brace->GetClosingParen(); + + if (desired_type == CT_WHILE_OF_DO) + { + Chunk *top = pc; + Chunk *bottom = end_brace; + + if (bottom->Is(CT_VBRACE_CLOSE)) + { + // Insert a new line before the new 'while' keyword + newline_add_before(bottom); + } + // Add a 'while' at the bottom of the loop + bottom = top->CopyAndAddAfter(bottom); + rewrite_loop_keyword(bottom, CT_WHILE_OF_DO); + + // Change the 'while' at the top of the loop to a 'do' + rewrite_loop_keyword(top, CT_DO); + top = top->GetNext(); + + // Move the tokens from the top to the bottom + rewrite_loop_condition(top, bottom, desired_type, desired_condition); + + // Add the final semicolon + bottom = bottom->CopyAndAddAfter(bottom); + bottom->SetType(CT_SEMICOLON); + bottom->Str() = ";"; + + // Update the braces' parent types + start_brace->SetParentType(CT_DO); + end_brace->SetParentType(CT_DO); + } + else + { + // Change 'for' to 'while' or vice-versa + rewrite_loop_in_place(pc, desired_type, desired_condition); + + // Update the braces' parent types + start_brace->SetParentType(desired_type); + end_brace->SetParentType(desired_type); + } + } + } +} // rewrite_infinite_loops diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/rewrite_infinite_loops.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/rewrite_infinite_loops.h new file mode 100644 index 00000000..5b8f3fee --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/rewrite_infinite_loops.h @@ -0,0 +1,19 @@ +/** + * @file rewrite_infinite_loops.h + * prototypes for rewrite_infinite_loops.cpp + * + * @author Alex Henrie + * @license GPL v2+ + */ + +#ifndef REWRITE_INFINITE_LOOPS_H_INCLUDED +#define REWRITE_INFINITE_LOOPS_H_INCLUDED + + +/** + * @brief Rewrite infinite loops in a consistent syntax + */ +void rewrite_infinite_loops(); + + +#endif /* REWRITE_INFINITE_LOOPS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/semicolons.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/semicolons.cpp new file mode 100644 index 00000000..390fdecb --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/semicolons.cpp @@ -0,0 +1,153 @@ +/** + * @file semicolons.cpp + * Removes extra semicolons + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "semicolons.h" + +#include "prototypes.h" + + +static void remove_semicolon(Chunk *pc); + + +/** + * We are on a semicolon that is after an unidentified brace close. + * Check for what is before the brace open. + * Do not remove if it is a square close, word, type, or paren close. + */ +static void check_unknown_brace_close(Chunk *semi, Chunk *brace_close); + + +static void remove_semicolon(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LDELSEMI, "%s(%d): Removed semicolon: orig line is %zu, orig col is %zu", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_func_stack_inline(LDELSEMI); + // TODO: do we want to shift stuff back a column? + Chunk::Delete(pc); +} + + +void remove_extra_semicolons() +{ + LOG_FUNC_ENTRY(); + + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + Chunk *next = pc->GetNextNcNnl(); + Chunk *prev; + + if ( pc->Is(CT_SEMICOLON) + && !pc->TestFlags(PCF_IN_PREPROC) + && (prev = pc->GetPrevNcNnl())->IsNotNullChunk()) + { + LOG_FMT(LSCANSEMI, "%s(%d): Semi orig line is %zu, orig col is %zu, parent is %s, prev = '%s' [%s/%s]\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetParentType()), + prev->Text(), + get_token_name(prev->GetType()), get_token_name(prev->GetParentType())); + + if (pc->GetParentType() == CT_TYPEDEF) + { + // keep it + } + else if ( prev->Is(CT_BRACE_CLOSE) + && ( prev->GetParentType() == CT_IF + || prev->GetParentType() == CT_ELSEIF + || prev->GetParentType() == CT_ELSE + || prev->GetParentType() == CT_SWITCH + || prev->GetParentType() == CT_WHILE + || prev->GetParentType() == CT_USING_STMT + || prev->GetParentType() == CT_FOR + || prev->GetParentType() == CT_FUNC_DEF + || prev->GetParentType() == CT_OC_MSG_DECL + || prev->GetParentType() == CT_FUNC_CLASS_DEF + || prev->GetParentType() == CT_NAMESPACE)) + { + // looking for code block vs. initialisation + bool code_block_found = true; + Chunk *closing_brace = pc->GetPrevNcNnl(); // Issue #3506 + + if ( closing_brace != nullptr + && closing_brace->IsNotNullChunk()) + { + Chunk *opening_brace = closing_brace->GetOpeningParen(); + + if ( opening_brace != nullptr + && opening_brace->IsNotNullChunk()) + { + Chunk *equal_sign = opening_brace->GetPrevNcNnl(); + + if ( equal_sign != nullptr + && equal_sign->IsNotNullChunk() + && equal_sign->Is(CT_ASSIGN)) + { + // initialisation found + code_block_found = false; + } + } + } + + if (code_block_found) + { + // code block found + remove_semicolon(pc); + } + } + else if ( prev->Is(CT_BRACE_CLOSE) + && prev->GetParentType() == CT_NONE) + { + check_unknown_brace_close(pc, prev); + } + else if ( prev->Is(CT_SEMICOLON) + && prev->GetParentType() != CT_FOR) + { + remove_semicolon(pc); + } + else if ( language_is_set(LANG_D) + && ( prev->GetParentType() == CT_ENUM + || prev->GetParentType() == CT_UNION + || prev->GetParentType() == CT_STRUCT)) + { + remove_semicolon(pc); + } + else if ( language_is_set(LANG_JAVA) + && prev->GetParentType() == CT_SYNCHRONIZED) + { + remove_semicolon(pc); + } + else if (prev->Is(CT_BRACE_OPEN)) + { + remove_semicolon(pc); + } + } + pc = next; + } +} // remove_extra_semicolons + + +static void check_unknown_brace_close(Chunk *semi, Chunk *brace_close) +{ + LOG_FUNC_ENTRY(); + Chunk *pc = brace_close->GetPrevType(CT_BRACE_OPEN, brace_close->GetLevel()); + + pc = pc->GetPrevNcNnl(); + + if ( pc->IsNotNullChunk() + && pc->IsNot(CT_RETURN) + && pc->IsNot(CT_WORD) + && pc->IsNot(CT_TYPE) + && pc->IsNot(CT_SQUARE_CLOSE) + && pc->IsNot(CT_ANGLE_CLOSE) + && pc->IsNot(CT_TSQUARE) + && !pc->IsParenClose()) + { + remove_semicolon(semi); + } +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/semicolons.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/semicolons.h new file mode 100644 index 00000000..19591574 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/semicolons.h @@ -0,0 +1,26 @@ +/** + * @file semicolons.h + * prototypes for semicolons.c + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef SEMICOLONS_H_INCLUDED +#define SEMICOLONS_H_INCLUDED + +#include "uncrustify_types.h" + + +/** + * Removes superfluous semicolons: + * - after brace close whose parent is IF, ELSE, SWITCH, WHILE, FOR, NAMESPACE + * - after another semicolon where parent is not FOR + * - (D) after brace close whose parent is ENUM/STRUCT/UNION + * - (Java) after brace close whose parent is SYNCHRONIZED + * - after an open brace + * - when not in a #DEFINE + */ +void remove_extra_semicolons(); + + +#endif /* SEMICOLONS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/sorting.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/sorting.cpp new file mode 100644 index 00000000..27152101 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/sorting.cpp @@ -0,0 +1,711 @@ +/** + * @file sorting.cpp + * Sorts chunks and imports + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "sorting.h" + +#include "newlines.h" +#include "prototypes.h" + +#include <regex> +#include <unordered_map> + +constexpr static auto LCURRENT = LSORT; + +using namespace uncrustify; + +Option<std::string> *include_category_options[] = +{ + &options::include_category_0, + &options::include_category_1, + &options::include_category_2, +}; +constexpr static int kIncludeCategoriesCount = 3; + + +struct include_category +{ + include_category(const std::string &pattern) + : regex(pattern) + { + } + std::regex regex; +}; + + +include_category *include_categories[kIncludeCategoriesCount]; +unordered_map<Chunk *, int> chunk_priority_cache; +unordered_map<std::string, bool> filename_without_ext_cache; + + +/** + * Compare two series of chunks, starting with the given ones. + * @param pc1 first instance to compare + * @param pc2 second instance to compare + * @param tcare take care of case (lower case/ upper case) Issue #2091 + * + * @retval == 0 both text elements are equal + * @retval > 0 + * @retval < 0 + */ +static int compare_chunks(Chunk *pc1, Chunk *pc2, bool tcare); + + +/** + * Sort all of the chunks in O(n log n) time with a maximum of O(n) swaps + */ +static void do_the_sort(Chunk **chunks, size_t num_chunks); + + +#define MARK_CHANGE() mark_change(__func__, __LINE__) + + +static void mark_change(const char *func, size_t line) +{ + LOG_FUNC_ENTRY(); + cpd.changes++; + + if (cpd.pass_count == 0) + { + LOG_FMT(LCHANGE, "%s(%d): change %d on %s:%zu\n", + __func__, __LINE__, cpd.changes, func, line); + } +} + + +static void prepare_categories() +{ + for (int i = 0; i < kIncludeCategoriesCount; ++i) + { + const auto &cat_pattern = (*include_category_options[i])(); + + if (!cat_pattern.empty()) + { + include_categories[i] = new include_category(cat_pattern); + } + else + { + include_categories[i] = nullptr; + } + } +} + + +static void cleanup_categories() +{ + chunk_priority_cache.clear(); + filename_without_ext_cache.clear(); + + for (auto &include_category : include_categories) + { + if (include_category == nullptr) + { + continue; + } + delete include_category; + include_category = NULL; + } +} + + +static int get_chunk_priority(Chunk *pc) +{ + if (chunk_priority_cache.count(pc) > 0) + { + return(chunk_priority_cache[pc]); + } + int category = kIncludeCategoriesCount; + + for (int i = 0; i < kIncludeCategoriesCount; i++) + { + if (include_categories[i] != nullptr) + { + if (std::regex_match(pc->Text(), include_categories[i]->regex)) + { + category = i; + break; + } + } + } + + chunk_priority_cache[pc] = category; + return(category); +} + + +/** + * Returns true if the text contains filename without extension. + */ +static bool text_contains_filename_without_ext(const char *text) +{ + if (filename_without_ext_cache.count(text) > 0) + { + return(filename_without_ext_cache[text]); + } + std::string filepath = cpd.filename; + size_t slash_idx = filepath.find_last_of("/\\"); + std::string filename_without_ext = filepath; + + if ( slash_idx != std::string::npos + && slash_idx < (filepath.size() - 1)) + { + std::string filename = filepath.substr(slash_idx + 1); + size_t dot_idx = filename.find_last_of('.'); + filename_without_ext = filename.substr(0, dot_idx); + } + const std::regex special_chars = std::regex(R"([-[\]{}()*+?.,\^$|#\s])"); + const std::string sanitized_filename = std::regex_replace(filename_without_ext, special_chars, R"(\$&)"); + const std::regex filename_pattern = std::regex("\\S?" + sanitized_filename + "\\b.*"); + + filename_without_ext_cache[text] = std::regex_match(text, filename_pattern); + return(filename_without_ext_cache[text]); +} + + +/** + * Get chunk text without the extension. + */ +static unc_text get_text_without_ext(const unc_text &chunk_text) +{ + unc_text result = chunk_text; + int idx = result.rfind(".", result.size() - 1); + + if (idx == -1) + { + return(result); + } + result.erase(idx, result.size() - idx); + return(result); +} + + +/** + * Returns true if unc_text has "." which implies extension. + */ +static bool has_dot(const unc_text &chunk_text) +{ + int idx = chunk_text.rfind(".", chunk_text.size() - 1); + + return(idx != -1); +} + + +/** + * Returns chunk string required for sorting. + */ +static unc_text chunk_sort_str(Chunk *pc) +{ + if (pc->GetParentType() == CT_PP_INCLUDE) + { + return(unc_text{ pc->GetStr(), 0, pc->Len() - 1 }); + } + return(pc->GetStr()); +} + + +//! Compare two chunks +static int compare_chunks(Chunk *pc1, Chunk *pc2, bool tcare) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LSORT, "%s(%d): @begin pc1->len is %zu, line is %zu, column is %zu\n", + __func__, __LINE__, pc1->Len(), pc1->GetOrigLine(), pc1->GetOrigCol()); + LOG_FMT(LSORT, "%s(%d): @begin pc2->len is %zu, line is %zu, column is %zu\n", + __func__, __LINE__, pc2->Len(), pc2->GetOrigLine(), pc2->GetOrigCol()); + + if (pc1 == pc2) // same chunk is always identical thus return 0 differences + { + return(0); + } + + while ( pc1->IsNotNullChunk() + && pc2->IsNotNullChunk()) + { + auto const &s1_ext = chunk_sort_str(pc1); + auto const &s2_ext = chunk_sort_str(pc2); + + log_rule_B("mod_sort_incl_import_ignore_extension"); + auto const &s1 = (options::mod_sort_incl_import_ignore_extension()) ? get_text_without_ext(s1_ext) : s1_ext; + auto const &s2 = (options::mod_sort_incl_import_ignore_extension()) ? get_text_without_ext(s2_ext) : s2_ext; + log_rule_B("mod_sort_incl_import_prioritize_filename"); + + if (options::mod_sort_incl_import_prioritize_filename()) + { + bool s1_contains_filename = text_contains_filename_without_ext(s1.c_str()); + bool s2_contains_filename = text_contains_filename_without_ext(s2.c_str()); + + if ( s1_contains_filename + && !s2_contains_filename) + { + return(-1); + } + else if ( !s1_contains_filename + && s2_contains_filename) + { + return(1); + } + } + + if (options::mod_sort_incl_import_prioritize_extensionless()) + { + log_rule_B("mod_sort_incl_import_prioritize_extensionless"); + const bool s1_has_dot = has_dot(s1_ext); + const bool s2_has_dot = has_dot(s2_ext); + + if ( s1_has_dot + && !s2_has_dot) + { + return(1); + } + else if ( !s1_has_dot + && s2_has_dot) + { + return(-1); + } + } + + if (options::mod_sort_incl_import_prioritize_angle_over_quotes()) + { + log_rule_B("mod_sort_incl_import_prioritize_angle_over_quotes"); + + if ( s1.startswith("<") + && s2.startswith("\"")) + { + return(-1); + } + else if ( s1.startswith("\"") + && s2.startswith("<")) + { + return(1); + } + } + int ppc1 = get_chunk_priority(pc1); + int ppc2 = get_chunk_priority(pc2); + + if (ppc1 != ppc2) + { + return(ppc1 - ppc2); + } + LOG_FMT(LSORT, "%s(%d): text is %s, pc1->len is %zu, line is %zu, column is %zu\n", + __func__, __LINE__, pc1->Text(), pc1->Len(), pc1->GetOrigLine(), pc1->GetOrigCol()); + LOG_FMT(LSORT, "%s(%d): text is %s, pc2->len is %zu, line is %zu, column is %zu\n", + __func__, __LINE__, pc2->Text(), pc2->Len(), pc2->GetOrigLine(), pc2->GetOrigCol()); + + int ret_val = unc_text::compare(s1, s2, std::min(s1.size(), s2.size()), tcare); + LOG_FMT(LSORT, "%s(%d): ret_val is %d\n", + __func__, __LINE__, ret_val); + + if (ret_val != 0) + { + return(ret_val); + } + + if (pc1->Len() != pc2->Len()) + { + return(pc1->Len() - pc2->Len()); + } + // Same word, same length. Step to the next chunk. + pc1 = pc1->GetNext(); + LOG_FMT(LSORT, "%s(%d): text is %s, pc1->len is %zu, line is %zu, column is %zu\n", + __func__, __LINE__, pc1->Text(), pc1->Len(), pc1->GetOrigLine(), pc1->GetOrigCol()); + + if (pc1->Is(CT_MEMBER)) + { + pc1 = pc1->GetNext(); + LOG_FMT(LSORT, "%s(%d): text is %s, pc1->len is %zu, line is %zu, column is %zu\n", + __func__, __LINE__, pc1->Text(), pc1->Len(), pc1->GetOrigLine(), pc1->GetOrigCol()); + } + pc2 = pc2->GetNext(); + LOG_FMT(LSORT, "%s(%d): text is %s, pc2->len is %zu, line is %zu, column is %zu\n", + __func__, __LINE__, pc2->Text(), pc2->Len(), pc2->GetOrigLine(), pc2->GetOrigCol()); + + if (pc2->Is(CT_MEMBER)) + { + pc2 = pc2->GetNext(); + LOG_FMT(LSORT, "%s(%d): text is %s, pc2->len is %zu, line is %zu, column is %zu\n", + __func__, __LINE__, pc2->Text(), pc2->Len(), pc2->GetOrigLine(), pc2->GetOrigCol()); + } + LOG_FMT(LSORT, "%s(%d): >>>text is %s, pc1->len is %zu, line is %zu, column is %zu\n", + __func__, __LINE__, pc1->Text(), pc1->Len(), pc1->GetOrigLine(), pc1->GetOrigCol()); + LOG_FMT(LSORT, "%s(%d): >>>text is %s, pc2->len is %zu, line is %zu, column is %zu\n", + __func__, __LINE__, pc2->Text(), pc2->Len(), pc2->GetOrigLine(), pc2->GetOrigCol()); + + // If we hit a newline or nullptr, we are done + if ( pc1->IsNullChunk() + || pc1->IsNewline() + || pc2->IsNullChunk() + || pc2->IsNewline()) + { + break; + } + } + + if ( pc1->IsNullChunk() + || !pc2->IsNewline()) + { + return(-1); + } + + if (!pc1->IsNewline()) + { + return(1); + } + return(0); +} // compare_chunks + + +/** + * Sort all of the chunks in O(n log n) time with a maximum of O(n) swaps + */ +static void do_the_sort(Chunk **chunks, size_t num_chunks) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LSORT, "%s(%d): %zu chunks:", + __func__, __LINE__, num_chunks); + + for (size_t idx = 0; idx < num_chunks; idx++) + { + LOG_FMT(LSORT, " [%s]", chunks[idx]->Text()); + } + + LOG_FMT(LSORT, "\n"); + + log_rule_B("mod_sort_case_sensitive"); + bool take_care = options::mod_sort_case_sensitive(); // Issue #2091 + + // Sort an array of the chunk positions in order to minimize the number of swaps + std::vector<size_t> chunk_positions(num_chunks); + + for (size_t idx = 0; idx < num_chunks; idx++) + { + chunk_positions[idx] = idx; + } + + sort(chunk_positions.begin(), chunk_positions.end(), [chunks, take_care](const size_t &l, const size_t &r) { + return(compare_chunks(chunks[l], chunks[r], take_care) < 0); + }); + + // Swap the chunk positions + for (size_t idx = 0; idx < num_chunks; idx++) + { + if (chunk_positions[idx] != idx) + { + log_rule_B("mod_sort_incl_import_grouping_enabled"); + + const size_t from = chunk_positions[idx]; + const size_t to = chunk_positions[from]; + chunks[from]->SwapLines(chunks[to]); + + Chunk *pc = chunks[from]; + chunks[from] = chunks[to]; + chunks[to] = pc; + + chunk_positions[from] = from; + chunk_positions[idx] = to; + idx--; + } + } +} // do_the_sort + + +/** + * Remove blank lines between chunks. + */ +static void remove_blank_lines_between_imports(Chunk **chunks, size_t num_chunks) +{ + LOG_FUNC_ENTRY(); + + if (num_chunks < 2) + { + return; + } + + for (size_t idx = 0; idx < (num_chunks - 1); idx++) + { + Chunk *chunk1 = chunks[idx]->GetNextNl(); + chunk1->SetNlCount(1); + MARK_CHANGE(); + } +} + + +/** + * Delete chunks on line having chunk. + */ +static void delete_chunks_on_line_having_chunk(Chunk *chunk) +{ + LOG_FUNC_ENTRY(); + + Chunk *pc = chunk->GetFirstChunkOnLine(); + + while ( pc->IsNotNullChunk() + && !pc->IsComment()) + { + Chunk *next_pc = pc->GetNext(); + LOG_FMT(LCHUNK, "%s(%d): Removed '%s' on orig line %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine()); + + if (pc->IsNewline()) + { + Chunk::Delete(pc); + break; + } + else + { + Chunk::Delete(pc); + } + pc = next_pc; + } +} + + +/** + * Dedupe import/include directives. + */ +static void dedupe_imports(Chunk **chunks, size_t num_chunks) +{ + LOG_FUNC_ENTRY(); + log_rule_B("mod_sort_case_sensitive"); + + for (size_t idx = 1; idx < num_chunks; idx++) + { + auto const &s1 = chunk_sort_str(chunks[idx - 1]); + auto const &s2 = chunk_sort_str(chunks[idx]); + + if (s1.size() != s2.size()) + { + continue; + } + int ret_val = unc_text::compare(s1, s2, std::min(s1.size(), s2.size()), options::mod_sort_case_sensitive()); + + if (ret_val == 0) + { + delete_chunks_on_line_having_chunk(chunks[idx - 1]); + } + } +} + + +/** + * Add blank line before the chunk. + */ +static void blankline_add_before(Chunk *pc) +{ + Chunk *newline = newline_add_before(pc->GetFirstChunkOnLine()); + + if (newline->GetNlCount() < 2) + { + double_newline(newline); + } +} + + +/** + * Group imports. + */ +static void group_imports_by_adding_newlines(Chunk **chunks, size_t num_chunks) +{ + LOG_FUNC_ENTRY(); + + // Group imports based on first character, typically quote or angle. + int c_idx = -1; + int c_idx_last = -1; + + for (size_t idx = 0; idx < num_chunks; idx++) + { + if (chunks[idx]->GetStr().size() > 0) + { + c_idx = chunks[idx]->GetStr().at(0); + } + else + { + c_idx = -1; + } + + if ( c_idx_last != c_idx + && idx > 0) + { + blankline_add_before(chunks[idx]); + } + c_idx_last = c_idx; + } + + // Group imports based on having extension. + bool chunk_has_dot = false; + bool chunk_last_has_dot = false; + + for (size_t idx = 0; idx < num_chunks; idx++) + { + chunk_has_dot = has_dot(chunks[idx]->GetStr()); + + if ( chunk_last_has_dot != chunk_has_dot + && idx > 0) + { + blankline_add_before(chunks[idx]); + } + chunk_last_has_dot = chunk_has_dot; + } + + // Group imports based on priority defined by config. + int chunk_pri = -1; + int chunk_pri_last = -1; + + for (size_t idx = 0; idx < num_chunks; idx++) + { + chunk_pri = get_chunk_priority(chunks[idx]); + + if ( chunk_pri_last != chunk_pri + && idx > 0) + { + blankline_add_before(chunks[idx]); + } + chunk_pri_last = chunk_pri; + } + + // Group imports that contain filename pattern. + bool chunk_has_filename = false; + bool last_chunk_has_filename = false; + + for (size_t idx = 0; idx < num_chunks; idx++) + { + auto const &chunk_text = chunk_sort_str(chunks[idx]); + chunk_has_filename = text_contains_filename_without_ext(chunk_text.c_str()); + + if ( !chunk_has_filename + && last_chunk_has_filename) + { + blankline_add_before(chunks[idx]); + } + last_chunk_has_filename = chunk_has_filename; + } +} // group_imports_by_adding_newlines + + +void sort_imports() +{ + LOG_FUNC_ENTRY(); + const int max_number_to_sort = 1024; + const int max_lines_to_check_for_sort_after_include = 128; + const int max_gap_threshold_between_include_to_sort = 32; + + Chunk *chunks[max_number_to_sort]; + size_t num_chunks = 0; + Chunk *p_last = nullptr; + Chunk *p_imp = nullptr; + Chunk *p_imp_last = nullptr; + + prepare_categories(); + + Chunk *pc = Chunk::GetHead(); + + log_rule_B("mod_sort_incl_import_grouping_enabled"); + + while (pc->IsNotNullChunk()) + { + // Simple optimization to limit the sorting. Any MAX_LINES_TO_CHECK_AFTER_INCLUDE lines after last + // import is seen are ignore from sorting. + if ( options::mod_sort_incl_import_grouping_enabled() + && p_imp_last != nullptr + && (pc->GetOrigLine() - p_imp_last->GetOrigLine()) > max_lines_to_check_for_sort_after_include) + { + break; + } + Chunk *next = pc->GetNext(); + + if (pc->IsNewline()) + { + bool did_import = false; + + if ( p_imp != nullptr + && p_imp->IsNotNullChunk() + && p_last != nullptr + && ( p_last->Is(CT_SEMICOLON) + || p_imp->TestFlags(PCF_IN_PREPROC))) + { + if (num_chunks < max_number_to_sort) + { + LOG_FMT(LSORT, "%s(%d): p_imp is %s\n", + __func__, __LINE__, p_imp->Text()); + chunks[num_chunks++] = p_imp; + } + else + { + fprintf(stderr, "Number of 'import' to be sorted is too big for the current value %d.\n", max_number_to_sort); + fprintf(stderr, "Please make a report.\n"); + log_flush(true); + exit(EX_SOFTWARE); + } + did_import = true; + } + log_rule_B("mod_sort_incl_import_grouping_enabled"); + + if ( !did_import + || ( !options::mod_sort_incl_import_grouping_enabled() + && pc->GetNlCount() > 1) + || ( options::mod_sort_incl_import_grouping_enabled() + && p_imp_last != nullptr + && (pc->GetOrigLine() - p_imp_last->GetOrigLine()) > max_gap_threshold_between_include_to_sort) + || next->IsNullChunk()) + { + if (num_chunks > 1) + { + log_rule_B("mod_sort_incl_import_grouping_enabled"); + + if (options::mod_sort_incl_import_grouping_enabled()) + { + remove_blank_lines_between_imports(chunks, num_chunks); + do_the_sort(chunks, num_chunks); + group_imports_by_adding_newlines(chunks, num_chunks); + dedupe_imports(chunks, num_chunks); + } + else + { + do_the_sort(chunks, num_chunks); + } + } + num_chunks = 0; + } + p_imp_last = p_imp; + p_imp = nullptr; + p_last = nullptr; + } + else if (pc->Is(CT_IMPORT)) + { + log_rule_B("mod_sort_import"); + + if (options::mod_sort_import()) + { + p_imp = pc->GetNext(); + } + } + else if (pc->Is(CT_USING)) + { + log_rule_B("mod_sort_using"); + + if (options::mod_sort_using()) + { + p_imp = pc->GetNext(); + } + } + else if (pc->Is(CT_PP_INCLUDE)) + { + log_rule_B("mod_sort_include"); + + if (options::mod_sort_include()) + { + p_imp = pc->GetNext(); + p_last = pc; + } + } + else if (!pc->IsComment()) + { + p_last = pc; + } + pc = next; + } + cleanup_categories(); +} // sort_imports diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/sorting.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/sorting.h new file mode 100644 index 00000000..8d518df8 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/sorting.h @@ -0,0 +1,24 @@ +/** + * @file sorting.h + * prototypes for sorting.cpp + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef SORTING_H_INCLUDED +#define SORTING_H_INCLUDED + +#include "uncrustify_types.h" + +/** + * alphabetically sort the #include or #import + * statements of a file + * + * @todo better use a chunk pointer parameter + * instead of a global variable + */ +void sort_imports(); + + +#endif /* SORTING_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/space.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/space.cpp new file mode 100644 index 00000000..2e6dafde --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/space.cpp @@ -0,0 +1,3782 @@ +/** + * @file space.cpp + * Adds or removes inter-chunk spaces. + * + * Information + * "Ignore" means do not change it. + * "Add" in the context of spaces means make sure there is at least 1. + * "Add" elsewhere means make sure one is present. + * "Remove" mean remove the space/brace/newline/etc. + * "Force" in the context of spaces means ensure that there is exactly 1. + * "Force" in other contexts means the same as "add". + * + * Rmk: spaces = space + nl + * + * @author Ben Gardner + * @author Guy Maurel, 2015-2022 + * @license GPL v2+ + */ + +#include "space.h" + +#include "add_space_table.h" +#include "log_rules.h" +#include "options_for_QT.h" +#include "punctuators.h" + +#ifdef WIN32 +#include <algorithm> // to get max +#endif // ifdef WIN32 + +using namespace std; +using namespace uncrustify; + + +/** + * Decides how to change inter-chunk spacing. + * Note that the order of the if statements is VERY important. + * + * @param first The first chunk + * @param second The second chunk + * + * @return IARF_IGNORE, IARF_ADD, IARF_REMOVE or IARF_FORCE + */ +static iarf_e do_space(Chunk *first, Chunk *second, int &min_sp); + +/** + * Ensure to force the space between the \a first and the \a second chunks + * if the PCF_FORCE_SPACE flag is set in the \a first. + * + * @param first The first chunk + * @param second The second chunk + * @param av Av from the do_space() + * + * @return IARF_IGNORE, IARF_ADD, IARF_REMOVE or IARF_FORCE + */ +static iarf_e ensure_force_space(Chunk *first, Chunk *second, iarf_e av); + + +bool token_is_within_trailing_return(Chunk *pc) +{ + // look back for '->' type is TRAILING_RET + // until CT_FPAREN_CLOSE + // or CT_FPAREN_OPEN is found + Chunk *prev = pc; + + if (prev == nullptr) + { + prev = Chunk::NullChunkPtr; + } + + while (prev->IsNotNullChunk()) + { + if (prev->Is(CT_TRAILING_RET)) + { + return(true); + } + else if ( prev->Is(CT_FPAREN_CLOSE) + || prev->Is(CT_FPAREN_OPEN)) + { + return(false); + } + else + { + prev = prev->GetPrev(); + } + } + return(false); +} // token_is_within_trailing_return + + +/* + * this function is called for every chunk in the input file. + * Thus it is important to keep this function efficient + */ +static iarf_e do_space(Chunk *first, Chunk *second, int &min_sp) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LSPACE, "%s(%d): orig line is %zu, orig col is %zu, first Text() '%s', type is %s\n", + __func__, __LINE__, first->GetOrigLine(), first->GetOrigCol(), first->Text(), get_token_name(first->GetType())); + + min_sp = 1; + + if ( first->Is(CT_PP_IGNORE) + && second->Is(CT_PP_IGNORE)) + { + // Leave spacing alone between PP_IGNORE tokens as we don't want the default behavior (which is ADD). + log_rule("PP_IGNORE"); + return(IARF_IGNORE); + } + + if ( first->Is(CT_PP) + || second->Is(CT_PP)) + { + // Add or remove space around preprocessor '##' concatenation operator. + log_rule("sp_pp_concat"); + return(options::sp_pp_concat()); + } + + if (first->Is(CT_POUND)) + { + // Add or remove space after preprocessor '#' stringify operator. + // Also affects the '#@' charizing operator. + log_rule("sp_pp_stringify"); + return(options::sp_pp_stringify()); + } + + if ( second->Is(CT_POUND) + && second->TestFlags(PCF_IN_PREPROC) + && first->GetParentType() != CT_MACRO_FUNC) + { + // Add or remove space before preprocessor '#' stringify operator + // as in '#define x(y) L#y'. + log_rule("sp_before_pp_stringify"); + return(options::sp_before_pp_stringify()); + } + + if ( first->Is(CT_SPACE) + || second->Is(CT_SPACE)) + { + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if (first->Is(CT_DECLSPEC)) // Issue 1289 + { + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if ( second->Is(CT_NEWLINE) + || second->Is(CT_VBRACE_OPEN)) + { + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if ( first->Is(CT_VBRACE_OPEN) + && second->IsNot(CT_NL_CONT) + && second->IsNot(CT_SEMICOLON)) // # Issue 1158 + { + log_rule("FORCE"); + return(IARF_FORCE); + } + + if ( first->Is(CT_VBRACE_CLOSE) + && second->IsNot(CT_NL_CONT)) + { + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if (second->Is(CT_VSEMICOLON)) + { + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if (first->Is(CT_MACRO_FUNC)) + { + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if (second->Is(CT_NL_CONT)) + { + // Add or remove space before a backslash-newline at the end of a line. + log_rule("sp_before_nl_cont"); + return(options::sp_before_nl_cont()); + } + + if ( language_is_set(LANG_D) + && ( first->Is(CT_D_ARRAY_COLON) + || second->Is(CT_D_ARRAY_COLON))) + { + // (D) Add or remove around the D named array initializer ':' operator. + log_rule("sp_d_array_colon"); + return(options::sp_d_array_colon()); + } + + if ( first->Is(CT_CASE) + && (( CharTable::IsKw1(second->GetStr()[0]) + || second->Is(CT_NUMBER)))) + { + // Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make + // sense here. + log_rule("sp_case_label"); + return(options::sp_case_label() | IARF_ADD); + } + + if (first->Is(CT_FOR_COLON)) + { + // java + // Add or remove space after ':' in a Java/C++11 range-based 'for', + // as in 'for (Type var : expr)'. + log_rule("sp_after_for_colon"); + return(options::sp_after_for_colon()); + } + + if (second->Is(CT_FOR_COLON)) + { + // java + // Add or remove space before ':' in a Java/C++11 range-based 'for', + // as in 'for (Type var : expr)'. + log_rule("sp_before_for_colon"); + return(options::sp_before_for_colon()); + } + + if ( first->Is(CT_QUESTION) + && second->Is(CT_COND_COLON)) + { + // In the abbreviated ternary form '(a ?: b)', add or remove space between '?' + // and ':'. + // Overrides all other sp_cond_* options. + log_rule("sp_cond_ternary_short"); + return(options::sp_cond_ternary_short()); + } + + if ( first->Is(CT_QUESTION) // see the tests cpp:34513-34516 + || second->Is(CT_QUESTION)) + { + if ( second->Is(CT_QUESTION) + && (options::sp_cond_question_before() != IARF_IGNORE)) + { + // Add or remove space before the '?' in 'b ? t : f'. + // Overrides sp_cond_question. + log_rule("sp_cond_question_before"); + return(options::sp_cond_question_before()); + } + + if ( first->Is(CT_QUESTION) + && (options::sp_cond_question_after() != IARF_IGNORE)) + { + // Add or remove space after the '?' in 'b ? t : f'. + // Overrides sp_cond_question. + log_rule("sp_cond_question_after"); + return(options::sp_cond_question_after()); + } + log_rule("sp_cond_question"); + return(options::sp_cond_question()); + } + + if ( first->Is(CT_COND_COLON) + || second->Is(CT_COND_COLON)) + { + if ( second->Is(CT_COND_COLON) + && (options::sp_cond_colon_before() != IARF_IGNORE)) + { + // Add or remove space before the ':' in 'b ? t : f'. + // Overrides sp_cond_colon. + log_rule("sp_cond_colon_before"); + return(options::sp_cond_colon_before()); + } + + if ( first->Is(CT_COND_COLON) + && (options::sp_cond_colon_after() != IARF_IGNORE)) + { + // Add or remove space after the ':' in 'b ? t : f'. + // Overrides sp_cond_colon. + log_rule("sp_cond_colon_after"); + return(options::sp_cond_colon_after()); + } + // Issue #2596 + // replace "if (first->Is(CT_WORD) && second->Is(CT_COND_COLON))" + // Add or remove space around the ':' in 'b ? t : f'. + log_rule("sp_cond_colon"); + return(options::sp_cond_colon()); + } + + if ( language_is_set(LANG_D) + && ( first->Is(CT_RANGE) + || second->Is(CT_RANGE))) + { + // (D) Add or remove space around the D '..' operator. + log_rule("sp_range"); + return(options::sp_range()); + } + + if ( first->Is(CT_COLON) + && first->GetParentType() == CT_SQL_EXEC) + { + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + // Macro stuff can only return IGNORE, ADD, or FORCE + if (first->Is(CT_MACRO)) + { + // Add or remove space between a macro name and its definition. + log_rule("sp_macro"); + iarf_e arg = options::sp_macro(); + return(arg | ((arg != IARF_IGNORE) ? IARF_ADD : IARF_IGNORE)); + } + + if ( first->Is(CT_FPAREN_CLOSE) + && first->GetParentType() == CT_MACRO_FUNC) + { + // Add or remove space between a macro function ')' and its definition. + log_rule("sp_macro_func"); + iarf_e arg = options::sp_macro_func(); + return(arg | ((arg != IARF_IGNORE) ? IARF_ADD : IARF_IGNORE)); + } + + if (first->Is(CT_PREPROC)) + { + // Remove spaces, unless we are ignoring. See indent_preproc() + log_rule("pp_space_after"); + + if (options::pp_space_after() == IARF_IGNORE) + { + log_rule("IGNORE"); + return(IARF_IGNORE); + } + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if (second->Is(CT_PREPROC)) + { + // Remove spaces, unless we are ignoring. See indent_preproc() + log_rule("pp_indent"); + + if (options::pp_indent() == IARF_IGNORE) + { + log_rule("IGNORE"); + return(IARF_IGNORE); + } + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if (second->Is(CT_SEMICOLON)) // see the tests cpp:34517-34519 + { + if (first->Is(CT_VBRACE_OPEN)) + { + // Add or remove space before ';'. + log_rule("sp_before_semi"); + return(options::sp_before_semi()); + } + + if (second->GetParentType() == CT_FOR) + { + if (first->Is(CT_SPAREN_OPEN)) + { + // empty, e.g. for (;;) + // ^ is first + // ^ is second + // Add or remove space before a semicolon of an empty left part of a for statement. + log_rule("sp_before_semi_for_empty"); + return(options::sp_before_semi_for_empty()); + } + + if (first->Is(CT_SEMICOLON)) + { + // empty, e.g. for (;;) + // ^ is first + // ^ is second + // Add or remove space between semicolons of an empty middle part of a for statement. + log_rule("sp_between_semi_for_empty"); + return(options::sp_between_semi_for_empty()); + } + // Add or remove space before ';' in non-empty 'for' statements. + log_rule("sp_before_semi_for"); + return(options::sp_before_semi_for()); + } + iarf_e arg = options::sp_before_semi(); // see the tests cpp:34517-34519 + + if ( first->Is(CT_VBRACE_OPEN) // Issue #2942 + && first->GetPrev()->Is(CT_SPAREN_CLOSE) + && first->GetParentType() != CT_WHILE_OF_DO) + { + // Add or remove space before empty statement ';' on 'if', 'for' and 'while'. + log_rule("sp_special_semi"); + arg = arg | options::sp_special_semi(); + } + else + { + // Add or remove space before ';'. + log_rule("sp_before_semi"); + } + return(arg); + } + + if ( ( second->Is(CT_COMMENT) + || second->Is(CT_COMMENT_CPP)) + && ( first->Is(CT_PP_ELSE) + || first->Is(CT_PP_ENDIF))) + { + second->SetType(CT_COMMENT_ENDIF); + // Add or remove space between #else or #endif and a trailing comment. + log_rule("sp_endif_cmt"); + return(options::sp_endif_cmt()); + } + + if ( options::sp_before_tr_cmt() != IARF_IGNORE + && second->GetParentType() == CT_COMMENT_END) + { + // Add or remove space before a trailing comment. + // Number of spaces before a trailing comment. + log_rule("sp_num_before_tr_cmt"); + min_sp = options::sp_num_before_tr_cmt(); + return(options::sp_before_tr_cmt()); + } + + if (second->GetParentType() == CT_COMMENT_END) + { + switch (second->GetOrigPrevSp()) + { + case 0: + log_rule("orig prev sp - REMOVE"); + return(IARF_REMOVE); + + case 1: + log_rule("orig prev sp - FORCE"); + return(IARF_FORCE); + + default: + log_rule("orig prev sp - ADD"); + return(IARF_ADD); + } + } + + // "for (;;)" vs. "for (;; )" and "for (a;b;c)" vs. "for (a; b; c)" + if (first->Is(CT_SEMICOLON)) // see the tests cpp:34517-34519 + { + if (first->GetParentType() == CT_FOR) + { + if (second->Is(CT_SPAREN_CLOSE)) + { + // Add or remove space after the final semicolon of an empty part of a for + // statement, as in 'for ( ; ; <here> )'. + log_rule("sp_after_semi_for_empty"); + return(options::sp_after_semi_for_empty()); + } + + if (second->IsNot(CT_SPAREN_CLOSE)) // Issue 1324 + { + // Add or remove space after ';' in non-empty 'for' statements. + log_rule("sp_after_semi_for"); + return(options::sp_after_semi_for()); + } + } + else if ( !second->IsComment() + && second->IsNot(CT_BRACE_CLOSE)) // issue #197 + { + // Add or remove space after ';', except when followed by a comment. + // see the tests cpp:34517-34519 + log_rule("sp_after_semi"); + return(options::sp_after_semi()); + } + // Let the comment spacing rules handle this + } + + // puts a space in the rare '+-' or '-+' + if ( ( first->Is(CT_NEG) + || first->Is(CT_POS) + || first->Is(CT_ARITH) + || first->Is(CT_SHIFT)) + && ( second->Is(CT_NEG) + || second->Is(CT_POS) + || second->Is(CT_ARITH) + || second->Is(CT_SHIFT))) + { + log_rule("ADD"); + return(IARF_ADD); + } + + // "return(a);" vs. "return (foo_t)a + 3;" vs. "return a;" vs. "return;" + if (first->Is(CT_RETURN)) + { + if ( second->Is(CT_PAREN_OPEN) + && second->GetParentType() == CT_RETURN) + { + // Add or remove space between 'return' and '('. + log_rule("sp_return_paren"); + return(options::sp_return_paren()); + } + else if ( second->Is(CT_BRACE_OPEN) + && second->GetParentType() == CT_BRACED_INIT_LIST) + { + // Add or remove space between 'return' and '{'. + log_rule("sp_return_brace"); + return(options::sp_return_brace()); + } + // Everything else requires a space + // The value REMOVE will be overridden with FORCE + log_rule("sp_return"); + + if (options::sp_return() == IARF_REMOVE) + { + return(IARF_FORCE); + } + return(options::sp_return()); + } + + // "sizeof(foo_t)" vs. "sizeof (foo_t)" + if (first->Is(CT_SIZEOF)) + { + if (second->Is(CT_PAREN_OPEN)) + { + // Add or remove space between 'sizeof' and '('. + log_rule("sp_sizeof_paren"); + return(options::sp_sizeof_paren()); + } + + if (second->Is(CT_ELLIPSIS)) + { + // Add or remove space between 'sizeof' and '...'. + log_rule("sp_sizeof_ellipsis"); + return(options::sp_sizeof_ellipsis()); + } + log_rule("FORCE"); + return(IARF_FORCE); + } + + // "decltype(foo_t)" vs. "decltype (foo_t)" + if (first->Is(CT_DECLTYPE)) + { + if (second->Is(CT_PAREN_OPEN)) + { + // Add or remove space between 'decltype' and '('. + log_rule("sp_decltype_paren"); + return(options::sp_decltype_paren()); + } + log_rule("FORCE"); + return(IARF_FORCE); + } + + // handle '::' + if (first->Is(CT_DC_MEMBER)) + { + // Add or remove space after the '::' operator. + log_rule("sp_after_dc"); + return(options::sp_after_dc()); + } + + // Issue #889 + // mapped_file_source abc((int) ::CW2A(sTemp)); + if ( first->Is(CT_PAREN_CLOSE) + && second->Is(CT_DC_MEMBER) + && second->GetNext()->GetType() == CT_FUNC_CALL) + { + log_rule("sp_after_cast"); + return(options::sp_after_cast()); + } + + if (second->Is(CT_DC_MEMBER)) + { + /* '::' at the start of an identifier is not member access, but global scope operator. + * Detect if previous chunk is keyword + */ + switch (first->GetType()) + { + case CT_SBOOL: + case CT_SASSIGN: + case CT_ARITH: + case CT_SHIFT: + case CT_CASE: + case CT_CLASS: + case CT_DELETE: + case CT_FRIEND: + case CT_NAMESPACE: + case CT_NEW: + case CT_SARITH: + case CT_SCOMPARE: + case CT_OPERATOR: + case CT_ACCESS: + case CT_QUALIFIER: + case CT_RETURN: + case CT_SIZEOF: + case CT_DECLTYPE: + case CT_STRUCT: + case CT_THROW: + case CT_TYPEDEF: + case CT_TYPENAME: + case CT_UNION: + case CT_USING: + log_rule("FORCE"); + return(IARF_FORCE); + + default: + break; + } + + if ( ( first->Is(CT_WORD) + || first->Is(CT_TYPE) + || first->Is(CT_PAREN_CLOSE) + || CharTable::IsKw1(first->GetStr()[0])) + && (strcmp(first->Text(), "void") != 0)) // Issue 1249 + { + // Add or remove space before the '::' operator. + log_rule("sp_before_dc"); + return(options::sp_before_dc()); + } + } + + // "a,b" vs. "a, b" + if (first->Is(CT_COMMA)) // see the tests cpp:34520-34524 + // see the tests c-sharp:12200-12202 + { + if ( language_is_set(LANG_CS | LANG_VALA) + && first->GetParentType() == CT_TYPE) + { + // (C#, Vala) multidimensional array type: ',,' vs. ', ,' or ',]' vs. ', ]' + if (second->Is(CT_COMMA)) + { + // (C#, Vala) Add or remove space between ',' in multidimensional array type + // like 'int[,,]'. + log_rule("sp_between_mdatype_commas"); + return(options::sp_between_mdatype_commas()); + } + // (C#, Vala) Add or remove space between ',' and ']' in multidimensional array type + // like 'int[,,]'. + log_rule("sp_after_mdatype_commas"); + return(options::sp_after_mdatype_commas()); + } + + // Fix for issue #1243 + // Don't add extra space after comma immediately followed by Angle close + if (second->Is(CT_ANGLE_CLOSE)) + { + log_rule("IGNORE"); + return(IARF_IGNORE); + } + // Add or remove space after ',', i.e. 'a,b' vs. 'a, b'. + log_rule("sp_after_comma"); + return(options::sp_after_comma()); + } + + // test if we are within a SIGNAL/SLOT call + if (QT_SIGNAL_SLOT_found) + { + if ( first->Is(CT_FPAREN_CLOSE) + && ( second->Is(CT_FPAREN_CLOSE) + || second->Is(CT_COMMA))) + { + if (second->GetLevel() == QT_SIGNAL_SLOT_level) + { + restoreValues = true; + } + } + } + + if (second->Is(CT_COMMA)) + { + if ( language_is_set(LANG_CS | LANG_VALA) + && first->Is(CT_SQUARE_OPEN) + && first->GetParentType() == CT_TYPE) + { + // (C#, Vala) Add or remove space between '[' and ',' in multidimensional array type + // like 'int[,,]'. + log_rule("sp_before_mdatype_commas"); + return(options::sp_before_mdatype_commas()); + } + + if ( first->Is(CT_PAREN_OPEN) + || first->Is(CT_FPAREN_OPEN)) + { + // Add or remove space between an open parenthesis and comma, + // i.e. '(,' vs. '( ,'. + log_rule("sp_paren_comma"); + return(options::sp_paren_comma()); + } + // Add or remove space before ',', i.e. 'a,b' vs. 'a ,b'. + log_rule("sp_before_comma"); + return(options::sp_before_comma()); + } + + if (second->Is(CT_ELLIPSIS)) + { + // type followed by a ellipsis + Chunk *tmp = first; + + if ( tmp->Is(CT_PTR_TYPE) + || tmp->Is(CT_BYREF)) + { + tmp = tmp->GetPrevNcNnl(); + } + + if ( tmp->Is(CT_TYPE) + || tmp->Is(CT_QUALIFIER)) + { + // Add or remove space between a type and '...'. + log_rule("sp_type_ellipsis"); + return(options::sp_type_ellipsis()); + } + + // non-punc followed by a ellipsis + if ( !first->TestFlags(PCF_PUNCTUATOR) + && (options::sp_before_ellipsis() != IARF_IGNORE)) + { + // Add or remove space before the variadic '...' when preceded by a + // non-punctuator. + log_rule("sp_before_ellipsis"); + return(options::sp_before_ellipsis()); + } + + if ( first->Is(CT_FPAREN_CLOSE) + || first->Is(CT_PAREN_CLOSE)) + { + // Add or remove space between ')' and '...'. + log_rule("sp_paren_ellipsis"); + return(options::sp_paren_ellipsis()); + } + + if (first->Is(CT_TAG_COLON)) + { + log_rule("FORCE"); + return(IARF_FORCE); + } + + if (first->Is(CT_BYREF)) // Issue #3309 + { + log_rule("sp_byref_ellipsis"); + return(options::sp_byref_ellipsis()); + } + + if (first->Is(CT_PARAMETER_PACK)) // Issue #3309 + { + log_rule("sp_parameter_pack_ellipsis"); + return(options::sp_parameter_pack_ellipsis()); + } + } + + if (first->Is(CT_ELLIPSIS)) + { + if (second->Is(CT_PARAMETER_PACK)) // Issue #3309 + { + log_rule("sp_ellipsis_parameter_pack"); + return(options::sp_ellipsis_parameter_pack()); + } + + if (CharTable::IsKw1(second->GetStr()[0])) + { + log_rule("FORCE"); + return(IARF_FORCE); + } + + if ( second->Is(CT_PAREN_OPEN) + && first->GetPrev()->Is(CT_SIZEOF)) + { + // Add or remove space between 'sizeof...' and '('. + log_rule("sp_sizeof_ellipsis_paren"); + return(options::sp_sizeof_ellipsis_paren()); + } + } + + if ( language_is_set(LANG_PAWN) + && first->Is(CT_TAG_COLON)) + { + // (Pawn) Add or remove space after the tag keyword. + log_rule("sp_after_tag"); + return(options::sp_after_tag()); + } + + if (second->Is(CT_TAG_COLON)) + { + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + // handle '~' + if (first->Is(CT_DESTRUCTOR)) + { + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if ( language_is_set(LANG_OC) + && first->Is(CT_CATCH) + && second->Is(CT_SPAREN_OPEN) + && (options::sp_oc_catch_paren() != IARF_IGNORE)) + { + // (OC) Add or remove space between '@catch' and '(' + // in '@catch (something) { }'. If set to ignore, sp_catch_paren is used. + log_rule("sp_oc_catch_paren"); + return(options::sp_oc_catch_paren()); + } + + if ( language_is_set(LANG_OC) + && ( first->Is(CT_PAREN_CLOSE) + || first->Is(CT_OC_CLASS) + || first->Is(CT_WORD)) + && second->Is(CT_ANGLE_OPEN) + && ( second->GetParentType() == CT_OC_PROTO_LIST + || second->GetParentType() == CT_OC_GENERIC_SPEC) + && (options::sp_before_oc_proto_list() != IARF_IGNORE)) + { + // (OC) Add or remove space before Objective-C protocol list + // as in '@protocol Protocol<here><Protocol_A>' or '@interface MyClass : NSObject<here><MyProtocol>'. + log_rule("sp_before_oc_proto_list"); + return(options::sp_before_oc_proto_list()); + } + + if ( language_is_set(LANG_OC) + && first->Is(CT_OC_CLASS) + && second->Is(CT_PAREN_OPEN) + && (options::sp_oc_classname_paren() != IARF_IGNORE)) + { + // (OC) Add or remove space between class name and '(' + // in '@interface className(categoryName)<ProtocolName>:BaseClass' + log_rule("sp_oc_classname_paren"); + return(options::sp_oc_classname_paren()); + } + + if ( first->Is(CT_CATCH) + && second->Is(CT_SPAREN_OPEN) + && (options::sp_catch_paren() != IARF_IGNORE)) + { + // Add or remove space between 'catch' and '(' in 'catch (something) { }'. + // If set to ignore, sp_before_sparen is used. + log_rule("sp_catch_paren"); + return(options::sp_catch_paren()); + } + + if ( language_is_set(LANG_D) + && first->Is(CT_D_VERSION_IF) + && second->Is(CT_SPAREN_OPEN) + && (options::sp_version_paren() != IARF_IGNORE)) + { + // (D) Add or remove space between 'version' and '(' + // in 'version (something) { }'. If set to ignore, sp_before_sparen is used. + log_rule("sp_version_paren"); + return(options::sp_version_paren()); + } + + if ( language_is_set(LANG_D) + && first->Is(CT_D_SCOPE_IF) + && second->Is(CT_SPAREN_OPEN) + && (options::sp_scope_paren() != IARF_IGNORE)) + { + // (D) Add or remove space between 'scope' and '(' + // in 'scope (something) { }'. If set to ignore, sp_before_sparen is used. + log_rule("sp_scope_paren"); + return(options::sp_scope_paren()); + } + + if ( language_is_set(LANG_OC) + && first->Is(CT_SYNCHRONIZED) + && second->Is(CT_SPAREN_OPEN)) + { + // (OC) Add or remove space between '@synchronized' and the open parenthesis, + // i.e. '@synchronized(foo)' vs. '@synchronized (foo)'. + log_rule("sp_after_oc_synchronized"); + return(options::sp_after_oc_synchronized()); + } + + // "if (" vs. "if(" + if (second->Is(CT_SPAREN_OPEN)) + { + // Add or remove space after 'do' between 'while' and '('. Issue #995 + if ( first->Is(CT_WHILE_OF_DO) + && options::sp_while_paren_open() != IARF_IGNORE) + { + log_rule("sp_while_paren_open"); + return(options::sp_while_paren_open()); + } + // Add or remove space before '(' of other control statements ('if', 'for', + // 'switch', 'while', etc.). + log_rule("sp_before_sparen"); + return(options::sp_before_sparen()); + } + + if ( first->Is(CT_LAMBDA) + || second->Is(CT_LAMBDA)) + { + // Add or remove space around assignment operator '=', '+=', etc. + log_rule("sp_assign (lambda)"); + return(options::sp_assign()); + } + + // Handle the special lambda case for C++11: + // [=](Something arg){.....} + // Add or remove space around '=' in C++11 lambda capture specifications. + // Overrides sp_assign. + if ( (options::sp_cpp_lambda_assign() != IARF_IGNORE) + && ( ( first->Is(CT_SQUARE_OPEN) + && first->GetParentType() == CT_CPP_LAMBDA + && second->Is(CT_ASSIGN)) + || ( first->Is(CT_ASSIGN) + && second->Is(CT_SQUARE_CLOSE) + && second->GetParentType() == CT_CPP_LAMBDA))) + { + log_rule("sp_cpp_lambda_assign"); + return(options::sp_cpp_lambda_assign()); + } + + if ( first->Is(CT_SQUARE_CLOSE) + && first->GetParentType() == CT_CPP_LAMBDA) + { + // Handle the special lambda case for C++11: + // [](Something arg){.....} + // Add or remove space after the capture specification of a C++11 lambda when + // an argument list is present, as in '[] <here> (int x){ ... }'. + if (second->Is(CT_LPAREN_OPEN)) + { + log_rule("sp_cpp_lambda_square_paren"); + return(options::sp_cpp_lambda_square_paren()); + } + else if (second->Is(CT_BRACE_OPEN)) + { + // Add or remove space after the capture specification of a C++11 lambda with + // no argument list is present, as in '[] <here> { ... }'. + log_rule("sp_cpp_lambda_square_brace"); + return(options::sp_cpp_lambda_square_brace()); + } + } + + if (first->Is(CT_LPAREN_OPEN)) + { + // Add or remove space after the opening parenthesis of a argument list + // of a C++11 lambda, as in '[]( <here> int x ){ ... }'. + log_rule("sp_cpp_lambda_argument_list"); + return(options::sp_cpp_lambda_argument_list()); + } + + if (first->Is(CT_LPAREN_CLOSE)) + { + if (second->Is(CT_BRACE_OPEN)) + { + // Add or remove space after the argument list of a C++11 lambda, as in + // '[](int x) <here> { ... }'. + log_rule("sp_cpp_lambda_paren_brace"); + return(options::sp_cpp_lambda_paren_brace()); + } + } + + if (second->Is(CT_LPAREN_CLOSE)) + { + // Add or remove space before the closing parenthesis of a argument list + // of a C++11 lambda, as in '[]( int x <here> ){ ... }'. + log_rule("sp_cpp_lambda_argument_list"); + return(options::sp_cpp_lambda_argument_list()); + } + + if ( first->Is(CT_BRACE_CLOSE) + && first->GetParentType() == CT_CPP_LAMBDA + && second->Is(CT_FPAREN_OPEN)) + { + // Add or remove space between a lambda body and its call operator of an + // immediately invoked lambda, as in '[]( ... ){ ... } <here> ( ... )'. + log_rule("sp_cpp_lambda_fparen"); + return(options::sp_cpp_lambda_fparen()); + } + + if (first->Is(CT_ENUM)) + { + if (second->Is(CT_BRACE_OPEN)) + { + // Add or remove space in 'enum {'. + log_rule("sp_enum_brace"); + return(options::sp_enum_brace()); + } + else if (second->Is(CT_FPAREN_OPEN)) + { + // Add or remove space in 'NS_ENUM ('. + log_rule("sp_enum_paren"); + return(options::sp_enum_paren()); + } + } + + if (second->Is(CT_ASSIGN)) + { + if (second->TestFlags(PCF_IN_ENUM)) + { + // Add or remove space before assignment '=' in enum. + // Overrides sp_enum_assign. + if (options::sp_enum_before_assign() != IARF_IGNORE) + { + log_rule("sp_enum_before_assign"); + return(options::sp_enum_before_assign()); + } + // Add or remove space around assignment '=' in enum. + log_rule("sp_enum_assign"); + return(options::sp_enum_assign()); + } + + // Add or remove space around assignment operator '=' in a prototype. + // If set to ignore, use sp_assign. + if ( (options::sp_assign_default() != IARF_IGNORE) + && second->GetParentType() == CT_FUNC_PROTO) + { + log_rule("sp_assign_default"); + return(options::sp_assign_default()); + } + + // Add or remove space before assignment operator '=', '+=', etc. + // Overrides sp_assign. + if (options::sp_before_assign() != IARF_IGNORE) + { + log_rule("sp_before_assign"); + return(options::sp_before_assign()); + } + // Add or remove space around assignment operator '=', '+=', etc. + log_rule("sp_assign"); + return(options::sp_assign()); + } + + if (second->Is(CT_ASSIGN_DEFAULT_ARG)) + { + // Add or remove space around assignment operator '=' in a prototype. + // If set to ignore, use sp_assign. + if ( (options::sp_assign_default() != IARF_IGNORE) + && second->GetParentType() == CT_FUNC_PROTO) + { + log_rule("sp_assign_default"); + return(options::sp_assign_default()); + } + + // Add or remove space before assignment operator '=', '+=', etc. + // Overrides sp_assign. + if (options::sp_before_assign() != IARF_IGNORE) + { + log_rule("sp_before_assign"); + return(options::sp_before_assign()); + } + // Add or remove space around assignment operator '=', '+=', etc. + log_rule("sp_assign"); + return(options::sp_assign()); + } + + if (first->Is(CT_ASSIGN)) + { + if (first->TestFlags(PCF_IN_ENUM)) + { + // Add or remove space after assignment '=' in enum. + // Overrides sp_enum_assign. + if (options::sp_enum_after_assign() != IARF_IGNORE) + { + log_rule("sp_enum_after_assign"); + return(options::sp_enum_after_assign()); + } + // Add or remove space around assignment '=' in enum. + log_rule("sp_enum_assign"); + return(options::sp_enum_assign()); + } + + // Add or remove space around assignment operator '=' in a prototype. + // If set to ignore, use sp_assign. + if ( (options::sp_assign_default() != IARF_IGNORE) + && first->GetParentType() == CT_FUNC_PROTO) + { + log_rule("sp_assign_default"); + return(options::sp_assign_default()); + } + + // Add or remove space after assignment operator '=', '+=', etc. + // Overrides sp_assign. + if (options::sp_after_assign() != IARF_IGNORE) + { + log_rule("sp_after_assign"); + return(options::sp_after_assign()); + } + // Add or remove space around assignment operator '=', '+=', etc. + log_rule("sp_assign"); + return(options::sp_assign()); + } + + if ( first->Is(CT_TRAILING_RET) + || first->Is(CT_CPP_LAMBDA_RET) + || second->Is(CT_TRAILING_RET) + || second->Is(CT_CPP_LAMBDA_RET)) + { + // Add or remove space around trailing return operator '->'. + log_rule("sp_trailing_return"); + return(options::sp_trailing_return()); + } + + if (first->Is(CT_ASSIGN_DEFAULT_ARG)) + { + // Add or remove space around assignment operator '=' in a prototype. + // If set to ignore, use sp_assign. + if ( (options::sp_assign_default() != IARF_IGNORE) + && first->GetParentType() == CT_FUNC_PROTO) + { + log_rule("sp_assign_default"); + return(options::sp_assign_default()); + } + + // Add or remove space after assignment operator '=', '+=', etc. + // Overrides sp_assign. + if (options::sp_after_assign() != IARF_IGNORE) + { + log_rule("sp_after_assign"); + return(options::sp_after_assign()); + } + // Add or remove space around assignment operator '=', '+=', etc. + log_rule("sp_assign"); + return(options::sp_assign()); + } + + if (first->Is(CT_BIT_COLON)) + { + if ( first->TestFlags(PCF_IN_ENUM) + || first->GetParentType() == CT_ENUM) + { + // Add or remove space around assignment ':' in enum. + log_rule("sp_enum_colon"); + return(options::sp_enum_colon()); + } + } + + if (second->Is(CT_BIT_COLON)) + { + if ( second->TestFlags(PCF_IN_ENUM) + || second->GetParentType() == CT_ENUM) + { + // Add or remove space around assignment ':' in enum. + log_rule("sp_enum_colon"); + return(options::sp_enum_colon()); + } + } + + if ( first->Is(CT_OC_AVAILABLE_VALUE) + || second->Is(CT_OC_AVAILABLE_VALUE)) + { + log_rule("IGNORE"); + return(IARF_IGNORE); + } + + if (language_is_set(LANG_OC)) + { + if (second->Is(CT_OC_BLOCK_CARET)) + { + // (OC) Add or remove space before a block pointer caret, + // i.e. '^int (int arg){...}' vs. ' ^int (int arg){...}'. + log_rule("sp_before_oc_block_caret"); + return(options::sp_before_oc_block_caret()); + } + + if (first->Is(CT_OC_BLOCK_CARET)) + { + // (OC) Add or remove space after a block pointer caret, + // i.e. '^int (int arg){...}' vs. '^ int (int arg){...}'. + log_rule("sp_after_oc_block_caret"); + return(options::sp_after_oc_block_caret()); + } + + if (second->Is(CT_OC_MSG_FUNC)) + { + if ( (options::sp_after_oc_msg_receiver() == IARF_REMOVE) + && ( first->IsNot(CT_SQUARE_CLOSE) + && first->IsNot(CT_FPAREN_CLOSE) + && first->IsNot(CT_PAREN_CLOSE))) + { + log_rule("FORCE"); + return(IARF_FORCE); + } + // (OC) Add or remove space between the receiver and selector in a message, + // as in '[receiver selector ...]'. + log_rule("sp_after_oc_msg_receiver"); + return(options::sp_after_oc_msg_receiver()); + } + } + + // c++17 structured bindings e.g., "auto [x, y, z]" vs. a[x, y, z]" or "auto const [x, y, z]" vs. "auto const[x, y, z]" + if ( language_is_set(LANG_CPP) + && ( first->Is(CT_BYREF) + || first->Is(CT_QUALIFIER) + || first->Is(CT_TYPE)) + && second->Is(CT_SQUARE_OPEN) + && second->GetParentType() != CT_OC_MSG + && second->GetParentType() != CT_CS_SQ_STMT) + { + // Add or remove space before C++17 structured bindings. + log_rule("sp_cpp_before_struct_binding"); + return(options::sp_cpp_before_struct_binding()); + } + + // "a [x]" vs. "a[x]" + if ( second->Is(CT_SQUARE_OPEN) + && ( second->GetParentType() != CT_OC_MSG + && second->GetParentType() != CT_CS_SQ_STMT + && second->GetParentType() != CT_CPP_LAMBDA)) + { + if ( second->TestFlags(PCF_IN_SPAREN) + && (first->Is(CT_IN))) + { + log_rule("FORCE"); + return(IARF_FORCE); + } + + if (first->Is(CT_ASM_COLON)) + { + // Add or remove space before '[' for asm block. + log_rule("sp_before_square_asm_block"); + return(options::sp_before_square_asm_block()); + } + + if (first->TestFlags(PCF_VAR_DEF)) + { + // Add or remove space before '[' for a variable definition. + log_rule("sp_before_vardef_square"); + return(options::sp_before_vardef_square()); + } + // Add or remove space before '[' (except '[]'). + log_rule("sp_before_square"); + return(options::sp_before_square()); + } + + // "byte[]" vs. "byte []" + if (second->Is(CT_TSQUARE)) + { + // Add or remove space before '[]'. + log_rule("sp_before_squares"); + return(options::sp_before_squares()); + } + + if ( (options::sp_angle_shift() != IARF_IGNORE) + && first->Is(CT_ANGLE_CLOSE) + && second->Is(CT_ANGLE_CLOSE)) + { + // Add or remove space between '>' and '>' in '>>' (template stuff). + log_rule("sp_angle_shift"); + return(options::sp_angle_shift()); + } + + // spacing around template < > stuff + if ( first->Is(CT_ANGLE_OPEN) + || second->Is(CT_ANGLE_CLOSE)) + { + if ( first->Is(CT_ANGLE_OPEN) + && second->Is(CT_ANGLE_CLOSE)) + { + // Add or remove space inside '<>'. + log_rule("sp_inside_angle_empty"); + return(options::sp_inside_angle_empty()); + } + // Add or remove space inside '<' and '>'. + log_rule("sp_inside_angle"); + iarf_e op = options::sp_inside_angle(); + + // special: if we're not supporting digraphs, then we shouldn't create them! + if ( (op == IARF_REMOVE) + && !options::enable_digraphs() + && first->Is(CT_ANGLE_OPEN) + && second->Is(CT_DC_MEMBER)) + { + op = IARF_IGNORE; + } + return(op); + } + + if (second->Is(CT_ANGLE_OPEN)) + { + if ( first->Is(CT_TEMPLATE) + && (options::sp_template_angle() != IARF_IGNORE)) + { + // Add or remove space between 'template' and '<'. + // If set to ignore, sp_before_angle is used. + log_rule("sp_template_angle"); + return(options::sp_template_angle()); + } + + if (first->IsNot(CT_QUALIFIER)) + { + // Add or remove space before '<'. + log_rule("sp_before_angle"); + return(options::sp_before_angle()); + } + } + + if (first->Is(CT_ANGLE_CLOSE)) + { + if ( second->Is(CT_WORD) + || CharTable::IsKw1(second->GetStr()[0])) + { + // Add or remove space between '>' and a word as in 'List<byte> m;' or + // 'template <typename T> static ...'. + log_rule("sp_angle_word"); + return(options::sp_angle_word()); + } + + if ( second->Is(CT_FPAREN_OPEN) + || second->Is(CT_PAREN_OPEN)) + { + Chunk *next = second->GetNextNcNnl(); + + if (next->Is(CT_FPAREN_CLOSE)) + { + // Add or remove space between '>' and '()' as found in 'new List<byte>();'. + log_rule("sp_angle_paren_empty"); + return(options::sp_angle_paren_empty()); + } + // Add or remove space between '>' and '(' as found in 'new List<byte>(foo);'. + log_rule("sp_angle_paren"); + return(options::sp_angle_paren()); + } + + if (second->Is(CT_DC_MEMBER)) + { + // Add or remove space before the '::' operator. + log_rule("sp_before_dc"); + return(options::sp_before_dc()); + } + + if ( second->IsNot(CT_BYREF) + && second->IsNot(CT_PTR_TYPE) + && second->IsNot(CT_BRACE_OPEN) + && second->IsNot(CT_PAREN_CLOSE)) + { + if ( second->Is(CT_CLASS_COLON) + && options::sp_angle_colon() != IARF_IGNORE) + { + // Add or remove space between '>' and ':'. + log_rule("sp_angle_colon"); + return(options::sp_angle_colon()); + } + + // Whether sp_after_angle takes precedence over sp_inside_fparen. This was the + // historic behavior, but is probably not the desired behavior, so this is off + // by default. + if ( second->Is(CT_FPAREN_CLOSE) + && options::sp_inside_fparen() != IARF_IGNORE + && !options::use_sp_after_angle_always()) + { + // Add or remove space between '>' and ')'. + log_rule("sp_inside_fparen"); + return(options::sp_inside_fparen()); + } + // Add or remove space after '>'. + log_rule("sp_after_angle"); + return(options::sp_after_angle()); + } + } + + if (first->Is(CT_BYREF)) // see the tests cpp:34509-34512 + { + if (second->Is(CT_PAREN_OPEN)) + { + // Add or remove space after a reference sign '&', if followed by an open + // parenthesis, as in 'char& (*)()'. + log_rule("sp_byref_paren"); + return(options::sp_byref_paren()); + } + else if ( first->GetParentType() == CT_FUNC_DEF // Issue #3197, #3210 + || first->GetParentType() == CT_FUNC_PROTO) + { + // Add or remove space after a reference sign '&', if followed by a function + // prototype or function definition. + log_rule("sp_after_byref_func"); // byref 2 + return(options::sp_after_byref_func()); + } + else if ( CharTable::IsKw1(second->GetStr()[0]) + && ( options::sp_after_byref() != IARF_IGNORE + || ( !second->Is(CT_FUNC_PROTO) + && !second->Is(CT_FUNC_DEF)))) + { + // Add or remove space after reference sign '&', if followed by a word. + log_rule("sp_after_byref"); // byref 1 + return(options::sp_after_byref()); + } + } + + if ( second->Is(CT_BYREF) + && !first->Is(CT_PAREN_OPEN)) // Issue #1804 + { + if ( second->GetParentType() == CT_FUNC_DEF // Issue #3197, #3210 + || second->GetParentType() == CT_FUNC_PROTO) + { + // Add or remove space before a reference sign '&', if followed by a function + // prototype or function definition. + log_rule("sp_before_byref_func"); // byref 4 + return(options::sp_before_byref_func()); + } + Chunk *next = second->GetNext(); + + if ( next->IsNotNullChunk() + && ( next->Is(CT_COMMA) + || next->Is(CT_PAREN_CLOSE) // Issue #3691 + || next->Is(CT_FPAREN_CLOSE) + || next->Is(CT_SEMICOLON))) + { + if (options::sp_before_unnamed_byref() != IARF_IGNORE) // Issue #3691 + { + // Add or remove space before a reference sign '&' that isn't followed by a + // variable name. If set to 'ignore', sp_before_byref is used instead. + log_rule("sp_before_unnamed_byref"); // byref 5 + return(options::sp_before_unnamed_byref()); + } + else + { + // Add or remove space before a reference sign '&'. + log_rule("sp_before_byref"); // byref 3 + return(options::sp_before_byref()); + } + } + // Add or remove space before a reference sign '&'. + log_rule("sp_before_byref"); // byref 3 + return(options::sp_before_byref()); + } + + if (first->Is(CT_SPAREN_CLOSE)) + { + if (second->Is(CT_BRACE_OPEN)) + { + if (second->GetParentType() == CT_CATCH) + { + if ( language_is_set(LANG_OC) + && (options::sp_oc_catch_brace() != IARF_IGNORE)) + { + // (OC) Add or remove space before the '{' of a '@catch' statement, if the '{' + // and '@catch' are on the same line, as in '@catch (decl) <here> {'. + // If set to ignore, sp_catch_brace is used. + // only to help the vim command }} + log_rule("sp_oc_catch_brace"); + return(options::sp_oc_catch_brace()); + } + + if (options::sp_catch_brace() != IARF_IGNORE) + { + // Add or remove space before the '{' of a 'catch' statement, if the '{' and + // 'catch' are on the same line, as in 'catch (decl) <here> {'. + log_rule("sp_catch_brace"); + return(options::sp_catch_brace()); + } + } + + if (options::sp_sparen_brace() != IARF_IGNORE) + { + // Add or remove space between ')' and '{' of control statements. + log_rule("sp_sparen_brace"); + return(options::sp_sparen_brace()); + } + } + + if ( !second->IsComment() + && (options::sp_after_sparen() != IARF_IGNORE)) + { + // Add or remove space after ')' of control statements. + log_rule("sp_after_sparen"); + return(options::sp_after_sparen()); + } + } + + if ( second->Is(CT_FPAREN_OPEN) + && first->GetParentType() == CT_OPERATOR + && (options::sp_after_operator_sym() != IARF_IGNORE)) + { + if ( (options::sp_after_operator_sym_empty() != IARF_IGNORE) + && second->Is(CT_FPAREN_OPEN)) + { + Chunk *next = second->GetNextNcNnl(); + + if (next->Is(CT_FPAREN_CLOSE)) + { + // Overrides sp_after_operator_sym when the operator has no arguments, as in + // 'operator *()'. + log_rule("sp_after_operator_sym_empty"); + return(options::sp_after_operator_sym_empty()); + } + } + // Add or remove space between the operator symbol and the open parenthesis, as + // in 'operator ++('. + log_rule("sp_after_operator_sym"); + return(options::sp_after_operator_sym()); + } + + // Issue #2270 + // Translations under vala + if ( language_is_set(LANG_VALA) + && first->Is(CT_FUNC_CALL)) + { + if ( first->IsString("_") + && second->Is(CT_FPAREN_OPEN) + && (options::sp_vala_after_translation() != IARF_IGNORE)) + { + // Add or remove space after '_'. + log_rule("sp_vala_after_translation"); + return(options::sp_vala_after_translation()); + } + } + + if ( first->Is(CT_MACRO_OPEN) + || first->Is(CT_MACRO_CLOSE) + || first->Is(CT_MACRO_ELSE)) + { + if (second->Is(CT_FPAREN_OPEN)) + { + // TODO: provide some test data to check this block + // Add or remove space between function name and '(' on function calls. + log_rule("sp_func_call_paren"); + return(options::sp_func_call_paren()); + } + log_rule("IGNORE"); + return(IARF_IGNORE); + } + + // spaces between function and open paren + if ( first->Is(CT_FUNC_CALL) + || first->Is(CT_FUNCTION) // Issue #2665 + || first->Is(CT_FUNC_CTOR_VAR) + || first->Is(CT_CNG_HASINC) + || first->Is(CT_CNG_HASINCN) + || ( first->Is(CT_BRACE_CLOSE) + && first->GetParentType() == CT_BRACED_INIT_LIST + && second->Is(CT_FPAREN_OPEN)) + || ( first->Is(CT_FUNC_VAR) // Issue #3852 + && second->Is(CT_PAREN_OPEN))) + { + if ( (options::sp_func_call_paren_empty() != IARF_IGNORE) + && second->Is(CT_FPAREN_OPEN)) + { + Chunk *next = second->GetNextNcNnl(); + + if (next->Is(CT_FPAREN_CLOSE)) + { + // Add or remove space between function name and '()' on function calls without + // parameters. If set to 'ignore' (the default), sp_func_call_paren is used. + log_rule("sp_func_call_paren_empty"); + return(options::sp_func_call_paren_empty()); + } + } + // Add or remove space between function name and '(' on function calls. + log_rule("sp_func_call_paren"); + return(options::sp_func_call_paren()); + } + + if (first->Is(CT_FUNC_CALL_USER)) + { + // Add or remove space between the user function name and '(' on function + // calls. You need to set a keyword to be a user function in the config file, + // like: + // set func_call_user tr _ i18n + log_rule("sp_func_call_user_paren"); + return(options::sp_func_call_user_paren()); + } + + if ( first->Is(CT_ATTRIBUTE) + && second->IsParenOpen()) + { + // Add or remove space between '__attribute__' and '('. + log_rule("sp_attribute_paren"); + return(options::sp_attribute_paren()); + } + + if (first->Is(CT_FUNC_DEF)) + { + if ( (options::sp_func_def_paren_empty() != IARF_IGNORE) + && second->Is(CT_FPAREN_OPEN)) + { + Chunk *next = second->GetNextNcNnl(); + + if (next->Is(CT_FPAREN_CLOSE)) + { + // Add or remove space between function name and '()' on function definition + // without parameters. + log_rule("sp_func_def_paren_empty"); + return(options::sp_func_def_paren_empty()); + } + } + // Add or remove space between function name and '(' on function definition. + log_rule("sp_func_def_paren"); + return(options::sp_func_def_paren()); + } + + if ( first->Is(CT_CPP_CAST) + || first->Is(CT_TYPE_WRAP)) + { + // Add or remove space between the type and open parenthesis in a C++ cast, + // i.e. 'int(exp)' vs. 'int (exp)'. + log_rule("sp_cpp_cast_paren"); + return(options::sp_cpp_cast_paren()); + } + + if ( first->Is(CT_SPAREN_CLOSE) + && second->Is(CT_WHEN)) + { + // TODO: provide some test data to check this block + log_rule("FORCE"); + return(IARF_FORCE); // TODO: make this configurable? + } + + if ( first->Is(CT_PAREN_CLOSE) + && ( second->Is(CT_PAREN_OPEN) + || second->Is(CT_FPAREN_OPEN))) + { + // "(int)a" vs. "(int) a" or "cast(int)a" vs. "cast(int) a" + if ( first->GetParentType() == CT_C_CAST + || first->GetParentType() == CT_D_CAST) + { + // Add or remove space after C/D cast, i.e. 'cast(int)a' vs. 'cast(int) a' or + // '(int)a' vs. '(int) a'. + log_rule("sp_after_cast"); + return(options::sp_after_cast()); + } + // Probably a parenthesized indirect function call or similar (issue #3260) + log_rule("sp_cparen_oparen"); + return(options::sp_cparen_oparen()); + } + + // handle the space between parens in fcn type 'void (*f)(void)' + if (first->Is(CT_TPAREN_CLOSE)) + { + // Add or remove space between the ')' and '(' in a function type, as in + // 'void (*x)(...)'. + log_rule("sp_after_tparen_close"); + return(options::sp_after_tparen_close()); + } + + // ")(" vs. ") (" + if ( ( first->IsString(")") + && second->IsString("(")) + || ( first->IsParenClose() + && second->IsParenOpen())) + { + // Add or remove space between back-to-back parentheses, i.e. ')(' vs. ') ('. + log_rule("sp_cparen_oparen"); + return(options::sp_cparen_oparen()); + } + + if ( first->Is(CT_FUNC_PROTO) + || ( second->Is(CT_FPAREN_OPEN) + && second->GetParentType() == CT_FUNC_PROTO)) + { + if ( (options::sp_func_proto_paren_empty() != IARF_IGNORE) + && second->Is(CT_FPAREN_OPEN)) + { + Chunk *next = second->GetNextNcNnl(); + + if (next->Is(CT_FPAREN_CLOSE)) + { + // Add or remove space between function name and '()' on function declaration + // without parameters. + log_rule("sp_func_proto_paren_empty"); + return(options::sp_func_proto_paren_empty()); + } + } + // Add or remove space between function name and '(' on function declaration. + log_rule("sp_func_proto_paren"); + return(options::sp_func_proto_paren()); + } + + // Issue #2437 + if ( first->Is(CT_FUNC_TYPE) + && second->Is(CT_FPAREN_OPEN)) + { + // Add or remove space between function name and '(' with a typedef specifier. + log_rule("sp_func_type_paren"); + return(options::sp_func_type_paren()); + } + + if ( first->Is(CT_FUNC_CLASS_DEF) + || first->Is(CT_FUNC_CLASS_PROTO)) + { + if ( (options::sp_func_class_paren_empty() != IARF_IGNORE) + && second->Is(CT_FPAREN_OPEN)) + { + Chunk *next = second->GetNextNcNnl(); + + if (next->Is(CT_FPAREN_CLOSE)) + { + // Add or remove space between a constructor without parameters or destructor + // and '()'. + log_rule("sp_func_class_paren_empty"); + return(options::sp_func_class_paren_empty()); + } + } + // Add or remove space between a constructor/destructor and the open + // parenthesis. + log_rule("sp_func_class_paren"); + return(options::sp_func_class_paren()); + } + + if ( first->Is(CT_CLASS) + && !first->TestFlags(PCF_IN_OC_MSG)) + { + log_rule("FORCE"); + return(IARF_FORCE); + } + + if ( first->Is(CT_BRACE_OPEN) + && second->Is(CT_BRACE_CLOSE)) + { + // Add or remove space inside '{}'. + log_rule("sp_inside_braces_empty"); + return(options::sp_inside_braces_empty()); + } + + if ( ( first->Is(CT_TYPE) // Issue #2428 + || first->Is(CT_ANGLE_CLOSE)) + && second->Is(CT_BRACE_OPEN) + && second->GetParentType() == CT_BRACED_INIT_LIST) + { + iarf_flags_t arg = iarf_flags_t{ options::sp_type_brace_init_lst() }; + + if ( arg != IARF_IGNORE + || first->GetParentType() != CT_DECLTYPE) + { + // 'int{9}' vs. 'int {9}' + // Add or remove space between type and open brace of an unnamed temporary + // direct-list-initialization. + log_rule("sp_type_brace_init_lst"); + return(arg); + } + } + + if ( ( first->Is(CT_WORD) // Issue #2428 + || first->Is(CT_SQUARE_CLOSE) + || first->Is(CT_TSQUARE)) + && second->Is(CT_BRACE_OPEN) + && second->GetParentType() == CT_BRACED_INIT_LIST) + { + // Add or remove space between a variable and '{' for C++ uniform + // initialization. + auto arg = iarf_flags_t{ options::sp_word_brace_init_lst() }; + + if ( arg != IARF_IGNORE + || first->GetParentType() != CT_DECLTYPE) + { + // 'a{9}' vs. 'a {9}' + // Add or remove space between variable/word and open brace of an unnamed + // temporary direct-list-initialization. + log_rule("sp_word_brace_init_lst"); + return(arg); + } + } + + if (second->Is(CT_BRACE_CLOSE)) + { + if (second->GetParentType() == CT_ENUM) + { + // Add or remove space inside enum '{' and '}'. + log_rule("sp_inside_braces_enum"); + return(options::sp_inside_braces_enum()); + } + + if ( second->GetParentType() == CT_STRUCT + || second->GetParentType() == CT_UNION) + { + // Fix for issue #1240 adding space in struct initializers + Chunk *tmp = second->GetOpeningParen()->GetPrevNcNnl(); + + if (tmp->Is(CT_ASSIGN)) + { + // TODO: provide some test data to check this block + log_rule("IGNORE"); + return(IARF_IGNORE); + } + // Add or remove space inside struct/union '{' and '}'. + log_rule("sp_inside_braces_struct"); + return(options::sp_inside_braces_struct()); + } + else if ( language_is_set(LANG_OC) + && second->GetParentType() == CT_OC_AT + && options::sp_inside_braces_oc_dict() != IARF_IGNORE) + { + // (OC) Add or remove space inside Objective-C boxed dictionary '{' and '}' + log_rule("sp_inside_braces_oc_dict"); + return(options::sp_inside_braces_oc_dict()); + } + + if (second->GetParentType() == CT_BRACED_INIT_LIST) + { + // Add or remove space between nested braces, i.e. '{{' vs. '{ {'. + // only to help the vim command }}}} + if ( options::sp_brace_brace() != IARF_IGNORE + && first->Is(CT_BRACE_CLOSE) + && first->GetParentType() == CT_BRACED_INIT_LIST) + { + log_rule("sp_brace_brace"); + return(options::sp_brace_brace()); + } + + if (options::sp_before_type_brace_init_lst_close() != IARF_IGNORE) + { + // Add or remove space before close brace in an unnamed temporary + // direct-list-initialization + // if statement is a brace_init_lst + // works only if sp_brace_brace is set to ignore. + log_rule("sp_before_type_brace_init_lst_close"); + return(options::sp_before_type_brace_init_lst_close()); + } + + if (options::sp_inside_type_brace_init_lst() != IARF_IGNORE) + { + // Add or remove space inside an unnamed temporary direct-list-initialization. + // if statement is a brace_init_lst + // works only if sp_brace_brace is set to ignore + // works only if sp_before_type_brace_init_lst_close is set to ignore. + log_rule("sp_inside_type_brace_init_lst"); + return(options::sp_inside_type_brace_init_lst()); + } + } + // Add or remove space inside '{' and '}'. + log_rule("sp_inside_braces"); + return(options::sp_inside_braces()); + } + + if (first->Is(CT_D_CAST)) + { + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if ( first->Is(CT_PP_DEFINED) + && second->Is(CT_PAREN_OPEN)) + { + // Add or remove space between 'defined' and '(' in '#if defined (FOO)'. + log_rule("sp_defined_paren"); + return(options::sp_defined_paren()); + } + + if (first->Is(CT_THROW)) + { + if (second->Is(CT_PAREN_OPEN)) + { + // Add or remove space between 'throw' and '(' in 'throw (something)'. + log_rule("sp_throw_paren"); + return(options::sp_throw_paren()); + } + // Add or remove space between 'throw' and anything other than '(' as in + // '@throw [...];'. + log_rule("sp_after_throw"); + return(options::sp_after_throw()); + } + + if ( first->Is(CT_THIS) + && second->Is(CT_PAREN_OPEN)) + { + // Add or remove space between 'this' and '(' in 'this (something)'. + log_rule("sp_this_paren"); + return(options::sp_this_paren()); + } + + if ( first->Is(CT_STATE) + && second->Is(CT_PAREN_OPEN)) + { + log_rule("ADD"); + return(IARF_ADD); + } + + if ( first->Is(CT_DELEGATE) + && second->Is(CT_PAREN_OPEN)) + { + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if ( first->Is(CT_MEMBER) + || second->Is(CT_MEMBER)) + { + // Add or remove space around the '.' or '->' operators. + log_rule("sp_member"); + return(options::sp_member()); + } + + if (first->Is(CT_C99_MEMBER)) + { + // always remove space(s) after then '.' of a C99-member + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if ( first->Is(CT_SUPER) + && second->Is(CT_PAREN_OPEN)) + { + // Add or remove space between 'super' and '(' in 'super (something)'. + log_rule("sp_super_paren"); + return(options::sp_super_paren()); + } + + if ( first->Is(CT_FPAREN_CLOSE) + && second->Is(CT_BRACE_OPEN)) + { + if ( language_is_set(LANG_JAVA) + && second->GetParentType() == CT_DOUBLE_BRACE) + { + // (Java) Add or remove space between ')' and '{{' of double brace initializer. + // only to help the vim command }} + log_rule("sp_fparen_dbrace"); + return(options::sp_fparen_dbrace()); + } + + // To fix issue #1234 + // check for initializers and add space or ignore based on the option. + if (first->GetParentType() == CT_FUNC_CALL) + { + Chunk *tmp = first->GetPrevType(first->GetParentType(), first->GetLevel()); + tmp = tmp->GetPrevNcNnl(); + + if (tmp->Is(CT_NEW)) + { + // Add or remove space between ')' and '{' of s function call in object + // initialization. + // Overrides sp_fparen_brace. + log_rule("sp_fparen_brace_initializer"); + return(options::sp_fparen_brace_initializer()); + } + } + // Add or remove space between ')' and '{' of function. + log_rule("sp_fparen_brace"); + return(options::sp_fparen_brace()); + } + + if ( first->Is(CT_D_TEMPLATE) + || second->Is(CT_D_TEMPLATE)) + { + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if ( first->Is(CT_ELSE) + && second->Is(CT_BRACE_OPEN)) + { + // Add or remove space between 'else' and '{' if on the same line. + log_rule("sp_else_brace"); + return(options::sp_else_brace()); + } + + if ( first->Is(CT_ELSE) + && second->Is(CT_ELSEIF)) + { + log_rule("FORCE"); + return(IARF_FORCE); + } + + if ( first->Is(CT_FINALLY) + && second->Is(CT_BRACE_OPEN)) + { + // Add or remove space between 'finally' and '{' if on the same line. + log_rule("sp_finally_brace"); + return(options::sp_finally_brace()); + } + + if ( first->Is(CT_TRY) + && second->Is(CT_BRACE_OPEN)) + { + // Add or remove space between 'try' and '{' if on the same line. + log_rule("sp_try_brace"); + return(options::sp_try_brace()); + } + + if ( first->Is(CT_GETSET) + && second->Is(CT_BRACE_OPEN)) + { + // Add or remove space between get/set and '{' if on the same line. + log_rule("sp_getset_brace"); + return(options::sp_getset_brace()); + } + + if ( first->Is(CT_WORD) + && second->Is(CT_BRACE_OPEN)) + { + if (first->GetParentType() == CT_NAMESPACE) + { + // Add or remove space between a variable and '{' for a namespace. + log_rule("sp_word_brace_ns"); + return(options::sp_word_brace_ns()); + } + } + + if ( language_is_set(LANG_D) + && second->Is(CT_PAREN_OPEN) + && second->GetParentType() == CT_INVARIANT) + { + // (D) Add or remove space between 'invariant' and '('. + log_rule("sp_invariant_paren"); + return(options::sp_invariant_paren()); + } + + if ( first->Is(CT_PAREN_CLOSE) + && first->GetParentType() != CT_DECLTYPE) + { + if ( language_is_set(LANG_D) + && first->GetParentType() == CT_INVARIANT) + { + // (D) Add or remove space after the ')' in 'invariant (C) c'. + log_rule("sp_after_invariant_paren"); + return(options::sp_after_invariant_paren()); + } + + // "(struct foo) {...}" vs. "(struct foo){...}" + if (second->Is(CT_BRACE_OPEN)) + { + // Add or remove space between ')' and '{'. + log_rule("sp_paren_brace"); + return(options::sp_paren_brace()); + } + + // D-specific: "delegate(some thing) dg + if (first->GetParentType() == CT_DELEGATE) + { + log_rule("ADD"); + return(IARF_ADD); + } + + // PAWN-specific: "state (condition) next" + if (first->GetParentType() == CT_STATE) + { + log_rule("ADD"); + return(IARF_ADD); + } + + /* C++ new operator: new(bar) Foo */ + if (first->GetParentType() == CT_NEW) + { + // Add or remove space between ')' and type in 'new(foo) BAR'. + log_rule("sp_after_newop_paren"); + return(options::sp_after_newop_paren()); + } + } + + /* "((" vs. "( (" or "))" vs. ") )" */ + // Issue #1342 + if ( ( first->IsString("(") + && second->IsString("(")) + || ( first->IsString(")") + && second->IsString(")"))) + { + if (second->GetParentType() == CT_FUNC_CALL_USER) + { + // Add or remove space between nested parentheses with user functions, + // i.e. '((' vs. '( ('. + log_rule("sp_func_call_user_paren_paren"); + return(options::sp_func_call_user_paren_paren()); + } + + if ( options::sp_sparen_paren() != IARF_IGNORE + && ( first->Is(CT_SPAREN_OPEN) + || second->Is(CT_SPAREN_CLOSE))) + { + // Add or remove space between nested parentheses with control + // statements, i.e. 'if ((' vs. 'if ( ('. Issue #3209 + log_rule("sp_sparen_paren"); + return(options::sp_sparen_paren()); + } + // Add or remove space between nested parentheses, i.e. '((' vs. ') )'. + log_rule("sp_paren_paren"); + return(options::sp_paren_paren()); + } + + // "foo(...)" vs. "foo( ... )" + if ( first->Is(CT_FPAREN_OPEN) + || second->Is(CT_FPAREN_CLOSE)) + { + if ( (first->GetParentType() == CT_FUNC_CALL_USER) + || ( (second->GetParentType() == CT_FUNC_CALL_USER) + && ( (first->Is(CT_WORD)) + || (first->Is(CT_SQUARE_CLOSE))))) + { + // Add or remove space inside user function '(' and ')'. + log_rule("sp_func_call_user_inside_fparen"); + return(options::sp_func_call_user_inside_fparen()); + } + + if ( first->Is(CT_FPAREN_OPEN) + && second->Is(CT_FPAREN_CLOSE)) + { + // Add or remove space inside empty function '()'. + log_rule("sp_inside_fparens"); + return(options::sp_inside_fparens()); + } + // Add or remove space inside function '(' and ')'. + log_rule("sp_inside_fparen"); + return(options::sp_inside_fparen()); + } + + // "foo(...)" vs. "foo( ... )" + if ( first->Is(CT_TPAREN_OPEN) + || second->Is(CT_TPAREN_CLOSE)) + { + // Add or remove space inside the first parentheses in a function type, as in + // 'void (*x)(...)'. + log_rule("sp_inside_tparen"); + return(options::sp_inside_tparen()); + } + + if ( language_is_set(LANG_OC) + && first->Is(CT_PAREN_CLOSE)) + { + if ( first->TestFlags(PCF_OC_RTYPE) // == CT_OC_RTYPE) + && ( first->GetParentType() == CT_OC_MSG_DECL + || first->GetParentType() == CT_OC_MSG_SPEC)) + { + // (OC) Add or remove space after the first (type) in message specs, + // i.e. '-(int) f:(int)x;' vs. '-(int)f:(int)x;'. + log_rule("sp_after_oc_return_type"); + return(options::sp_after_oc_return_type()); + } + + if ( first->GetParentType() == CT_OC_MSG_SPEC + || first->GetParentType() == CT_OC_MSG_DECL) + { + // (OC) Add or remove space after the (type) in message specs, + // i.e. '-(int)f: (int) x;' vs. '-(int)f: (int)x;'. + log_rule("sp_after_oc_type"); + return(options::sp_after_oc_type()); + } + + if ( first->GetParentType() == CT_OC_SEL + && second->IsNot(CT_SQUARE_CLOSE)) + { + // (OC) Add or remove space between '@selector(x)' and the following word, + // i.e. '@selector(foo) a:' vs. '@selector(foo)a:'. + log_rule("sp_after_oc_at_sel_parens"); + return(options::sp_after_oc_at_sel_parens()); + } + } + + if ( language_is_set(LANG_OC) + && options::sp_inside_oc_at_sel_parens() != IARF_IGNORE) + { + if ( ( first->Is(CT_PAREN_OPEN) + && ( first->GetParentType() == CT_OC_SEL + || first->GetParentType() == CT_OC_PROTOCOL)) + || ( second->Is(CT_PAREN_CLOSE) + && ( second->GetParentType() == CT_OC_SEL + || second->GetParentType() == CT_OC_PROTOCOL))) + { + // (OC) Add or remove space inside '@selector' parentheses, + // i.e. '@selector(foo)' vs. '@selector( foo )'. + // Also applies to '@protocol()' constructs. + log_rule("sp_inside_oc_at_sel_parens"); + return(options::sp_inside_oc_at_sel_parens()); + } + } + + if ( second->Is(CT_PAREN_OPEN) + && ( first->Is(CT_OC_SEL) + || first->Is(CT_OC_PROTOCOL))) + { + // (OC) Add or remove space between '@selector' and '(', + // i.e. '@selector(msgName)' vs. '@selector (msgName)'. + // Also applies to '@protocol()' constructs. + log_rule("sp_after_oc_at_sel"); + return(options::sp_after_oc_at_sel()); + } + + /* + * C cast: "(int)" vs. "( int )" + * D cast: "cast(int)" vs. "cast( int )" + * CPP cast: "int(a + 3)" vs. "int( a + 3 )" + */ + if (first->Is(CT_PAREN_OPEN)) + { + if ( first->GetParentType() == CT_C_CAST + || first->GetParentType() == CT_CPP_CAST + || first->GetParentType() == CT_D_CAST) + { + // Add or remove spaces inside cast parentheses. + log_rule("sp_inside_paren_cast"); + return(options::sp_inside_paren_cast()); + } + + if (first->GetParentType() == CT_NEW) + { + if (options::sp_inside_newop_paren_open() != IARF_IGNORE) + { + // Add or remove space after the open parenthesis of the new operator, + // as in 'new(foo) BAR'. + // Overrides sp_inside_newop_paren. + log_rule("sp_inside_newop_paren_open"); + return(options::sp_inside_newop_paren_open()); + } + + if (options::sp_inside_newop_paren() != IARF_IGNORE) + { + // Add or remove space inside parentheses of the new operator + // as in 'new(foo) BAR'. + log_rule("sp_inside_newop_paren"); + return(options::sp_inside_newop_paren()); + } + } + log_rule("sp_inside_paren"); + return(options::sp_inside_paren()); + } + + if (second->Is(CT_PAREN_CLOSE)) + { + if ( second->GetParentType() == CT_C_CAST + || second->GetParentType() == CT_CPP_CAST + || second->GetParentType() == CT_D_CAST) + { + // Add or remove spaces inside cast parentheses. + log_rule("sp_inside_paren_cast"); + return(options::sp_inside_paren_cast()); + } + + if (second->GetParentType() == CT_NEW) + { + if (options::sp_inside_newop_paren_close() != IARF_IGNORE) + { + // Add or remove space before the close parenthesis of the new operator, + // as in 'new(foo) BAR'. + // Overrides sp_inside_newop_paren. + log_rule("sp_inside_newop_paren_close"); + return(options::sp_inside_newop_paren_close()); + } + + if (options::sp_inside_newop_paren() != IARF_IGNORE) + { + // Add or remove space inside parentheses of the new operator + // as in 'new(foo) BAR'. + log_rule("sp_inside_newop_paren"); + return(options::sp_inside_newop_paren()); + } + } + // Add or remove space inside '(' and ')'. + log_rule("sp_inside_paren"); + return(options::sp_inside_paren()); + } + + if ( first->Is(CT_SQUARE_OPEN) + && second->Is(CT_SQUARE_CLOSE)) + { + // Add or remove space inside '[]'. + log_rule("sp_inside_square_empty"); + return(options::sp_inside_square_empty()); + } + + // "[3]" vs. "[ 3 ]" or for objective-c "@[@3]" vs. "@[ @3 ]" + if ( first->Is(CT_SQUARE_OPEN) + || second->Is(CT_SQUARE_CLOSE)) + { + if ( language_is_set(LANG_OC) + && ( ( first->GetParentType() == CT_OC_AT + && first->Is(CT_SQUARE_OPEN)) + || ( second->GetParentType() == CT_OC_AT + && second->Is(CT_SQUARE_CLOSE))) + && (options::sp_inside_square_oc_array() != IARF_IGNORE)) + { + // (OC) Add or remove space inside a non-empty Objective-C boxed array '@[' and + // ']'. If set to ignore, sp_inside_square is used. + log_rule("sp_inside_square_oc_array"); + return(options::sp_inside_square_oc_array()); + } + // Add or remove space inside a non-empty '[' and ']'. + log_rule("sp_inside_square"); + return(options::sp_inside_square()); + } + + if ( first->Is(CT_SQUARE_CLOSE) + && second->Is(CT_FPAREN_OPEN)) + { + // Add or remove space between ']' and '(' when part of a function call. + log_rule("sp_square_fparen"); + return(options::sp_square_fparen()); + } + + // "if(...)" vs. "if( ... )" etc. + if (second->Is(CT_SPAREN_CLOSE)) + { + if ( second->GetParentType() == CT_FOR + && options::sp_inside_for_open() != IARF_IGNORE) + { + // Add or remove space before ')' of 'for' statements. + // Overrides sp_inside_for. + log_rule("sp_inside_for_close"); + return(options::sp_inside_for_close()); + } + else if (options::sp_inside_sparen_open() != IARF_IGNORE) + { + // Add or remove space before ')' of other control statements. + // Overrides sp_inside_sparen. + log_rule("sp_inside_sparen_close"); + return(options::sp_inside_sparen_close()); + } + } + + if (first->Is(CT_SPAREN_OPEN)) + { + if ( first->GetParentType() == CT_FOR + && options::sp_inside_for_open() != IARF_IGNORE) + { + // Add or remove space before ')' of 'for' statements. + // Overrides sp_inside_for. + log_rule("sp_inside_for_close"); + return(options::sp_inside_for_close()); + } + else if (options::sp_inside_sparen_open() != IARF_IGNORE) + { + // Add or remove space after '(' of other control statements. + // Overrides sp_inside_sparen. + log_rule("sp_inside_sparen_open"); + return(options::sp_inside_sparen_open()); + } + } + + if (first->Is(CT_SPAREN_OPEN)) + { + if (first->GetParentType() == CT_FOR) + { + // Add or remove space inside '(' and ')' of 'for' statements. + log_rule("sp_inside_for"); + return(options::sp_inside_for()); + } + else + { + // Add or remove space inside '(' and ')' of other control statements. + log_rule("sp_inside_sparen"); + return(options::sp_inside_sparen()); + } + } + + if (second->Is(CT_SPAREN_CLOSE)) + { + if (second->GetParentType() == CT_FOR) + { + // Add or remove space inside '(' and ')' of 'for' statements. + log_rule("sp_inside_for"); + return(options::sp_inside_for()); + } + else + { + // Add or remove space inside '(' and ')' of other control statements. + log_rule("sp_inside_sparen"); + return(options::sp_inside_sparen()); + } + } + + if (first->Is(CT_CLASS_COLON)) + { + if ( first->GetParentType() == CT_OC_CLASS + && ( first->GetPrevType(CT_OC_INTF, first->GetLevel(), E_Scope::ALL)->IsNullChunk() + && first->GetPrevType(CT_OC_IMPL, first->GetLevel(), E_Scope::ALL)->IsNullChunk())) + { + if (options::sp_after_oc_colon() != IARF_IGNORE) + { + // TODO: provide some test data to check this block + // (OC) Add or remove space after the colon in message specs, + // i.e. '-(int) f:(int) x;' vs. '-(int) f: (int) x;'. + log_rule("sp_after_oc_colon"); + return(options::sp_after_oc_colon()); + } + } + + if (options::sp_after_class_colon() != IARF_IGNORE) + { + // Add or remove space after class ':'. + log_rule("sp_after_class_colon"); + return(options::sp_after_class_colon()); + } + } + + if (second->Is(CT_CLASS_COLON)) + { + if ( language_is_set(LANG_OC) + && second->GetParentType() == CT_OC_CLASS + && ( second->GetPrevType(CT_OC_INTF, second->GetLevel(), E_Scope::ALL)->IsNullChunk() + && second->GetPrevType(CT_OC_IMPL, second->GetLevel(), E_Scope::ALL)->IsNullChunk())) + { + if ( second->GetParentType() == CT_OC_CLASS + && second->GetPrevType(CT_OC_INTF, second->GetLevel(), E_Scope::ALL)->IsNullChunk()) + { + if (options::sp_before_oc_colon() != IARF_IGNORE) + { + // TODO: provide some test data to check this block + // (OC) Add or remove space before the colon in message specs, + // i.e. '-(int) f: (int) x;' vs. '-(int) f : (int) x;'. + log_rule("sp_before_oc_colon"); + return(options::sp_before_oc_colon()); + } + } + } + + if (options::sp_before_class_colon() != IARF_IGNORE) + { + // Add or remove space before class ':'. + log_rule("sp_before_class_colon"); + return(options::sp_before_class_colon()); + } + } + + if (first->Is(CT_CONSTR_COLON)) + { + min_sp = options::indent_ctor_init_leading() - 1; // default indent is 1 space + // Add or remove space after class constructor ':'. + log_rule("sp_after_constr_colon"); + return(options::sp_after_constr_colon()); + } + + if (second->Is(CT_CONSTR_COLON)) + { + // Add or remove space before class constructor ':'. + log_rule("sp_before_constr_colon"); + return(options::sp_before_constr_colon()); + } + + if (second->Is(CT_CASE_COLON)) + { + // Add or remove space before case ':'. + log_rule("sp_before_case_colon"); + return(options::sp_before_case_colon()); + } + + if (first->Is(CT_DOT)) + { + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if (second->Is(CT_DOT)) + { + log_rule("ADD"); + return(IARF_ADD); + } + + if ( first->Is(CT_NULLCOND) + || second->Is(CT_NULLCOND)) + { + // TODO: provide some test data to check this block + // LANG_CS null conditional operator + // Add or remove space around the '.' or '->' operators. + log_rule("sp_member"); + return(options::sp_member()); + } + + if ( first->Is(CT_ARITH) + || first->Is(CT_SHIFT) + || first->Is(CT_CARET) + || second->Is(CT_ARITH) + || second->Is(CT_SHIFT) + || second->Is(CT_CARET)) + { + // Add or remove space around arithmetic operators '+' and '-'. + // Overrides sp_arith. + if (options::sp_arith_additive() != IARF_IGNORE) + { + auto arith_char = ( first->Is(CT_ARITH) + || first->Is(CT_SHIFT) + || first->Is(CT_CARET)) + ? first->GetStr()[0] : second->GetStr()[0]; + + if ( arith_char == '+' + || arith_char == '-') + { + log_rule("sp_arith_additive"); + return(options::sp_arith_additive()); + } + } + // Add or remove space around non-assignment symbolic operators ('+', '/', '%', + // '<<', and so forth). + log_rule("sp_arith"); + return(options::sp_arith()); + } + + if ( first->Is(CT_BOOL) + || second->Is(CT_BOOL)) + { + // Add or remove space around boolean operators '&&' and '||'. + iarf_e arg = options::sp_bool(); + + if ( (options::pos_bool() != TP_IGNORE) + && first->GetOrigLine() != second->GetOrigLine()) + { + arg = arg | IARF_ADD; + } + log_rule("sp_bool"); + return(arg); + } + + if ( first->Is(CT_COMPARE) + || second->Is(CT_COMPARE)) + { + // Add or remove space around compare operator '<', '>', '==', etc. + log_rule("sp_compare"); + return(options::sp_compare()); + } + + if ( first->Is(CT_PAREN_OPEN) + && second->Is(CT_PTR_TYPE)) + { + // TODO: provide some test data to check this block + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if (first->Is(CT_PTR_TYPE)) // see the tests cpp:34505-34508 + { + if ( second->Is(CT_FPAREN_OPEN) + || second->Is(CT_TPAREN_OPEN)) + { + // Add or remove space after a pointer star '*', if followed by an open + // parenthesis, as in 'void* (*)()'. + log_rule("sp_ptr_star_paren"); // ptr_star 10 + return(options::sp_ptr_star_paren()); + } + else if (second->Is(CT_PTR_TYPE)) + { + // Add or remove space between pointer stars '*'. + // as in 'int ***a;'. + log_rule("sp_between_ptr_star"); // ptr_star 9 + return(options::sp_between_ptr_star()); + } + else if (second->Is(CT_FUNC_VAR)) + { + // Add or remove space between the pointer star '*' and the name of the + // variable in a function pointer definition. + log_rule("sp_ptr_star_func_var"); + return(options::sp_ptr_star_func_var()); + } + else if (second->Is(CT_FUNC_TYPE)) + { + // Add or remove space between the pointer star '*' and the name of the + // type in a function pointer type definition. + log_rule("sp_ptr_star_func_type"); + return(options::sp_ptr_star_func_type()); + } + else if ( first->GetParentType() == CT_FUNC_DEF + || first->GetParentType() == CT_FUNC_PROTO + || first->GetParentType() == CT_FUNC_VAR) + { + if (token_is_within_trailing_return(first)) + { + // Add or remove space after a pointer star '*', in the trailing return + // a function prototype or function definition. + log_rule("sp_after_ptr_star_trailing"); // ptr_star 3 + return(options::sp_after_ptr_star_trailing()); + } + else + { + // Add or remove space after a pointer star '*', if followed by a function + // prototype or function definition. + log_rule("sp_after_ptr_star_func"); // ptr_star 2 + return(options::sp_after_ptr_star_func()); + } + } + else if (CharTable::IsKw1(second->GetStr()[0])) + { + Chunk *prev = first->GetPrev(); + + if (prev->Is(CT_IN)) + { + // Add or remove space after the '*' (dereference) unary operator. This does + // not affect the spacing after a '*' that is part of a type. + log_rule("sp_deref"); + return(options::sp_deref()); + } + else if ( first->GetParentType() == CT_FUNC_VAR + || first->GetParentType() == CT_FUNC_TYPE) + { + // Add or remove space after pointer caret '^', if followed by a word. + log_rule("sp_after_ptr_block_caret"); + return(options::sp_after_ptr_block_caret()); + } + else if (second->Is(CT_QUALIFIER)) + { + // Add or remove space after pointer star '*', if followed by a qualifier. + log_rule("sp_after_ptr_star_qualifier"); // ptr_star 4 + return(options::sp_after_ptr_star_qualifier()); + } + // Add or remove space after pointer star '*', if followed by a word. + log_rule("sp_after_ptr_star"); // ptr_star 1 + return(options::sp_after_ptr_star()); + } + else if (second->Is(CT_PAREN_OPEN)) + { + // Add or remove space after pointer star '*', if followed by a word. + log_rule("sp_after_ptr_star"); // ptr_star 1 + return(options::sp_after_ptr_star()); + } + + // must be placed at the end of the block + // look back for '->' type is TRAILING_RET + if (token_is_within_trailing_return(first)) + { + log_rule("sp_after_ptr_star_trailing"); // ptr_star 3 + return(options::sp_after_ptr_star_trailing()); + } + } + + if ( second->Is(CT_PTR_TYPE) + && first->IsNot(CT_IN)) + { + // look back for '->' type is TRAILING_RET + if (token_is_within_trailing_return(second)) + { + log_rule("sp_before_ptr_star_trailing"); // ptr_star 7 + return(options::sp_before_ptr_star_trailing()); + } + + // Add or remove space before a pointer star '*', if followed by a function + // prototype or function definition. + if (options::sp_before_ptr_star_func() != IARF_IGNORE) + { + // Find the next non-'*' chunk + Chunk *next = second; + + do + { + next = next->GetNext(); + } while (next->Is(CT_PTR_TYPE)); + + if ( next->Is(CT_FUNC_DEF) + || next->Is(CT_FUNC_PROTO)) + { + log_rule("sp_before_ptr_star_func"); // ptr_star 6 + return(options::sp_before_ptr_star_func()); + } + } + + // Add or remove space before pointer star '*' that isn't followed by a + // variable name. If set to 'ignore', sp_before_ptr_star is used instead. + if (options::sp_before_unnamed_ptr_star() != IARF_IGNORE) + { + Chunk *next = second->GetNextNc(); + + while (next->Is(CT_PTR_TYPE)) + { + next = next->GetNextNc(); + } + + if ( next->IsNotNullChunk() + && next->IsNot(CT_WORD)) + { + log_rule("sp_before_unnamed_ptr_star"); // ptr_star 8 + return(options::sp_before_unnamed_ptr_star()); + } + } + + // Add or remove space before pointer star '*'. + if (options::sp_before_ptr_star() != IARF_IGNORE) + { + log_rule("sp_before_ptr_star"); // ptr_star 5 + return(options::sp_before_ptr_star()); + } + } + + if (first->Is(CT_OPERATOR)) + { + // Add or remove space between 'operator' and operator sign. + log_rule("sp_after_operator"); + return(options::sp_after_operator()); + } + + if ( second->Is(CT_FUNC_PROTO) + || second->Is(CT_FUNC_DEF)) + { + if ( first->IsNot(CT_PTR_TYPE) + && first->IsNot(CT_BYREF)) + { + // Add or remove space between return type and function name. A + // minimum of 1 is forced except for pointer/reference return types. + log_rule("sp_type_func | ADD"); + return(options::sp_type_func() | IARF_ADD); + } + // Add or remove space between return type and function name. A + // minimum of 1 is forced except for pointer/reference return types. + log_rule("sp_type_func"); + return(options::sp_type_func()); + } + + // "(int)a" vs. "(int) a" or "cast(int)a" vs. "cast(int) a" + if ( ( first->GetParentType() == CT_C_CAST + || first->GetParentType() == CT_D_CAST) + && first->Is(CT_PAREN_CLOSE)) + { + log_rule("sp_after_cast"); + return(options::sp_after_cast()); + } + + if (first->Is(CT_BRACE_CLOSE)) + { + if (second->Is(CT_ELSE)) + { + // Add or remove space between '}' and 'else' if on the same line. + log_rule("sp_brace_else"); + return(options::sp_brace_else()); + } + + if ( language_is_set(LANG_OC) + && second->Is(CT_CATCH) + && (options::sp_oc_brace_catch() != IARF_IGNORE)) + { + // TODO: provide some test data to check this block + // (OC) Add or remove space between '}' and '@catch' if on the same line. + // If set to ignore, sp_brace_catch is used. + log_rule("sp_oc_brace_catch"); + return(options::sp_oc_brace_catch()); + } + + if (second->Is(CT_CATCH)) + { + // TODO: provide some test data to check this block + // Add or remove space between '}' and 'catch' if on the same line. + log_rule("sp_brace_catch"); + return(options::sp_brace_catch()); + } + + if (second->Is(CT_FINALLY)) + { + // Add or remove space between '}' and 'finally' if on the same line. + log_rule("sp_brace_finally"); + return(options::sp_brace_finally()); + } + } + + if (first->Is(CT_BRACE_OPEN)) + { + if (first->GetParentType() == CT_ENUM) + { + // Add or remove space inside enum '{' and '}'. + log_rule("sp_inside_braces_enum"); + return(options::sp_inside_braces_enum()); + } + + if ( first->GetParentType() == CT_STRUCT + || first->GetParentType() == CT_UNION) + { + // Fix for issue #1240 adding space in struct initializers + Chunk *tmp = first->GetPrevNcNnl(); + + if (tmp->Is(CT_ASSIGN)) + { + // TODO: provide some test data to check this block + log_rule("IGNORE"); + return(IARF_IGNORE); + } + // Add or remove space inside struct/union '{' and '}'. + log_rule("sp_inside_braces_struct"); + return(options::sp_inside_braces_struct()); + } + else if ( first->GetParentType() == CT_OC_AT + && options::sp_inside_braces_oc_dict() != IARF_IGNORE) + { + // (OC) Add or remove space inside Objective-C boxed dictionary '{' and '}' + log_rule("sp_inside_braces_oc_dict"); + return(options::sp_inside_braces_oc_dict()); + } + + if (first->GetParentType() == CT_BRACED_INIT_LIST) + { + // Add or remove space between nested braces, i.e. '{{' vs. '{ {'. + // only to help the vim command }}}} + if ( options::sp_brace_brace() != IARF_IGNORE + && second->Is(CT_BRACE_OPEN) + && second->GetParentType() == CT_BRACED_INIT_LIST) + { + log_rule("sp_brace_brace"); + return(options::sp_brace_brace()); + } + + if (options::sp_after_type_brace_init_lst_open() != IARF_IGNORE) + { + // Add or remove space after open brace in an unnamed temporary + // direct-list-initialization + // if statement is a brace_init_lst + // works only if sp_brace_brace is set to ignore. + log_rule("sp_after_type_brace_init_lst_open"); + return(options::sp_after_type_brace_init_lst_open()); + } + + if (options::sp_inside_type_brace_init_lst() != IARF_IGNORE) + { + // Add or remove space inside an unnamed temporary direct-list-initialization + // if statement is a brace_init_lst + // works only if sp_brace_brace is set to ignore + // works only if sp_after_type_brace_init_lst_close is set to ignore. + log_rule("sp_inside_type_brace_init_lst"); + return(options::sp_inside_type_brace_init_lst()); + } + } + + if (!second->IsComment()) + { + // Add or remove space inside '{' and '}'. + log_rule("sp_inside_braces"); + return(options::sp_inside_braces()); + } + } + + if ( first->Is(CT_BRACE_CLOSE) + && first->TestFlags(PCF_IN_TYPEDEF) + && ( first->GetParentType() == CT_ENUM + || first->GetParentType() == CT_STRUCT + || first->GetParentType() == CT_UNION)) + { + // Add or remove space between '}' and the name of a typedef on the same line. + log_rule("sp_brace_typedef"); + return(options::sp_brace_typedef()); + } + + if ( language_is_set(LANG_D) + && second->Is(CT_PAREN_OPEN) + && second->GetParentType() == CT_TEMPLATE) + { + // (D) Add or remove space before the parenthesis in the D constructs + // 'template Foo(' and 'class Foo('. + log_rule("sp_before_template_paren"); + return(options::sp_before_template_paren()); + } + + // Issue #3080 + if ( first->Is(CT_PAREN_CLOSE) + && first->GetParentType() == CT_DECLTYPE + && ( second->Is(CT_WORD) + || second->Is(CT_BRACE_OPEN) + || second->Is(CT_FUNC_CALL))) + { + iarf_e arg = options::sp_after_decltype(); + // Add or remove space between 'decltype(...)' and word, brace or function call. + log_rule("sp_after_decltype"); + return(arg); + } + + // Issue #3080 + if ( !language_is_set(LANG_D) + && first->Is(CT_PAREN_CLOSE) + && second->Is(CT_WORD)) + { + // Add or remove space between type and word. + log_rule("sp_after_type"); + return(options::sp_after_type()); + } + + // see if the D template expression is used as a type + if ( language_is_set(LANG_D) + && first->Is(CT_PAREN_CLOSE) + && first->GetParentType() == CT_D_TEMPLATE) + { + if (second->GetParentType() == CT_USING_ALIAS) + { + log_rule("sp_after_type | ADD"); + return(options::sp_after_type() | IARF_ADD); + } + + if (second->Is(CT_WORD)) + { + Chunk *open_paren = first->GetOpeningParen(); + Chunk *type = open_paren->GetPrev()->GetPrev(); + + if (type->Is(CT_TYPE)) + { + log_rule("sp_after_type"); + return(options::sp_after_type()); + } + } + } + + if ( first->Is(CT_TYPE) // Issue #3457 + && second->Is(CT_COLON)) + { + log_rule("sp_type_colon"); + return(options::sp_type_colon()); + } + + if ( !second->Is(CT_PTR_TYPE) + && ( first->Is(CT_QUALIFIER) + || first->Is(CT_TYPE))) + { + // Add or remove space between type and word. In cases where total removal of + // whitespace would be a syntax error, a value of 'remove' is treated the same + // as 'force'. + // + // This also affects some other instances of space following a type that are + // not covered by other options; for example, between the return type and + // parenthesis of a function type template argument, between the type and + // parenthesis of an array parameter, or between 'decltype(...)' and the + // following word. + iarf_e arg = options::sp_after_type(); + log_rule("sp_after_type"); + return(arg); + } + + if ( first->Is(CT_PTR_TYPE) + && second->Is(CT_ELLIPSIS)) + { + log_rule("sp_ptr_type_ellipsis"); + return(options::sp_ptr_type_ellipsis()); + } + + // If nothing claimed the PTR_TYPE, then return ignore + if ( first->Is(CT_PTR_TYPE) + || second->Is(CT_PTR_TYPE)) + { + log_rule("IGNORE"); + return(IARF_IGNORE); + } + + if (first->Is(CT_NOT)) + { + if ( second->Is(CT_NOT) + && (options::sp_not_not() != IARF_IGNORE)) + { + log_rule("sp_not_not"); + return(options::sp_not_not()); + } + // Add or remove space after the '!' (not) unary operator. + log_rule("sp_not"); + return(options::sp_not()); + } + + if (first->Is(CT_INV)) + { + // Add or remove space after the '~' (invert) unary operator. + log_rule("sp_inv"); + return(options::sp_inv()); + } + + if (first->Is(CT_ADDR)) + { + // Add or remove space after the '&' (address-of) unary operator. This does not + // affect the spacing after a '&' that is part of a type. + log_rule("sp_addr"); + return(options::sp_addr()); + } + + if (first->Is(CT_DEREF)) + { + // Add or remove space after the '*' (dereference) unary operator. This does + // not affect the spacing after a '*' that is part of a type. + log_rule("sp_deref"); + return(options::sp_deref()); + } + + if ( first->Is(CT_POS) + || first->Is(CT_NEG)) + { + // Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. + log_rule("sp_sign"); + return(options::sp_sign()); + } + + if ( first->Is(CT_INCDEC_BEFORE) + || second->Is(CT_INCDEC_AFTER)) + { + // Add or remove space between '++' and '--' the word to which it is being + // applied, as in '(--x)' or 'y++;'. + log_rule("sp_incdec"); + return(options::sp_incdec()); + } + + if (second->Is(CT_CS_SQ_COLON)) + { + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + if (first->Is(CT_CS_SQ_COLON)) + { + log_rule("FORCE"); + return(IARF_FORCE); + } + + if ( language_is_set(LANG_OC) + && first->Is(CT_OC_SCOPE)) + { + // (OC) Add or remove space after the scope '+' or '-', as in '-(void) foo;' + // or '+(int) bar;'. + log_rule("sp_after_oc_scope"); + return(options::sp_after_oc_scope()); + } + + if ( language_is_set(LANG_OC) + && first->Is(CT_OC_DICT_COLON)) + { + // (OC) Add or remove space after the colon in immutable dictionary expression + // 'NSDictionary *test = @{@"foo" :@"bar"};'. + log_rule("sp_after_oc_dict_colon"); + return(options::sp_after_oc_dict_colon()); + } + + if ( language_is_set(LANG_OC) + && second->Is(CT_OC_DICT_COLON)) + { + // (OC) Add or remove space before the colon in immutable dictionary expression + // 'NSDictionary *test = @{@"foo" :@"bar"};'. + log_rule("sp_before_oc_dict_colon"); + return(options::sp_before_oc_dict_colon()); + } + + if ( language_is_set(LANG_OC) + && first->Is(CT_OC_COLON)) + { + if (first->TestFlags(PCF_IN_OC_MSG)) + { + // (OC) Add or remove space after the colon in message specs, + // i.e. '[object setValue:1];' vs. '[object setValue: 1];'. + log_rule("sp_after_send_oc_colon"); + return(options::sp_after_send_oc_colon()); + } + // (OC) Add or remove space after the colon in message specs, + // i.e. '-(int) f:(int) x;' vs. '-(int) f: (int) x;'. + log_rule("sp_after_oc_colon"); + return(options::sp_after_oc_colon()); + } + + if ( language_is_set(LANG_OC) + && second->Is(CT_OC_COLON)) + { + if ( first->TestFlags(PCF_IN_OC_MSG) + && ( first->Is(CT_OC_MSG_FUNC) + || first->Is(CT_OC_MSG_NAME))) + { + // (OC) Add or remove space before the colon in message specs, + // i.e. '[object setValue:1];' vs. '[object setValue :1];'. + log_rule("sp_before_send_oc_colon"); + return(options::sp_before_send_oc_colon()); + } + // (OC) Add or remove space before the colon in message specs, + // i.e. '-(int) f: (int) x;' vs. '-(int) f : (int) x;'. + log_rule("sp_before_oc_colon"); + return(options::sp_before_oc_colon()); + } + + if ( second->Is(CT_COMMENT) + && second->GetParentType() == CT_COMMENT_EMBED) + { + // Add or remove space before an embedded comment. + // Number of spaces before an embedded comment. + log_rule("sp_before_emb_cmt"); + min_sp = options::sp_num_before_emb_cmt(); + return(options::sp_before_emb_cmt()); + } + + if (first->Is(CT_COMMENT)) + { + // Add or remove space after an embedded comment. + // Number of spaces after an embedded comment. + log_rule("sp_after_emb_cmt"); + min_sp = options::sp_num_after_emb_cmt(); + return(options::sp_after_emb_cmt()); + } + + if ( first->Is(CT_NEW) + && second->Is(CT_PAREN_OPEN)) + { + // c# new Constraint, c++ new operator + // Add or remove space between 'new' and '(' in 'new()'. + log_rule("sp_between_new_paren"); + return(options::sp_between_new_paren()); + } + + if ( first->Is(CT_NEW) + || first->Is(CT_DELETE) + || ( first->Is(CT_TSQUARE) + && first->GetParentType() == CT_DELETE)) + { + // Add or remove space after 'new', 'delete' and 'delete[]'. + log_rule("sp_after_new"); + return(options::sp_after_new()); + } + + if ( language_is_set(LANG_JAVA) + && first->Is(CT_ANNOTATION) + && second->IsParenOpen()) + { + // (Java) Add or remove space between an annotation and the open parenthesis. + log_rule("sp_annotation_paren"); + return(options::sp_annotation_paren()); + } + + if ( language_is_set(LANG_OC) + && first->Is(CT_OC_PROPERTY)) + { + // (OC) Add or remove space after '@property'. + log_rule("sp_after_oc_property"); + return(options::sp_after_oc_property()); + } + + if ( language_is_set(LANG_D) + && first->Is(CT_EXTERN) + && second->Is(CT_PAREN_OPEN)) + { + // (D) Add or remove space between 'extern' and '(' as in 'extern (C)'. + log_rule("sp_extern_paren"); + return(options::sp_extern_paren()); + } + + if ( second->Is(CT_TYPE) + && ( ( first->Is(CT_STRING) + && first->GetParentType() == CT_EXTERN) + || ( first->Is(CT_FPAREN_CLOSE) + && first->GetParentType() == CT_ATTRIBUTE))) + { + log_rule("FORCE"); + return(IARF_FORCE); /* TODO: make this configurable? */ + } + + if (first->Is(CT_NOEXCEPT)) + { + // Add or remove space after 'noexcept'. + log_rule("sp_after_noexcept"); + return(options::sp_after_noexcept()); + } + + // Issue #2138 + if (first->Is(CT_FPAREN_CLOSE)) + { + if (second->Is(CT_QUALIFIER)) + { + // Add or remove space between ')' and a qualifier such as 'const'. + log_rule("sp_paren_qualifier"); + return(options::sp_paren_qualifier()); + } + else if (second->Is(CT_NOEXCEPT)) + { + // Add or remove space between ')' and 'noexcept'. + log_rule("sp_paren_noexcept"); + return(options::sp_paren_noexcept()); + } + } + + // Issue #2098 + if ( first->Is(CT_PP_PRAGMA) + && second->Is(CT_PREPROC_BODY)) + { + log_rule("REMOVE"); + return(IARF_REMOVE); + } + + // Issue #1733 + if ( first->Is(CT_OPERATOR_VAL) + && second->Is(CT_TYPE)) + { + log_rule("IGNORE"); + return(IARF_IGNORE); + } + + // Issue #995 + if ( first->Is(CT_DO) + && second->Is(CT_BRACE_OPEN)) + { + // Add or remove space between 'do' and '{'. + log_rule("sp_do_brace_open"); + return(options::sp_do_brace_open()); + } + + // Issue #995 + if ( first->Is(CT_BRACE_CLOSE) + && second->Is(CT_WHILE_OF_DO)) + { + // Add or remove space between '}' and 'while. + log_rule("sp_brace_close_while"); + return(options::sp_brace_close_while()); + } + + // TODO: have a look to Issue #2186, why NEWLINE? + // Issue #2524 + if ( first->Is(CT_NEWLINE) + && second->Is(CT_BRACE_OPEN)) + { + log_rule("IGNORE"); + return(IARF_IGNORE); + } + + // ============================================================= + // category 1 + // this table lists out all combos where a space should NOT be present + // CT_UNKNOWN is a wildcard. + for (auto it : no_space_table) + { + if ( ( it.first == CT_UNKNOWN + || it.first == first->GetType()) + && ( it.second == CT_UNKNOWN + || it.second == second->GetType())) + { + log_rule("REMOVE from no_space_table"); + return(IARF_REMOVE); + } + } + + // ============================================================= + // category 2 + // this table lists out all combos where a space MUST be present + for (auto it : add_space_table) + { + if ( it.first == first->GetType() + && it.second == second->GetType()) + { + // TODO: if necessary create a new option + log_rule("ADD from add_space_table"); + return(IARF_ADD); + } + } + + // Issue #2386 + if ( first->Is(CT_FORM_FEED) + || second->Is(CT_FORM_FEED)) + { + log_rule("IGNORE"); + return(IARF_IGNORE); + } + + // TODO: if necessary create a new option + if ( first->Is(CT_MACRO_FUNC_CALL) + && second->Is(CT_FPAREN_OPEN)) + { + log_rule("IGNORE"); + return(IARF_IGNORE); + } + + if ( first->Is(CT_CASE_ELLIPSIS) + && second->Is(CT_NUMBER)) + { + // Add or remove space after the variadic '...' when preceded by a + // non-punctuator. + // The value REMOVE will be overridden with FORCE + if (options::sp_after_ellipsis() == IARF_REMOVE) + { + log_rule("sp_after_ellipsis/FORCE"); + return(IARF_FORCE); + } + else + { + log_rule("sp_after_ellipsis"); + return(options::sp_after_ellipsis()); + } + } + + if ( first->Is(CT_NUMBER) + && second->Is(CT_CASE_ELLIPSIS)) + { + // Add or remove space before the variadic '...' when preceded by a + // non-punctuator. + // The value REMOVE will be overridden with FORCE + if (options::sp_before_ellipsis() == IARF_REMOVE) + { + log_rule("sp_before_ellipsis/FORCE"); + return(IARF_FORCE); + } + else + { + log_rule("sp_before_ellipsis"); + return(options::sp_before_ellipsis()); + } + } + // ============================================================= + // category 3 + // these lines are only useful for debugging uncrustify itself + LOG_FMT(LSPACE, "\n\n%s(%d): WARNING: unrecognize do_space:\n", + __func__, __LINE__); + LOG_FMT(LSPACE, " first orig line is %zu, orig col is %zu, Text() '%s', GetType() is %s\n", + first->GetOrigLine(), first->GetOrigCol(), first->Text(), get_token_name(first->GetType())); + LOG_FMT(LSPACE, " second orig line is %zu, orig col is %zu, Text() '%s', GetType() is %s\n", + second->GetOrigLine(), second->GetOrigCol(), second->Text(), get_token_name(second->GetType())); + LOG_FMT(LSPACE, " Please make a call at https://github.com/uncrustify/uncrustify/issues/new\n"); + LOG_FMT(LSPACE, " or merge the line:\n"); + LOG_FMT(LSPACE, " { CT_%s, CT_%s},\n", + get_token_name(first->GetType()), get_token_name(second->GetType())); + LOG_FMT(LSPACE, " in the file <Path_to_uncrustify>/src/add_space_table.h\n"); + + log_rule("ADD as default value"); + return(IARF_ADD); +} // do_space + + +static iarf_e ensure_force_space(Chunk *first, Chunk *second, iarf_e av) +{ + if (first->TestFlags(PCF_FORCE_SPACE)) + { + LOG_FMT(LSPACE, "%s(%d): <force between '%s' and '%s'>\n", + __func__, __LINE__, first->Text(), second->Text()); + return(av | IARF_ADD); + } + return(av); +} + + +static iarf_e do_space_ensured(Chunk *first, Chunk *second, int &min_sp) +{ + iarf_e aa = ensure_force_space(first, second, do_space(first, second, min_sp)); + + return(aa); +} + + +void space_text() +{ + LOG_FUNC_ENTRY(); + + Chunk *pc = Chunk::GetHead(); + Chunk *next; + size_t prev_column; + size_t column = pc->GetColumn(); + + while (pc->IsNotNullChunk()) + { + if (pc->Is(CT_NEWLINE)) + { + LOG_FMT(LSPACE, "%s(%d): orig line is %zu, orig col is %zu, <Newline>, nl is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->GetNlCount()); + } + else + { + char copy[1000]; + LOG_FMT(LSPACE, "%s(%d): orig line is %zu, orig col is %zu, '%s' type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->ElidedText(copy), get_token_name(pc->GetType())); + } + + if ( (options::use_options_overriding_for_qt_macros()) + && ( (strcmp(pc->Text(), "SIGNAL") == 0) + || (strcmp(pc->Text(), "SLOT") == 0))) + { + LOG_FMT(LSPACE, "%s(%d): orig col is %zu, type is %s SIGNAL/SLOT found\n", + __func__, __LINE__, pc->GetOrigLine(), get_token_name(pc->GetType())); + pc->SetFlagBits(PCF_IN_QT_MACRO); // flag the chunk for a second processing + + // save the values + save_set_options_for_QT(pc->GetLevel()); + } + + // Bug # 637 + // If true, vbrace tokens are dropped to the previous token and skipped. + if (options::sp_skip_vbrace_tokens()) + { + next = pc->GetNext(); + + while ( next->IsEmptyText() + && !next->IsNewline() + && next->IsVBrace()) + { + LOG_FMT(LSPACE, "%s(%d): orig line is %zu, orig col is %zu, Skip %s (%zu+%zu)\n", + __func__, __LINE__, next->GetOrigLine(), next->GetOrigCol(), get_token_name(next->GetType()), + pc->GetColumn(), pc->GetStr().size()); + next->SetColumn(pc->GetColumn() + pc->GetStr().size()); + next = next->GetNext(); + } + } + else + { + next = pc->GetNext(); + } + + if (next->IsNullChunk()) + { + break; + } + + // Issue # 481 + // Whether to balance spaces inside nested parentheses. + if ( QT_SIGNAL_SLOT_found + && options::sp_balance_nested_parens()) + { + Chunk *nn = next->GetNext(); // Issue #2734 + + if ( nn->IsNotNullChunk() + && nn->Is(CT_SPACE)) + { + Chunk::Delete(nn); // remove the space + } + } + + /* + * If the current chunk contains a newline, do not change the column + * of the next item + */ + if ( pc->IsNewline() + || pc->Is(CT_COMMENT_MULTI)) + { + column = next->GetColumn(); + } + else + { + // Set to the minimum allowed column + if (pc->GetNlCount() == 0) + { + column += pc->Len(); + } + else + { + column = pc->GetOrigColEnd(); + } + prev_column = column; + + /* + * Apply a general safety check + * If the two chunks combined will tokenize differently, then we + * must force a space. + * Two chunks -- "()" and "[]" will always tokenize differently. + * They are always safe to not have a space after them. + */ + pc->ResetFlagBits(PCF_FORCE_SPACE); + + if ( (pc->Len() > 0) + && !pc->IsString("[]") + && !pc->IsString("{{") + && !pc->IsString("}}") + && !pc->IsString("()") + && !pc->GetStr().startswith("@\"")) + { + // Find the next non-empty chunk on this line + Chunk *tmp = next; + + while ( tmp->IsNotNullChunk() + && (tmp->Len() == 0) + && !tmp->IsNewline()) + { + tmp = tmp->GetNext(); + } + + if ( tmp->IsNotNullChunk() + && tmp->Len() > 0) + { + bool kw1 = CharTable::IsKw2(pc->GetStr()[pc->Len() - 1]); + bool kw2 = CharTable::IsKw1(next->GetStr()[0]); + + if ( kw1 + && kw2) + { + // back-to-back words need a space + LOG_FMT(LSPACE, "%s(%d): back-to-back words need a space: pc->Text() '%s', next->Text() '%s'\n", + __func__, __LINE__, pc->Text(), next->Text()); + pc->SetFlagBits(PCF_FORCE_SPACE); + } + // TODO: what is the meaning of 4 + else if ( !kw1 + && !kw2 + && (pc->Len() < 4) + && (next->Len() < 4)) + { + // We aren't dealing with keywords. concat and try punctuators + char buf[9]; + memcpy(buf, pc->Text(), pc->Len()); + memcpy(buf + pc->Len(), next->Text(), next->Len()); + buf[pc->Len() + next->Len()] = 0; + + const chunk_tag_t *ct; + ct = find_punctuator(buf, cpd.lang_flags); + + if ( ct != nullptr + && (strlen(ct->tag) != pc->Len())) + { + // punctuator parsed to a different size.. + + /* + * C++11 allows '>>' to mean '> >' in templates: + * some_func<vector<string>>(); + */ + // (C++11) Permit removal of the space between '>>' in 'foo<bar<int> >'. Note + // that sp_angle_shift cannot remove the space without this option. + if ( ( ( language_is_set(LANG_CPP) + && options::sp_permit_cpp11_shift()) + || (language_is_set(LANG_JAVA | LANG_CS | LANG_VALA | LANG_OC))) + && pc->Is(CT_ANGLE_CLOSE) + && next->Is(CT_ANGLE_CLOSE)) + { + // allow '>' and '>' to become '>>' + } + else if (strcmp(ct->tag, "[]") == 0) + { + // this is OK + } + else + { + LOG_FMT(LSPACE, "%s(%d): : pc->Text() is %s, next->Text() is %s\n", + __func__, __LINE__, pc->Text(), next->Text()); + pc->SetFlagBits(PCF_FORCE_SPACE); + } + } + } + } + } + int min_sp; + LOG_FMT(LSPACE, "%s(%d): orig line is %zu, orig col is %zu, pc-Text() '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + iarf_e av = do_space_ensured(pc, next, min_sp); + min_sp = max(1, min_sp); + + switch (av) + { + case IARF_FORCE: + column += min_sp; // add exactly the specified number of spaces + break; + + case IARF_ADD: + { + int delta = min_sp; + + if ( next->GetOrigCol() >= pc->GetOrigColEnd() + && pc->GetOrigColEnd() != 0) + { + // Keep the same relative spacing, minimum 1 + delta = next->GetOrigCol() - pc->GetOrigColEnd(); + + if (delta < min_sp) + { + delta = min_sp; + } + } + column += delta; + break; + } + + case IARF_REMOVE: + // the symbols will be back-to-back "a+3" + break; + + case IARF_IGNORE: + + // Keep the same relative spacing, if possible + if ( next->GetOrigCol() >= pc->GetOrigColEnd() + && pc->GetOrigColEnd() != 0) + { + column += next->GetOrigCol() - pc->GetOrigColEnd(); + } + else + { + // preserve the position if virtual brace + // Issue #1854 + if (pc->Is(CT_VBRACE_OPEN)) + { + column = next->GetOrigCol(); + } + } + break; + + default: + // If we got here, something is wrong... + break; + } // switch + + if ( next->IsComment() + && next->GetNext()->IsNewline() + && column < next->GetOrigCol()) + { + /* + * do some comment adjustments if sp_before_tr_cmt and sp_endif_cmt + * did not apply. + */ + // Add or remove space between #else or #endif and a trailing comment. + if ( ( options::sp_before_tr_cmt() == IARF_IGNORE + || next->GetParentType() != CT_COMMENT_END) + && ( options::sp_endif_cmt() == IARF_IGNORE + || ( pc->IsNot(CT_PP_ELSE) + && pc->IsNot(CT_PP_ENDIF)))) + { + if (options::indent_relative_single_line_comments()) + { + // Try to keep relative spacing between tokens + LOG_FMT(LSPACE, "%s(%d): <relative adj>", __func__, __LINE__); + LOG_FMT(LSPACE, "%s(%d): pc is '%s', orig col is %zu, next orig col is %zu, pc orig col end is %zu\n", + __func__, __LINE__, pc->Text(), + pc->GetOrigCol(), next->GetOrigCol(), pc->GetOrigColEnd()); + column = pc->GetColumn() + (next->GetOrigCol() - pc->GetOrigColEnd()); + } + else + { + /* + * If there was a space, we need to force one, otherwise + * try to keep the comment in the same column. + */ + size_t col_min = pc->GetColumn() + pc->Len() + ((next->GetOrigPrevSp() > 0) ? 1 : 0); + column = next->GetOrigCol(); + + if (column < col_min) + { + column = col_min; + } + LOG_FMT(LSPACE, "%s(%d): <relative set>", __func__, __LINE__); + } + } + } + next->SetColumn(column); + + LOG_FMT(LSPACE, "%s(%d): orig line is %zu, orig col is %zu, pc-Text() '%s', type is %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text(), get_token_name(pc->GetType())); + LOG_FMT(LSPACE, "%s(%d): ", + __func__, __LINE__); + LOG_FMT(LSPACE, " rule = %s @ %zu => %zu\n", + (av == IARF_IGNORE) ? "IGNORE" : + (av == IARF_ADD) ? "ADD" : + (av == IARF_REMOVE) ? "REMOVE" : "FORCE", + column - prev_column, next->GetColumn()); + + if (restoreValues) // guy 2015-09-22 + { + restore_options_for_QT(); + } + } + pc = next; + + if (QT_SIGNAL_SLOT_found) + { + // flag the chunk for a second processing + pc->SetFlagBits(PCF_IN_QT_MACRO); + } + } +} // space_text + + +void space_text_balance_nested_parens() +{ + LOG_FUNC_ENTRY(); + + Chunk *first = Chunk::GetHead(); + + while (first->IsNotNullChunk()) + { + Chunk *next = first->GetNext(); + + if (next->IsNullChunk()) + { + break; + } + + // if there are two successive opening parenthesis + if ( first->IsString("(") + && next->IsString("(")) + { + // insert a space between them + space_add_after(first, 1); + + // test after the closing parens Issue #1703 + Chunk *closing = first->GetNextType((E_Token)(first->GetType() + 1), first->GetLevel()); + + if (closing->GetOrigCol() == closing->GetPrev()->GetOrigColEnd()) + { + space_add_after(closing->GetPrev(), 1); + } + } + else if ( first->IsString(")") + && next->IsString(")")) + { + // insert a space between the two closing parens + space_add_after(first, 1); + + // test after the opening parens Issue #1703 + Chunk *opening = next->GetPrevType((E_Token)(next->GetType() - 1), next->GetLevel()); + + if (opening->GetOrigColEnd() == opening->GetNext()->GetOrigCol()) + { + space_add_after(opening, 1); + } + } + first = next; + } +} // space_text_balance_nested_parens + + +size_t space_needed(Chunk *first, Chunk *second) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LSPACE, "%s(%d)\n", __func__, __LINE__); + + int min_sp; + + switch (do_space_ensured(first, second, min_sp)) + { + case IARF_ADD: + case IARF_FORCE: + return(max(1, min_sp)); + + case IARF_REMOVE: + return(0); + + case IARF_IGNORE: + default: + return(second->GetOrigCol() > (first->GetOrigCol() + first->Len())); + } +} + + +size_t space_col_align(Chunk *first, Chunk *second) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LSPACE, "%s(%d): first orig line is %zu, orig col is %zu, [%s/%s], Text() '%s' <==>\n", + __func__, __LINE__, first->GetOrigLine(), first->GetOrigCol(), + get_token_name(first->GetType()), get_token_name(first->GetParentType()), + first->Text()); + LOG_FMT(LSPACE, "%s(%d): second orig line is %zu, orig col is %zu [%s/%s], Text() '%s',", + __func__, __LINE__, second->GetOrigLine(), second->GetOrigCol(), + get_token_name(second->GetType()), get_token_name(second->GetParentType()), + second->Text()); + log_func_stack_inline(LSPACE); + + int min_sp; + iarf_e av = do_space_ensured(first, second, min_sp); + + LOG_FMT(LSPACE, "%s(%d): av is %s\n", __func__, __LINE__, to_string(av)); + size_t coldiff; + + if (first->GetNlCount()) + { + LOG_FMT(LSPACE, "%s(%d): new line count is %zu, orig col end is %zu\n", __func__, __LINE__, first->GetNlCount(), first->GetOrigColEnd()); + coldiff = first->GetOrigColEnd() - 1; + } + else + { + LOG_FMT(LSPACE, "%s(%d): Len is %zu\n", __func__, __LINE__, first->Len()); + coldiff = first->Len(); + } + LOG_FMT(LSPACE, "%s(%d): => coldiff is %zu\n", __func__, __LINE__, coldiff); + + LOG_FMT(LSPACE, "%s(%d): => av is %s\n", __func__, __LINE__, + (av == IARF_IGNORE) ? "IGNORE" : + (av == IARF_ADD) ? "ADD" : + (av == IARF_REMOVE) ? "REMOVE" : "FORCE"); + + switch (av) + { + case IARF_ADD: + case IARF_FORCE: + coldiff++; + break; + + case IARF_REMOVE: + break; + + case IARF_IGNORE: // Issue #2064 + LOG_FMT(LSPACE, "%s(%d): => first orig line is %zu\n", __func__, __LINE__, first->GetOrigLine()); + LOG_FMT(LSPACE, "%s(%d): => second orig line is %zu\n", __func__, __LINE__, second->GetOrigLine()); + LOG_FMT(LSPACE, "%s(%d): => first Text() is '%s'\n", __func__, __LINE__, first->Text()); + LOG_FMT(LSPACE, "%s(%d): => second Text() is '%s'\n", __func__, __LINE__, second->Text()); + LOG_FMT(LSPACE, "%s(%d): => first orig col is %zu\n", __func__, __LINE__, first->GetOrigCol()); + LOG_FMT(LSPACE, "%s(%d): => second orig col is %zu\n", __func__, __LINE__, second->GetOrigCol()); + LOG_FMT(LSPACE, "%s(%d): => first Len() is %zu\n", __func__, __LINE__, first->Len()); + + if ( first->GetOrigLine() == second->GetOrigLine() + && second->GetOrigCol() > (first->GetOrigCol() + first->Len())) + { + coldiff++; + } + break; + + default: + // If we got here, something is wrong... + break; + } + LOG_FMT(LSPACE, "%s(%d): => coldiff is %zu\n", __func__, __LINE__, coldiff); + return(coldiff); +} // space_col_align + + +void space_add_after(Chunk *pc, size_t count) +{ + LOG_FUNC_ENTRY(); + + Chunk *next = pc->GetNext(); + + // don't add at the end of the file or before a newline + if ( next->IsNullChunk() + || next->IsNewline()) + { + return; + } + + // Limit to 16 spaces + if (count > 16) + { + count = 16; + } + + // Two CT_SPACE in a row -- use the max of the two + if (next->Is(CT_SPACE)) + { + if (next->Len() < count) + { + while (next->Len() < count) + { + next->Str().append(' '); + } + } + return; + } + Chunk sp; + + sp.SetType(CT_SPACE); + sp.SetFlags(pc->GetFlags() & PCF_COPY_FLAGS); + sp.Str() = " "; // 16 spaces + sp.Str().resize(count); + sp.SetLevel(pc->GetLevel()); + sp.SetBraceLevel(pc->GetBraceLevel()); + sp.SetPpLevel(pc->GetPpLevel()); + sp.SetColumn(pc->GetColumn() + pc->Len()); + sp.SetOrigLine(pc->GetOrigLine()); + sp.SetOrigCol(pc->GetOrigCol()); + + sp.CopyAndAddAfter(pc); +} // space_add_after diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/space.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/space.h new file mode 100644 index 00000000..275772f2 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/space.h @@ -0,0 +1,45 @@ +/** + * @file space.h + * prototypes for space.cpp + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef SPACE_H_INCLUDED +#define SPACE_H_INCLUDED + +#include "uncrustify_types.h" + + +/** + * Marches through the whole file and checks to see how many spaces should be + * between two chunks + */ +void space_text(); + + +//! Marches through the whole file and adds spaces around nested parenthesis +void space_text_balance_nested_parens(); + + +//! Determines if a space is required between two chunks +size_t space_needed(Chunk *first, Chunk *second); + + +/** + * Calculates the column difference between two chunks. + * The rules are bent a bit here, as IARF_IGNORE and IARF_ADD become IARF_FORCE. + * So the column difference is either first->len or first->len + 1. + * + * @param first The first chunk + * @param second The second chunk + * + * @return the column difference between the two chunks + */ +size_t space_col_align(Chunk *first, Chunk *second); + + +void space_add_after(Chunk *pc, size_t count); + + +#endif /* SPACE_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/symbols_table.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/symbols_table.h new file mode 100644 index 00000000..bcf7c8b2 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/symbols_table.h @@ -0,0 +1,148 @@ +/** + * @file symbols + * Manages the table of punctuators. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +/** + * + * Content of the generated "punctuator_table.h" file is based off this. + * + * NOTE: the tables below do not need to be sorted. + */ + +#include "uncrustify_types.h" + +// 6-char symbols +static const chunk_tag_t symbols6[] = +{ + { R"_(??(??))_", CT_TSQUARE, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // trigraph [] + { R"_(??!??!)_", CT_BOOL, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // trigraph || + { R"_(??=??=)_", CT_PP, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // trigraph ## +}; + +/* 5-char symbols */ +static const chunk_tag_t symbols5[] = +{ + { R"_(??!=)_", CT_ASSIGN, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // trigraph |= + { R"_(??'=)_", CT_ASSIGN, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // trigraph ^= + { R"_(??=@)_", CT_POUND, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // trigraph #@ MS extension +}; + +/* 4-char symbols */ +static const chunk_tag_t symbols4[] = +{ + { "!<>=", CT_COMPARE, LANG_D }, + { ">>>=", CT_ASSIGN, LANG_D | LANG_JAVA | LANG_PAWN }, + { R"_(<::>)_", CT_TSQUARE, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // digraph [] + { R"_(%:%:)_", CT_PP, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // digraph ## +}; + +// 3-char symbols +static const chunk_tag_t symbols3[] = +{ + { "!<=", CT_COMPARE, LANG_D }, + { "!<>", CT_COMPARE, LANG_D }, + { "!==", CT_COMPARE, LANG_D | LANG_ECMA }, + { "!>=", CT_COMPARE, LANG_D }, + { "<=>", CT_COMPARE, LANG_CPP }, + { "->*", CT_MEMBER, LANG_C | LANG_CPP | LANG_OC | LANG_D }, + { "...", CT_ELLIPSIS, LANG_C | LANG_CPP | LANG_OC | LANG_D | LANG_PAWN | LANG_JAVA }, + { "<<=", CT_ASSIGN, LANG_ALL }, + { "<>=", CT_COMPARE, LANG_D }, + { "===", CT_COMPARE, LANG_D | LANG_ECMA }, + { ">>=", CT_ASSIGN, LANG_ALL }, + { ">>>", CT_ARITH, LANG_D | LANG_JAVA | LANG_PAWN | LANG_ECMA }, + { "%:@", CT_POUND, LANG_C | LANG_CPP | LANG_OC }, // digraph #@ MS extension + { R"_(??=)_", CT_POUND, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // trigraph # + { R"_(??=)_", CT_COMPARE, LANG_CS }, // cs: Null-Coalescing Assignment Operator + { R"_(??()_", CT_SQUARE_OPEN, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // trigraph [ + { R"_(??))_", CT_SQUARE_CLOSE, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // trigraph ] + { R"_(??')_", CT_CARET, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // trigraph ^ + { R"_(??<)_", CT_BRACE_OPEN, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // trigraph { + { R"_(??>)_", CT_BRACE_CLOSE, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // trigraph } + { R"_(??-)_", CT_INV, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // trigraph ~ + { R"_(??!)_", CT_ARITH, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // trigraph | +}; +// { R"_(??/)_", CT_UNKNOWN, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // trigraph '\' + +// 2-char symbols +static const chunk_tag_t symbols2[] = +{ + { "!<", CT_COMPARE, LANG_D }, // 0 + { "!=", CT_COMPARE, LANG_ALL }, // 1 + { "!>", CT_COMPARE, LANG_D }, // 2 + { "!~", CT_COMPARE, LANG_D }, // 3 + { "##", CT_PP, LANG_C | LANG_CPP | LANG_OC }, // 4 + { "#@", CT_POUND, LANG_C | LANG_CPP | LANG_OC }, // MS extension + { "%=", CT_ASSIGN, LANG_ALL }, // 6 + { "&&", CT_BOOL, LANG_ALL }, // 7 + { "&=", CT_ASSIGN, LANG_ALL }, // 8 + { "*=", CT_ASSIGN, LANG_ALL }, // 9 + { "++", CT_INCDEC_AFTER, LANG_ALL }, // 10 + { "+=", CT_ASSIGN, LANG_ALL }, // 11 + { "--", CT_INCDEC_AFTER, LANG_ALL }, // 12 + { "-=", CT_ASSIGN, LANG_ALL }, // 13 + { "->", CT_MEMBER, LANG_ALLC }, // 14 + { ".*", CT_MEMBER, LANG_C | LANG_CPP | LANG_OC | LANG_D }, // 15 + { "..", CT_RANGE, LANG_D }, // 16 + { "?.", CT_NULLCOND, LANG_CS }, // null conditional operator + { "/=", CT_ASSIGN, LANG_ALL }, // 18 + { "::", CT_DC_MEMBER, LANG_ALLC }, // 19 + { "<<", CT_SHIFT, LANG_ALL }, // 20 + { "<=", CT_COMPARE, LANG_ALL }, // 21 + { "<>", CT_COMPARE, LANG_D }, // 22 + { "==", CT_COMPARE, LANG_ALL }, // 23 + { ">=", CT_COMPARE, LANG_ALL }, // 24 + { ">>", CT_SHIFT, LANG_ALL }, // 25 + { "[]", CT_TSQUARE, LANG_ALL }, // 26 + { "^=", CT_ASSIGN, LANG_ALL }, // 27 + { "|=", CT_ASSIGN, LANG_ALL }, // 28 + { "||", CT_BOOL, LANG_ALL }, // 29 + { "~=", CT_COMPARE, LANG_D }, // 30 + { "~~", CT_COMPARE, LANG_D }, // 31 + { "=>", CT_LAMBDA, LANG_VALA | LANG_CS | LANG_D }, // 32 + { "??", CT_COMPARE, LANG_CS | LANG_VALA }, // 33 + { R"_(<%)_", CT_BRACE_OPEN, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // digraph { + { R"_(%>)_", CT_BRACE_CLOSE, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // digraph } + { R"_(<:)_", CT_SQUARE_OPEN, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // digraph [ + { R"_(:>)_", CT_SQUARE_CLOSE, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // digraph ] + { R"_(%:)_", CT_POUND, LANG_C | LANG_CPP | LANG_OC | FLAG_DIG }, // digraph # +}; + +// *INDENT-OFF* +// 1-char symbols +static const chunk_tag_t symbols1[] = +{ + { R"_()_", CT_FORM_FEED, LANG_ALL }, + { "!", CT_NOT, LANG_ALL }, + { "#", CT_POUND, LANG_ALL & ~(LANG_JAVA | LANG_ECMA) }, + { "$", CT_COMPARE, LANG_D }, + { "%", CT_ARITH, LANG_ALL }, + { "&", CT_AMP, LANG_ALL }, + { "(", CT_PAREN_OPEN, LANG_ALL }, + { ")", CT_PAREN_CLOSE, LANG_ALL }, + { "*", CT_STAR, LANG_ALL }, + { "+", CT_PLUS, LANG_ALL }, + { ",", CT_COMMA, LANG_ALL }, + { "-", CT_MINUS, LANG_ALL }, + { ".", CT_DOT, LANG_ALL }, + { "/", CT_ARITH, LANG_ALL }, + { ":", CT_COLON, LANG_ALL }, + { ";", CT_SEMICOLON, LANG_ALL }, + { "<", CT_ANGLE_OPEN, LANG_ALL }, + { "=", CT_ASSIGN, LANG_ALL }, + { ">", CT_ANGLE_CLOSE, LANG_ALL }, + { "@", CT_OC_AT, LANG_OC }, + { "?", CT_QUESTION, LANG_ALL }, + { "[", CT_SQUARE_OPEN, LANG_ALL }, + { "]", CT_SQUARE_CLOSE, LANG_ALL }, + { "^", CT_CARET, LANG_ALL }, + { "{", CT_BRACE_OPEN, LANG_ALL }, + { "|", CT_ARITH, LANG_ALL }, + { "}", CT_BRACE_CLOSE, LANG_ALL }, + { "~", CT_INV, LANG_ALL }, +}; +// *INDENT-ON* diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/token_enum.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/token_enum.h new file mode 100644 index 00000000..e7caa5ba --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/token_enum.h @@ -0,0 +1,400 @@ +/** + * @file token_enum.h + * List of the different tokens used in the program. + * + * @author Ben Gardner + * @author Guy Maurel since version 0.62 for uncrustify4Qt + * October 2015 + * @license GPL v2+ + */ + +#ifndef TOKEN_ENUM_H_INCLUDED +#define TOKEN_ENUM_H_INCLUDED + +/** + * abbreviations used: + * CT = chunk type + */ + + +/** + * This is an enum of all the different chunks/tokens/elements that the + * program can work with. The parser and scanner assigns one of these to + * each chunk/token. + */ +enum E_Token +{ + CT_NONE, + CT_PARENT_NOT_SET, + CT_EOF, + CT_UNKNOWN, + + CT_JUNK, // junk collected when parsing is disabled + + CT_WHITESPACE, // whitespace without any newlines + CT_SPACE, // a fixed number of spaces to support weird spacing rules + CT_NEWLINE, // CRA, one or more newlines + CT_NL_CONT, // CRA, backslash-newline + CT_FORM_FEED, // character 12 + CT_COMMENT_CPP, // C++ comment (always followed by CT_NEWLINE) + CT_COMMENT, // C-comment, single line + CT_COMMENT_MULTI, // Multi-lined comment + CT_COMMENT_EMBED, // comment parent_type: non-newline before and after + CT_COMMENT_START, // comment parent_type: newline before + CT_COMMENT_END, // comment parent_type: newline after + CT_COMMENT_WHOLE, // comment parent_type: newline before and after + CT_COMMENT_ENDIF, // C-comment, single line, after ENDIF + + CT_IGNORED, // a chunk of ignored text + + CT_WORD, // variable, type, function name, etc + CT_NUMBER, + CT_NUMBER_FP, + CT_STRING, // quoted string "hi" or 'a' or <in> for include + CT_STRING_MULTI, // quoted string with embedded newline + CT_IF, // built-in keywords + CT_ELSE, + CT_ELSEIF, + CT_CONSTEXPR, // only when preceded by 'if' (otherwise CT_QUALIFIER) + CT_FOR, + CT_WHILE, + CT_WHILE_OF_DO, + CT_SWITCH, + CT_CASE, + CT_DO, + CT_SYNCHRONIZED, + CT_VOLATILE, + CT_TYPEDEF, + CT_STRUCT, + CT_ENUM, + CT_ENUM_CLASS, + CT_SIZEOF, + CT_DECLTYPE, + CT_RETURN, + CT_BREAK, + CT_UNION, + CT_GOTO, + CT_CONTINUE, + CT_C_CAST, // C-style cast: "(int)5.6" + CT_CPP_CAST, // C++-style cast: "int(5.6)" + CT_D_CAST, // D-style cast: "cast(type)" and "const(type)" + CT_TYPE_CAST, // static_cast<type>(exp) + CT_TYPENAME, // typename type + CT_TEMPLATE, // template<...> + CT_PARAMETER_PACK, // template<typename ... ARGS> + CT_WHERE_SPEC, // 'where' : used in C# generic constraint + + CT_ASSIGN, // =, +=, /=, etc + CT_ASSIGN_NL, // Assign followed by a newline - fake item for indenting + CT_SASSIGN, // 'and_eq' + + CT_ASSIGN_DEFAULT_ARG, // Default argument such as + // Foo( int Foo = 5 ); + CT_ASSIGN_FUNC_PROTO, // function prototype modifier such as + // void* operator new(std::size_t) = delete; + // Foo( const Foo & ) = default; + // Foo( const Foo & ) = 0; + + CT_COMPARE, // ==, !=, <=, >= + CT_SCOMPARE, // compare op that is a string 'is', 'neq' + CT_BOOL, // || or && + CT_SBOOL, // or, and + CT_ARITH, // +, -, /, etc + CT_SARITH, // 'not', 'xor' + CT_SHIFT, // <<, >> + CT_CARET, // ^ + CT_DEREF, // * dereference + CT_INCDEC_BEFORE, // ++a or --a + CT_INCDEC_AFTER, // a++ or a-- + CT_MEMBER, // . or -> + CT_DC_MEMBER, // :: + CT_C99_MEMBER, // . in structure stuff + CT_INV, // ~ + CT_DESTRUCTOR, // ~ + CT_NOT, // ! + CT_D_TEMPLATE, // ! as in Foo!(A) + CT_ADDR, // & + CT_NEG, // - as in -1 + CT_POS, // + as in +1 + CT_STAR, // * : raw char to be changed + CT_PLUS, // + : raw char to be changed + CT_MINUS, // - : raw char to be changed + CT_AMP, // & : raw char to be changed + CT_BYREF, // & in function def/proto params + + // CT_BITWISE_AND, // & // is a CT_ARITH + // CT_BITWISE_OR, // | // is a CT_ARITH + // CT_BITWISE_EXCLUSIVE_OR,// ^ // is a CT_ARITH + // CT_BITWISE_NOT, // ~ // is a CT_ARITH + + CT_POUND, // # + CT_PREPROC, // # at the start of a line + CT_PREPROC_INDENT, // # at the start of a line that gets indented: #region + CT_PREPROC_BODY, // body of every preproc EXCEPT #define + CT_PP, // ## + CT_ELLIPSIS, // ... + CT_RANGE, // .. + CT_NULLCOND, // ?. + + CT_SEMICOLON, + CT_VSEMICOLON, // virtual semicolon for PAWN + CT_COLON, + CT_ASM_COLON, + CT_CASE_COLON, + CT_CASE_ELLIPSIS, // '...' in `case 1 ... 5`: + CT_CLASS_COLON, // colon after a class def + CT_CONSTR_COLON, // colon after a constructor + CT_D_ARRAY_COLON, // D named array initializer colon + CT_COND_COLON, // conditional colon in 'b ? t : f' + CT_WHERE_COLON, // C# where-constraint colon (after the type) + CT_QUESTION, + CT_COMMA, + + CT_ASM, + CT_ATTRIBUTE, + CT_AUTORELEASEPOOL, // OC: Autorelease Pool Blocks, used by iOS + CT_OC_AVAILABLE, + CT_OC_AVAILABLE_VALUE, + CT_CATCH, + CT_WHEN, + CT_WHERE, // C# where clause + CT_CLASS, + CT_DELETE, + CT_EXPORT, + CT_FRIEND, + CT_NAMESPACE, + CT_PACKAGE, + CT_NEW, // may turn into CT_PBRACED if followed by a '(' + CT_OPERATOR, + CT_OPERATOR_VAL, + CT_ASSIGN_OPERATOR, // the value after 'operator' such as: + // Foo &operator= ( const Foo & ); + CT_ACCESS, + CT_ACCESS_COLON, + CT_THROW, + CT_NOEXCEPT, + CT_TRY, + CT_BRACED_INIT_LIST, + CT_USING, + CT_USING_STMT, // using (xxx) ... + CT_USING_ALIAS, // using identifier attr(optional) = type-id + CT_D_WITH, // D: parenthetis+braced + CT_D_MODULE, + CT_SUPER, + CT_DELEGATE, + CT_BODY, + CT_DEBUG, + CT_DEBUGGER, + CT_INVARIANT, + CT_UNITTEST, + CT_UNSAFE, + CT_FINALLY, + CT_FIXED, // C# fixed + CT_IMPORT, + CT_D_SCOPE, + CT_D_SCOPE_IF, + CT_LAZY, + CT_D_MACRO, + CT_D_VERSION, // turns into CT_D_VERSION_IF if not followed by '=' + CT_D_VERSION_IF, // version(x) { } + + // note for parenthetis/brace/square pairs: close MUST be open + 1 + CT_PAREN_OPEN, + CT_PAREN_CLOSE, + + CT_ANGLE_OPEN, // template<T*> + CT_ANGLE_CLOSE, + + CT_SPAREN_OPEN, // 'special' parenthetis after if/for/switch/while/synchronized/catch + CT_SPAREN_CLOSE, + + CT_PPAREN_OPEN, // 'protect' parenthetis to protect a type such as (*int) + CT_PPAREN_CLOSE, // used at align_func_param + + CT_FPAREN_OPEN, // 'function' parenthetis after fcn/macro fcn + CT_FPAREN_CLOSE, + + CT_LPAREN_OPEN, // lambda-declarator parenthetis + CT_LPAREN_CLOSE, + + CT_TPAREN_OPEN, // 'type' parenthetis used in function types + CT_TPAREN_CLOSE, + + CT_BRACE_OPEN, // {...} + CT_BRACE_CLOSE, + + CT_VBRACE_OPEN, // virtual brace, i.e. brace inserted by uncrustify + CT_VBRACE_CLOSE, + + CT_SQUARE_OPEN, // [...] + CT_SQUARE_CLOSE, + + CT_TSQUARE, // special case of [] + + CT_MACRO_OPEN, // stuff specified via custom-pair + CT_MACRO_CLOSE, + CT_MACRO_ELSE, + + // aggregate types + CT_LABEL, // a non-case label + CT_LABEL_COLON, // the colon for a label + CT_FUNCTION, // function - unspecified, call mark_function() + CT_FUNC_CALL, // function call + CT_FUNC_CALL_USER, // function call (special user) + CT_FUNC_DEF, // function definition/implementation + CT_FUNC_TYPE, // function type - foo in "typedef void (*foo)(void)" + CT_FUNC_VAR, // foo and parent type of first parens in "void (*foo)(void)" + CT_FUNC_PROTO, // function prototype + CT_FUNC_START, // global DC member for functions(void ::func()) + CT_FUNC_CLASS_DEF, // ctor or dtor for a class + CT_FUNC_CLASS_PROTO, // ctor or dtor for a class + CT_FUNC_CTOR_VAR, // variable or class initialization + CT_FUNC_WRAP, // macro that wraps the function name + CT_PROTO_WRAP, // macro: "RETVAL PROTO_WRAP( fcn_name, (PARAMS))". Parens for PARAMS are optional. + CT_MACRO_FUNC, // function-like macro + CT_MACRO_FUNC_CALL, // function-like macro call + CT_MACRO, // a macro def + CT_QUALIFIER, // static, const, etc + CT_EXTERN, // extern + CT_DECLSPEC, // __declspec + CT_ALIGN, // paren'd qualifier: align(4) struct a { } + CT_TYPE, + CT_PTR_TYPE, // a '*' as part of a type + CT_TYPE_WRAP, // macro that wraps a type name + CT_CPP_LAMBDA, // parent for '[=](...){...}' + CT_CPP_LAMBDA_RET, // '->' in '[=](...) -> type {...}' + CT_EXECUTION_CONTEXT, // Keyword for use in lambda statement: [] CT_EXECUTION_CONTEXT ()->{} + CT_TRAILING_RET, // '->' in 'auto fname(...) -> type;' + // '->' in 'auto fname(...) const -> type;' + CT_BIT_COLON, // a ':' in a variable declaration + + CT_OC_DYNAMIC, + CT_OC_END, // ObjC: @end + CT_OC_IMPL, // ObjC: @implementation + CT_OC_INTF, // ObjC: @interface + CT_OC_PROTOCOL, // ObjC: @protocol or @protocol() + CT_OC_PROTO_LIST, // ObjC: protocol list < > (parent token only) + CT_OC_GENERIC_SPEC, // ObjC: specification of generic < > + CT_OC_PROPERTY, // ObjC: @property + CT_OC_CLASS, // ObjC: the name after @interface or @implementation + CT_OC_CLASS_EXT, // ObjC: a pair of empty parens after the class name in a @interface or @implementation + CT_OC_CATEGORY, // ObjC: the category name in parens after the class name in a @interface or @implementation + CT_OC_SCOPE, // ObjC: the '-' or '+' in '-(void) func: (int) i;' + CT_OC_MSG, // ObjC: parent type to '[', ']' and ';' in '[class func : param name: param];' + CT_OC_MSG_CLASS, // ObjC: 'class' in '[class func : param name: param];' (see also PCF_IN_OC_MSG) + CT_OC_MSG_FUNC, // ObjC: 'func' in '[class func : param name: param];' (see also PCF_IN_OC_MSG) + CT_OC_MSG_NAME, // ObjC: 'name' in '[class func : param name: param];' (see also PCF_IN_OC_MSG) + CT_OC_MSG_SPEC, // ObjC: msg spec '-(void) func: (int) i;' + CT_OC_MSG_DECL, // ObjC: msg decl '-(void) func: (int) i { }' + CT_OC_RTYPE, // ObjC: marks parens of the return type after scope + CT_OC_ATYPE, // ObjC: marks parens of the arg type after scope + CT_OC_COLON, // ObjC: the colon in a msg spec + CT_OC_DICT_COLON, // ObjC: colon in dictionary constant: "KEY: VALUE" + CT_OC_SEL, // ObjC: @selector + CT_OC_SEL_NAME, // ObjC: selector name + CT_OC_BLOCK, // ObjC: block parent type. + CT_OC_BLOCK_ARG, // ObjC: block arguments parent type. + CT_OC_BLOCK_TYPE, // ObjC: block declaration parent type, e.g. mainly the '(^block_t)' in 'void (^block_t)(int arg);' + CT_OC_BLOCK_EXPR, // ObjC: block expression with arg: '^(int arg) { arg++; };' and without (called a block literal): '^{ ... };' + CT_OC_BLOCK_CARET, // ObjC: block pointer caret: '^' + CT_OC_AT, // ObjC: boxed constants using '@' + CT_OC_PROPERTY_ATTR, // ObjC: property attribute (strong, weak, readonly, etc...) + + // start PP types + CT_PP_DEFINE, // #define + CT_PP_DEFINED, // #if defined + CT_PP_INCLUDE, // #include + CT_PP_IF, // #if, #ifdef, or #ifndef + CT_PP_ELSE, // #else or #elif + CT_PP_ENDIF, // #endif + CT_PP_ASSERT, + CT_PP_EMIT, + CT_PP_ENDASM, // end of assembly code section + CT_PP_ENDINPUT, + CT_PP_ERROR, + CT_PP_FILE, + CT_PP_LINE, + CT_PP_SECTION, + CT_PP_ASM, // start of assembly code section + CT_PP_UNDEF, + CT_PP_PROPERTY, + + CT_PP_BODYCHUNK, // everything after this gets put in CT_PREPROC_BODY + + CT_PP_PRAGMA, // pragma's should not be altered + CT_PP_REGION, // C# #region + CT_PP_ENDREGION, // C# #endregion + CT_PP_REGION_INDENT, // Dummy token for indenting a C# #region + CT_PP_IF_INDENT, // Dummy token for indenting a #if stuff + CT_PP_IGNORE, // Dummy token for ignoring a certain preprocessor directive (do not do any processing) + CT_PP_OTHER, // #line, #error, #pragma, etc + // end PP types + + // PAWN stuff + CT_CHAR, + CT_DEFINED, + CT_FORWARD, + CT_NATIVE, + CT_STATE, + CT_STOCK, + CT_TAGOF, + CT_DOT, + CT_TAG, + CT_TAG_COLON, + + // C-sharp + CT_LOCK, // lock/unlock + CT_AS, + CT_IN, // "foreach (T c in x)" or "foo(in char c)" or "in { ..." + CT_BRACED, // simple braced items: try {} + CT_THIS, // may turn into CT_PBRACED if followed by a '(' + CT_BASE, // C# thingy + CT_DEFAULT, // may be changed into CT_CASE + CT_GETSET, // must be followed by CT_BRACE_OPEN or reverts to CT_WORD + CT_GETSET_EMPTY, // get/set/add/remove followed by a semicolon + CT_CONCAT, // The '~' between strings + CT_CS_SQ_STMT, // '[assembly: xxx]' or '[Attribute()]' or '[Help()]', etc + CT_CS_SQ_COLON, // the colon in one of those [] thingys + CT_CS_PROPERTY, // word or ']' followed by '{' + + // Embedded SQL - always terminated with a semicolon + CT_SQL_EXEC, // the 'EXEC' in 'EXEC SQL ...' + CT_SQL_BEGIN, // the 'BEGINN' in 'EXEC SQL BEGIN ...' + CT_SQL_END, // the 'END' in 'EXEC SQL END ...' + CT_SQL_WORD, // CT_WORDs in the 'EXEC SQL' statement + CT_SQL_ASSIGN, // := + + // Vala stuff + CT_CONSTRUCT, // braced "construct { }" or qualifier "(construct int x)" + CT_LAMBDA, + + // Java + CT_ASSERT, // assert EXP1 [ : EXP2 ] ; + CT_ANNOTATION, // @interface or @something(...) + CT_FOR_COLON, // colon in "for ( TYPE var: EXPR ) { ... }" + CT_DOUBLE_BRACE, // parent for double brace + + /* Clang */ + CT_CNG_HASINC, // Clang: __has_include() + CT_CNG_HASINCN, // Clang: __has_include_next() + + // extensions for Qt macros + CT_Q_EMIT, // guy 2015-10-16 + CT_Q_FOREACH, // guy 2015-09-23 + CT_Q_FOREVER, // guy 2015-10-18 + CT_Q_GADGET, // guy 2016-05-04 + CT_Q_OBJECT, // guy 2015-10-16 + + // Machine Modes + CT_MODE, // guy 2016-03-11 + CT_DI, // guy 2016-03-11 + CT_HI, // guy 2016-03-11 + CT_QI, // guy 2016-03-11 + CT_SI, // guy 2016-03-11 + CT_NOTHROW, // guy 2016-03-11 + CT_WORD_, // guy 2016-03-11 + + CT_TOKEN_COUNT_ // NOTE: Keep this the last entry because it's used as a counter. +}; + +#endif /* TOKEN_ENUM_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/tokenize.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/tokenize.cpp new file mode 100644 index 00000000..0aeafe63 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/tokenize.cpp @@ -0,0 +1,2881 @@ +/** + * @file tokenize.cpp + * This file breaks up the text stream into tokens or chunks. + * + * Each routine needs to set pc.len and pc.type. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "tokenize.h" + +#include "keywords.h" +#include "prototypes.h" +#include "punctuators.h" +#include "unc_ctype.h" + +#include <regex> +#include <stack> + + +#define LE_COUNT(x) cpd.le_counts[static_cast<size_t>(LE_ ## x)] + +constexpr static auto LCURRENT = LTOK; + +using namespace std; +using namespace uncrustify; + + +struct tok_info +{ + tok_info() + : last_ch(0) + , idx(0) + , row(1) + , col(1) + { + } + + size_t last_ch; + size_t idx; + size_t row; + size_t col; +}; + + +struct tok_ctx +{ + tok_ctx(const deque<int> &d) + : data(d) + { + } + + + //! save before trying to parse something that may fail + void save() + { + save(s); + } + + + void save(tok_info &info) + { + info = c; + } + + + //! restore previous saved state + void restore() + { + restore(s); + } + + + void restore(const tok_info &info) + { + c = info; + } + + + bool more() + { + return(c.idx < data.size()); + } + + + size_t peek() + { + return(more() ? data[c.idx] : 0); + } + + + size_t peek(size_t idx) + { + idx += c.idx; + return((idx < data.size()) ? data[idx] : 0); + } + + + size_t get() + { + if (more()) + { + size_t ch = data[c.idx++]; + + switch (ch) + { + case '\t': + log_rule_B("input_tab_size"); + c.col = calc_next_tab_column(c.col, options::input_tab_size()); + break; + + case '\n': + + if (c.last_ch != '\r') + { + c.row++; + c.col = 1; + } + break; + + case '\r': + c.row++; + c.col = 1; + break; + + default: + c.col++; + break; + } + c.last_ch = ch; + return(ch); + } + return(0); + } + + + bool expect(size_t ch) + { + if (peek() == ch) + { + get(); + return(true); + } + return(false); + } + + + const deque<int> &data; + tok_info c; //! current + tok_info s; //! saved +}; + + +/** + * Count the number of characters in a quoted string. + * The next bit of text starts with a quote char " or ' or <. + * Count the number of characters until the matching character. + * + * @param pc The structure to update, str is an input. + * + * @return Whether a string was parsed + */ +static bool parse_string(tok_ctx &ctx, Chunk &pc, size_t quote_idx, bool allow_escape); + + +/** + * Literal string, ends with single " + * Two "" don't end the string. + * + * @param pc The structure to update, str is an input. + * + * @return Whether a string was parsed + */ +static bool parse_cs_string(tok_ctx &ctx, Chunk &pc); + + +/** + * VALA verbatim string, ends with three quotes (""") + * + * @param pc The structure to update, str is an input. + */ +static void parse_verbatim_string(tok_ctx &ctx, Chunk &pc); + + +static bool tag_compare(const deque<int> &d, size_t a_idx, size_t b_idx, size_t len); + + +/** + * Parses a C++0x 'R' string. R"( xxx )" R"tag( )tag" u8R"(x)" uR"(x)" + * Newlines may be in the string. + * + * @param pc structure to update, str is an input. + */ +static bool parse_cr_string(tok_ctx &ctx, Chunk &pc, size_t q_idx); + + +/** + * Count the number of whitespace characters. + * + * @param pc The structure to update, str is an input. + * + * @return Whether whitespace was parsed + */ +static bool parse_whitespace(tok_ctx &ctx, Chunk &pc); + + +/** + * Called when we hit a backslash. + * If there is nothing but whitespace until the newline, then this is a + * backslash newline + * + * @param pc structure to update, str is an input + */ +static bool parse_bs_newline(tok_ctx &ctx, Chunk &pc); + + +/** + * Parses any number of tab or space chars followed by a newline. + * Does not change pc.len if a newline isn't found. + * This is not the same as parse_whitespace() because it only consumes until + * a single newline is encountered. + */ +static bool parse_newline(tok_ctx &ctx); + + +/** + * PAWN #define is different than C/C++. + * #define PATTERN REPLACEMENT_TEXT + * The PATTERN may not contain a space or '[' or ']'. + * A generic whitespace check should be good enough. + * Do not change the pattern. + * + * @param pc structure to update, str is an input + */ +static void parse_pawn_pattern(tok_ctx &ctx, Chunk &pc, E_Token tt); + + +static bool parse_ignored(tok_ctx &ctx, Chunk &pc); + + +/** + * Skips the next bit of whatever and returns the type of block. + * + * pc.str is the input text. + * pc.len in the output length. + * pc.type is the output type + * pc.column is output column + * + * @param pc The structure to update, str is an input. + * @param prev_pc The previous structure + * + * @return true/false - whether anything was parsed + */ +static bool parse_next(tok_ctx &ctx, Chunk &pc, const Chunk *prev_pc); + + +/** + * Parses all legal D string constants. + * + * Quoted strings: + * r"Wysiwyg" # WYSIWYG string + * x"hexstring" # Hexadecimal array + * `Wysiwyg` # WYSIWYG string + * 'char' # single character + * "reg_string" # regular string + * + * Non-quoted strings: + * \x12 # 1-byte hex constant + * \u1234 # 2-byte hex constant + * \U12345678 # 4-byte hex constant + * \123 # octal constant + * \& # named entity + * \n # single character + * + * @param pc The structure to update, str is an input. + * + * @return Whether a string was parsed + */ +static bool d_parse_string(tok_ctx &ctx, Chunk &pc); + + +/** + * Figure of the length of the comment at text. + * The next bit of text starts with a '/', so it might be a comment. + * There are three types of comments: + * - C comments that start with '/ *' and end with '* /' + * - C++ comments that start with // + * - D nestable comments '/+' '+/' + * + * @param pc The structure to update, str is an input. + * + * @return Whether a comment was parsed + */ +static bool parse_comment(tok_ctx &ctx, Chunk &pc); + + +/** + * Figure of the length of the code placeholder at text, if present. + * This is only for Xcode which sometimes inserts temporary code placeholder chunks, which in plaintext <#look like this#>. + * + * @param pc The structure to update, str is an input. + * + * @return Whether a placeholder was parsed. + */ +static bool parse_code_placeholder(tok_ctx &ctx, Chunk &pc); + + +/** + * Parse any attached suffix, which may be a user-defined literal suffix. + * If for a string, explicitly exclude common format and scan specifiers, ie, + * PRIx32 and SCNx64. + */ +static void parse_suffix(tok_ctx &ctx, Chunk &pc, bool forstring); + + +//! check if a symbol holds a boolean value +static bool is_bin(int ch); +static bool is_bin_(int ch); + + +//! check if a symbol holds a octal value +static bool is_oct(int ch); +static bool is_oct_(int ch); + + +//! check if a symbol holds a decimal value; +static bool is_dec(int ch); +static bool is_dec_(int ch); + + +//! check if a symbol holds a hexadecimal value +static bool is_hex(int ch); +static bool is_hex_(int ch); + + +/** + * Count the number of characters in the number. + * The next bit of text starts with a number (0-9 or '.'), so it is a number. + * Count the number of characters in the number. + * + * This should cover all number formats for all languages. + * Note that this is not a strict parser. It will happily parse numbers in + * an invalid format. + * + * For example, only D allows underscores in the numbers, but they are + * allowed in all formats. + * + * @param[in,out] pc The structure to update, str is an input. + * + * @return Whether a number was parsed + */ +static bool parse_number(tok_ctx &ctx, Chunk &pc); + + +static bool d_parse_string(tok_ctx &ctx, Chunk &pc) +{ + size_t ch = ctx.peek(); + + if ( ch == '"' + || ch == '\'') + { + return(parse_string(ctx, pc, 0, true)); + } + + if (ch == '`') + { + return(parse_string(ctx, pc, 0, false)); + } + + if ( ( ch == 'r' + || ch == 'x') + && ctx.peek(1) == '"') + { + return(parse_string(ctx, pc, 1, false)); + } + + if (ch != '\\') + { + return(false); + } + ctx.save(); + int cnt; + + pc.Str().clear(); + + while (ctx.peek() == '\\') + { + pc.Str().append(ctx.get()); + + // Check for end of file + switch (ctx.peek()) + { + case 'x': // \x HexDigit HexDigit + cnt = 3; + + while (cnt--) + { + pc.Str().append(ctx.get()); + } + break; + + case 'u': // \u HexDigit (x4) + cnt = 5; + + while (cnt--) + { + pc.Str().append(ctx.get()); + } + break; + + case 'U': // \U HexDigit (x8) + cnt = 9; + + while (cnt--) + { + pc.Str().append(ctx.get()); + } + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + // handle up to 3 octal digits + pc.Str().append(ctx.get()); + ch = ctx.peek(); + + if ( (ch >= '0') + && (ch <= '7')) + { + pc.Str().append(ctx.get()); + ch = ctx.peek(); + + if ( (ch >= '0') + && (ch <= '7')) + { + pc.Str().append(ctx.get()); + } + } + break; + + case '&': + // \& NamedCharacterEntity ; + pc.Str().append(ctx.get()); + + while (unc_isalpha(ctx.peek())) + { + pc.Str().append(ctx.get()); + } + + if (ctx.peek() == ';') + { + pc.Str().append(ctx.get()); + } + break; + + default: + // Everything else is a single character + pc.Str().append(ctx.get()); + break; + } // switch + } + + if (pc.GetStr().size() < 1) + { + ctx.restore(); + return(false); + } + pc.SetType(CT_STRING); + return(true); +} // d_parse_string + + +#if 0 + + +//! A string-in-string search. Like strstr() with a haystack length. +static const char *str_search(const char *needle, const char *haystack, int haystack_len) +{ + int needle_len = strlen(needle); + + while (haystack_len-- >= needle_len) + { + if (memcmp(needle, haystack, needle_len) == 0) + { + return(haystack); + } + haystack++; + } + return(NULL); +} +#endif + + +static bool parse_comment(tok_ctx &ctx, Chunk &pc) +{ + bool is_d = language_is_set(LANG_D); + bool is_cs = language_is_set(LANG_CS); + size_t d_level = 0; + + // does this start with '/ /' or '/ *' or '/ +' (d) + if ( (ctx.peek() != '/') + || ( (ctx.peek(1) != '*') + && (ctx.peek(1) != '/') + && ( (ctx.peek(1) != '+') + || !is_d))) + { + return(false); + } + ctx.save(); + + // account for opening two chars + pc.Str() = ctx.get(); // opening '/' + size_t ch = ctx.get(); + + pc.Str().append(ch); // second char + + if (ch == '/') + { + pc.SetType(CT_COMMENT_CPP); + + while (true) + { + int bs_cnt = 0; + + while (ctx.more()) + { + ch = ctx.peek(); + + if ( (ch == '\r') + || (ch == '\n')) + { + break; + } + + if ( (ch == '\\') + && !is_cs) // backslashes aren't special in comments in C# + { + bs_cnt++; + } + else + { + bs_cnt = 0; + } + pc.Str().append(ctx.get()); + } + + /* + * If we hit an odd number of backslashes right before the newline, + * then we keep going. + */ + if ( ((bs_cnt & 1) == 0) + || !ctx.more()) + { + break; + } + + if (ctx.peek() == '\r') + { + pc.Str().append(ctx.get()); + } + + if (ctx.peek() == '\n') + { + pc.Str().append(ctx.get()); + } + pc.SetNlCount(pc.GetNlCount() + 1); + cpd.did_newline = true; + } + } + else if (!ctx.more()) + { + // unexpected end of file + ctx.restore(); + return(false); + } + else if (ch == '+') + { + pc.SetType(CT_COMMENT); + d_level++; + + while ( d_level > 0 + && ctx.more()) + { + if ( (ctx.peek() == '+') + && (ctx.peek(1) == '/')) + { + pc.Str().append(ctx.get()); // store the '+' + pc.Str().append(ctx.get()); // store the '/' + d_level--; + continue; + } + + if ( (ctx.peek() == '/') + && (ctx.peek(1) == '+')) + { + pc.Str().append(ctx.get()); // store the '/' + pc.Str().append(ctx.get()); // store the '+' + d_level++; + continue; + } + ch = ctx.get(); + pc.Str().append(ch); + + if ( (ch == '\n') + || (ch == '\r')) + { + pc.SetType(CT_COMMENT_MULTI); + pc.SetNlCount(pc.GetNlCount() + 1); + + if (ch == '\r') + { + if (ctx.peek() == '\n') + { + ++LE_COUNT(CRLF); + pc.Str().append(ctx.get()); // store the '\n' + } + else + { + ++LE_COUNT(CR); + } + } + else + { + ++LE_COUNT(LF); + } + } + } + } + else // must be '/ *' + { + pc.SetType(CT_COMMENT); + + while (ctx.more()) + { + if ( (ctx.peek() == '*') + && (ctx.peek(1) == '/')) + { + pc.Str().append(ctx.get()); // store the '*' + pc.Str().append(ctx.get()); // store the '/' + + tok_info ss; + ctx.save(ss); + size_t oldsize = pc.GetStr().size(); + + // If there is another C comment right after this one, combine them + while ( (ctx.peek() == ' ') + || (ctx.peek() == '\t')) + { + pc.Str().append(ctx.get()); + } + + if ( (ctx.peek() != '/') + || (ctx.peek(1) != '*')) + { + // undo the attempt to join + ctx.restore(ss); + pc.Str().resize(oldsize); + break; + } + } + ch = ctx.get(); + pc.Str().append(ch); + + if ( (ch == '\n') + || (ch == '\r')) + { + pc.SetType(CT_COMMENT_MULTI); + pc.SetNlCount(pc.GetNlCount() + 1); + + if (ch == '\r') + { + if (ctx.peek() == '\n') + { + ++LE_COUNT(CRLF); + pc.Str().append(ctx.get()); // store the '\n' + } + else + { + ++LE_COUNT(CR); + } + } + else + { + ++LE_COUNT(LF); + } + } + } + } + + if (cpd.unc_off) + { + bool found_enable_marker = (find_enable_processing_comment_marker(pc.GetStr()) >= 0); + + if (found_enable_marker) + { + const auto &ontext = options::enable_processing_cmt(); + + LOG_FMT(LBCTRL, "%s(%d): Found '%s' on line %zu\n", + __func__, __LINE__, ontext.c_str(), pc.GetOrigLine()); + cpd.unc_off = false; + } + } + else + { + auto position_disable_processing_cmt = find_disable_processing_comment_marker(pc.GetStr()); + bool found_disable_marker = (position_disable_processing_cmt >= 0); + + if (found_disable_marker) + { + /** + * the user may wish to disable processing part of a multiline comment, + * in which case we'll handle at a late time. Check to see if processing + * is re-enabled elsewhere in this comment + */ + auto position_enable_processing_cmt = find_enable_processing_comment_marker(pc.GetStr()); + + if (position_enable_processing_cmt < position_disable_processing_cmt) + { + const auto &offtext = options::disable_processing_cmt(); + + LOG_FMT(LBCTRL, "%s(%d): Found '%s' on line %zu\n", + __func__, __LINE__, offtext.c_str(), pc.GetOrigLine()); + cpd.unc_off = true; + // Issue #842 + cpd.unc_off_used = true; + } + } + } + return(true); +} // parse_comment + + +static bool parse_code_placeholder(tok_ctx &ctx, Chunk &pc) +{ + if ( (ctx.peek() != '<') + || (ctx.peek(1) != '#')) + { + return(false); + } + ctx.save(); + + // account for opening two chars '<#' + pc.Str() = ctx.get(); + pc.Str().append(ctx.get()); + + // grab everything until '#>', fail if not found. + size_t last1 = 0; + + while (ctx.more()) + { + size_t last2 = last1; + last1 = ctx.get(); + pc.Str().append(last1); + + if ( (last2 == '#') + && (last1 == '>')) + { + pc.SetType(CT_WORD); + return(true); + } + } + ctx.restore(); + return(false); +} + + +static void parse_suffix(tok_ctx &ctx, Chunk &pc, bool forstring = false) +{ + if (CharTable::IsKw1(ctx.peek())) + { + size_t slen = 0; + size_t oldsize = pc.GetStr().size(); + + // don't add the suffix if we see L" or L' or S" + size_t p1 = ctx.peek(); + size_t p2 = ctx.peek(1); + + if ( forstring + && ( ( (p1 == 'L') + && ( (p2 == '"') + || (p2 == '\''))) + || ( (p1 == 'S') + && (p2 == '"')))) + { + return; + } + tok_info ss; + ctx.save(ss); + + while ( ctx.more() + && CharTable::IsKw2(ctx.peek())) + { + slen++; + pc.Str().append(ctx.get()); + } + + if ( forstring + && slen >= 4 + && ( pc.GetStr().startswith("PRI", oldsize) + || pc.GetStr().startswith("SCN", oldsize))) + { + ctx.restore(ss); + pc.Str().resize(oldsize); + } + } +} + + +static bool is_bin(int ch) +{ + return( (ch == '0') + || (ch == '1')); +} + + +static bool is_bin_(int ch) +{ + return( is_bin(ch) + || ch == '_' + || ch == '\''); +} + + +static bool is_oct(int ch) +{ + return( (ch >= '0') + && (ch <= '7')); +} + + +static bool is_oct_(int ch) +{ + return( is_oct(ch) + || ch == '_' + || ch == '\''); +} + + +static bool is_dec(int ch) +{ + return( (ch >= '0') + && (ch <= '9')); +} + + +static bool is_dec_(int ch) +{ + // number separators: JAVA: "_", C++14: "'" + return( is_dec(ch) + || (ch == '_') + || (ch == '\'')); +} + + +static bool is_hex(int ch) +{ + return( ( (ch >= '0') + && (ch <= '9')) + || ( (ch >= 'a') + && (ch <= 'f')) + || ( (ch >= 'A') + && (ch <= 'F'))); +} + + +static bool is_hex_(int ch) +{ + return( is_hex(ch) + || ch == '_' + || ch == '\''); +} + + +static bool parse_number(tok_ctx &ctx, Chunk &pc) +{ + /* + * A number must start with a digit or a dot, followed by a digit + * (signs handled elsewhere) + */ + if ( !is_dec(ctx.peek()) + && ( (ctx.peek() != '.') + || !is_dec(ctx.peek(1)))) + { + return(false); + } + bool is_float = (ctx.peek() == '.'); + + if ( is_float + && (ctx.peek(1) == '.')) // make sure it isn't '..' + { + return(false); + } + /* + * Check for Hex, Octal, or Binary + * Note that only D, C++14 and Pawn support binary + * Fixes the issue # 1591 + * In c# the numbers starting with 0 are not treated as octal numbers. + */ + bool did_hex = false; + + if ( ctx.peek() == '0' + && !language_is_set(LANG_CS)) + { + size_t ch; + Chunk pc_temp; + + pc.Str().append(ctx.get()); // store the '0' + pc_temp.Str().append('0'); + + // MS constant might have an "h" at the end. Look for it + ctx.save(); + + while ( ctx.more() + && CharTable::IsKw2(ctx.peek())) + { + ch = ctx.get(); + pc_temp.Str().append(ch); + } + ch = pc_temp.GetStr()[pc_temp.Len() - 1]; + ctx.restore(); + LOG_FMT(LGUY, "%s(%d): pc_temp:%s\n", __func__, __LINE__, pc_temp.Text()); + + if (ch == 'h') // TODO can we combine this in analyze_character + { + // we have an MS hexadecimal number with "h" at the end + LOG_FMT(LGUY, "%s(%d): MS hexadecimal number\n", __func__, __LINE__); + did_hex = true; + + do + { + pc.Str().append(ctx.get()); // store the rest + } while (is_hex_(ctx.peek())); + + pc.Str().append(ctx.get()); // store the h + LOG_FMT(LGUY, "%s(%d): pc:%s\n", __func__, __LINE__, pc.Text()); + } + else + { + switch (unc_toupper(ctx.peek())) + { + case 'X': // hex + did_hex = true; + + do + { + pc.Str().append(ctx.get()); // store the 'x' and then the rest + } while (is_hex_(ctx.peek())); + + break; + + case 'B': // binary + + do + { + pc.Str().append(ctx.get()); // store the 'b' and then the rest + } while (is_bin_(ctx.peek())); + + break; + + case '0': // octal or decimal + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + + do + { + pc.Str().append(ctx.get()); + } while (is_oct_(ctx.peek())); + + break; + + default: + // either just 0 or 0.1 or 0UL, etc + break; + } // switch + } + } + else + { + // Regular int or float + while (is_dec_(ctx.peek())) + { + pc.Str().append(ctx.get()); + } + } + + // Check if we stopped on a decimal point & make sure it isn't '..' + if ( (ctx.peek() == '.') + && (ctx.peek(1) != '.')) + { + // Issue #1265, 5.clamp() + tok_info ss; + ctx.save(ss); + + while ( ctx.more() + && CharTable::IsKw2(ctx.peek(1))) + { + // skip characters to check for paren open + ctx.get(); + } + + if (ctx.peek(1) == '(') + { + ctx.restore(ss); + pc.SetType(CT_NUMBER); + return(true); + } + else + { + ctx.restore(ss); + } + pc.Str().append(ctx.get()); + is_float = true; + + if (did_hex) + { + while (is_hex_(ctx.peek())) + { + pc.Str().append(ctx.get()); + } + } + else + { + while (is_dec_(ctx.peek())) + { + pc.Str().append(ctx.get()); + } + } + } + /* + * Check exponent + * Valid exponents per language (not that it matters): + * C/C++/D/Java: eEpP + * C#/Pawn: eE + */ + size_t tmp = unc_toupper(ctx.peek()); + + if ( (tmp == 'E') + || (tmp == 'P')) + { + is_float = true; + pc.Str().append(ctx.get()); + + if ( (ctx.peek() == '+') + || (ctx.peek() == '-')) + { + pc.Str().append(ctx.get()); + } + + while (is_dec_(ctx.peek())) + { + pc.Str().append(ctx.get()); + } + } + + /* + * Check the suffixes + * Valid suffixes per language (not that it matters): + * Integer Float + * C/C++: uUlL64 lLfF + * C#: uUlL fFdDMm + * D: uUL ifFL + * Java: lL fFdD + * Pawn: (none) (none) + * + * Note that i, f, d, and m only appear in floats. + */ + while (1) + { + size_t tmp2 = unc_toupper(ctx.peek()); + + if ( (tmp2 == 'I') + || (tmp2 == 'F') + || (tmp2 == 'D') + || (tmp2 == 'M')) + { + is_float = true; + } + else if ( (tmp2 != 'L') + && (tmp2 != 'U')) + { + break; + } + pc.Str().append(ctx.get()); + } + + // skip the Microsoft-specific '32' and '64' suffix + if ( ( (ctx.peek() == '3') + && (ctx.peek(1) == '2')) + || ( (ctx.peek() == '6') + && (ctx.peek(1) == '4'))) + { + pc.Str().append(ctx.get()); + pc.Str().append(ctx.get()); + } + pc.SetType(is_float ? CT_NUMBER_FP : CT_NUMBER); + + /* + * If there is anything left, then we are probably dealing with garbage or + * some sick macro junk. Eat it. + */ + parse_suffix(ctx, pc); + + return(true); +} // parse_number + + +static bool parse_string(tok_ctx &ctx, Chunk &pc, size_t quote_idx, bool allow_escape) +{ + log_rule_B("string_escape_char"); + const size_t escape_char = options::string_escape_char(); + + log_rule_B("string_escape_char2"); + const size_t escape_char2 = options::string_escape_char2(); + + log_rule_B("string_replace_tab_chars"); + const bool should_escape_tabs = ( allow_escape + && options::string_replace_tab_chars() + && language_is_set(LANG_ALLC)); + + pc.Str().clear(); + + while (quote_idx-- > 0) + { + pc.Str().append(ctx.get()); + } + pc.SetType(CT_STRING); + const size_t termination_character = CharTable::Get(ctx.peek()) & 0xff; + + pc.Str().append(ctx.get()); // store the " + + bool escaped = false; + + while (ctx.more()) + { + const size_t ch = ctx.get(); + + // convert char 9 (\t) to chars \t + if ( (ch == '\t') + && should_escape_tabs) + { + const size_t lastcol = ctx.c.col - 1; + ctx.c.col = lastcol + 2; + pc.Str().append(escape_char); + pc.Str().append('t'); + continue; + } + pc.Str().append(ch); + + if (ch == '\n') + { + pc.SetNlCount(pc.GetNlCount() + 1); + pc.SetType(CT_STRING_MULTI); + } + else if ( ch == '\r' + && ctx.peek() != '\n') + { + pc.Str().append(ctx.get()); + pc.SetNlCount(pc.GetNlCount() + 1); + pc.SetType(CT_STRING_MULTI); + } + + // if last char in prev loop was escaped the one in the current loop isn't + if (escaped) + { + escaped = false; + continue; + } + + // see if the current char is a escape char + if (allow_escape) + { + if (ch == escape_char) + { + escaped = (escape_char != 0); + continue; + } + + if ( ch == escape_char2 + && (ctx.peek() == termination_character)) + { + escaped = allow_escape; + continue; + } + } + + if (ch == termination_character) + { + break; + } + } + parse_suffix(ctx, pc, true); + return(true); +} // parse_string + +enum cs_string_t +{ + CS_STRING_NONE = 0, + CS_STRING_STRING = 1 << 0, // is any kind of string + CS_STRING_VERBATIM = 1 << 1, // @"" style string + CS_STRING_INTERPOLATED = 1 << 2, // $"" or $@"" style string +}; + +static cs_string_t operator|=(cs_string_t &value, cs_string_t other) +{ + return(value = static_cast<cs_string_t>(value | other)); +} + + +static cs_string_t parse_cs_string_start(tok_ctx &ctx, Chunk &pc) +{ + cs_string_t stringType = CS_STRING_NONE; + int offset = 0; + + if (ctx.peek(offset) == '$') + { + stringType |= CS_STRING_INTERPOLATED; + ++offset; + } + + if (ctx.peek(offset) == '@') + { + stringType |= CS_STRING_VERBATIM; + ++offset; + } + + if (ctx.peek(offset) == '"') + { + stringType |= CS_STRING_STRING; + + pc.SetType(CT_STRING); + + for (int i = 0; i <= offset; ++i) + { + pc.Str().append(ctx.get()); + } + } + else + { + stringType = CS_STRING_NONE; + } + return(stringType); +} // parse_cs_string_start + + +struct CsStringParseState +{ + cs_string_t type; + int braceDepth; + + + CsStringParseState(cs_string_t stringType) + { + type = stringType; + braceDepth = 0; + } +}; + + +/** + * C# strings are complex enough (mostly due to interpolation and nesting) that they need a custom parser. + */ +static bool parse_cs_string(tok_ctx &ctx, Chunk &pc) +{ + cs_string_t stringType = parse_cs_string_start(ctx, pc); + + if (stringType == 0) + { + return(false); + } + // an interpolated string can contain {expressions}, which can contain $"strings", which in turn + // can contain {expressions}, so we must track both as they are interleaved, in order to properly + // parse the outermost string. + + std::stack<CsStringParseState> parseState; // each entry is a nested string + + parseState.push(CsStringParseState(stringType)); + + log_rule_B("string_replace_tab_chars"); + bool should_escape_tabs = options::string_replace_tab_chars(); + + while (ctx.more()) + { + if (parseState.top().braceDepth > 0) + { + // all we can do when in an expr is look for expr close with }, or a new string opening. must do this first + // so we can peek and potentially consume chars for new string openings, before the ch=get() happens later, + // which is needed for newline processing. + + if (ctx.peek() == '}') + { + pc.Str().append(ctx.get()); + + if (ctx.peek() == '}') + { + pc.Str().append(ctx.get()); // in interpolated string, `}}` is escape'd `}` + } + else + { + --parseState.top().braceDepth; + } + continue; + } + stringType = parse_cs_string_start(ctx, pc); + + if (stringType) + { + parseState.push(CsStringParseState(stringType)); + continue; + } + } + int lastcol = ctx.c.col; + int ch = ctx.get(); + + pc.Str().append(ch); + + if (ch == '\n') + { + pc.SetType(CT_STRING_MULTI); + pc.SetNlCount(pc.GetNlCount() + 1); + } + else if (ch == '\r') + { + pc.SetType(CT_STRING_MULTI); + } + else if (parseState.top().braceDepth > 0) + { + // do nothing. if we're in a brace, we only want the newline handling, and skip the rest. + } + else if ( (ch == '\t') + && should_escape_tabs) + { + if (parseState.top().type & CS_STRING_VERBATIM) + { + if (!cpd.warned_unable_string_replace_tab_chars) + { + cpd.warned_unable_string_replace_tab_chars = true; + + log_rule_B("warn_level_tabs_found_in_verbatim_string_literals"); + log_sev_t warnlevel = (log_sev_t)options::warn_level_tabs_found_in_verbatim_string_literals(); + + /* + * a tab char can't be replaced with \\t because escapes don't + * work in here-strings. best we can do is warn. + */ + LOG_FMT(warnlevel, "%s(%d): %s: orig line is %zu, orig col is %zu, Detected non-replaceable tab char in literal string\n", + __func__, __LINE__, cpd.filename.c_str(), pc.GetOrigLine(), pc.GetOrigCol()); + LOG_FMT(warnlevel, "%s(%d): Warning is given if doing tab-to-\\t replacement and we have found one in a C# verbatim string literal.\n", + __func__, __LINE__); + + if (warnlevel < LWARN) + { + // TODO: replace the code ?? cpd.error_count++; + } + } + } + else + { + ctx.c.col = lastcol + 2; + pc.Str().pop_back(); // remove \t + pc.Str().append("\\t"); + + continue; + } + } + else if ( ch == '\\' + && !(parseState.top().type & CS_STRING_VERBATIM)) + { + // catch escaped quote in order to avoid ending string (but also must handle \\ to avoid accidental 'escape' seq of `\\"`) + if ( ctx.peek() == '"' + || ctx.peek() == '\\') + { + pc.Str().append(ctx.get()); + } + } + else if (ch == '"') + { + if ( (parseState.top().type & CS_STRING_VERBATIM) + && (ctx.peek() == '"')) + { + // in verbatim string, `""` is escape'd `"` + pc.Str().append(ctx.get()); + } + else + { + // end of string + parseState.pop(); + + if (parseState.empty()) + { + break; + } + } + } + else if (parseState.top().type & CS_STRING_INTERPOLATED) + { + if (ch == '{') + { + if (ctx.peek() == '{') + { + pc.Str().append(ctx.get()); // in interpolated string, `{{` is escape'd `{` + } + else + { + ++parseState.top().braceDepth; + } + } + } + } + return(true); +} // parse_cs_string + + +static void parse_verbatim_string(tok_ctx &ctx, Chunk &pc) +{ + pc.SetType(CT_STRING); + + // consume the initial """ + pc.Str() = ctx.get(); + pc.Str().append(ctx.get()); + pc.Str().append(ctx.get()); + + // go until we hit a zero (end of file) or a """ + while (ctx.more()) + { + size_t ch = ctx.get(); + pc.Str().append(ch); + + if ( (ch == '"') + && (ctx.peek() == '"') + && (ctx.peek(1) == '"')) + { + pc.Str().append(ctx.get()); + pc.Str().append(ctx.get()); + break; + } + + if ( (ch == '\n') + || (ch == '\r')) + { + pc.SetType(CT_STRING_MULTI); + pc.SetNlCount(pc.GetNlCount() + 1); + } + } +} + + +static bool tag_compare(const deque<int> &d, size_t a_idx, size_t b_idx, size_t len) +{ + if (a_idx != b_idx) + { + while (len-- > 0) + { + if (d[a_idx] != d[b_idx]) + { + return(false); + } + } + } + return(true); +} + + +static bool parse_cr_string(tok_ctx &ctx, Chunk &pc, size_t q_idx) +{ + size_t tag_idx = ctx.c.idx + q_idx + 1; + size_t tag_len = 0; + + ctx.save(); + + // Copy the prefix + " to the string + pc.Str().clear(); + int cnt = q_idx + 1; + + while (cnt--) + { + pc.Str().append(ctx.get()); + } + + // Add the tag and get the length of the tag + while ( ctx.more() + && (ctx.peek() != '(')) + { + tag_len++; + pc.Str().append(ctx.get()); + } + + if (ctx.peek() != '(') + { + ctx.restore(); + return(false); + } + pc.SetType(CT_STRING); + + while (ctx.more()) + { + if ( (ctx.peek() == ')') + && (ctx.peek(tag_len + 1) == '"') + && tag_compare(ctx.data, tag_idx, ctx.c.idx + 1, tag_len)) + { + cnt = tag_len + 2; // for the )" + + while (cnt--) + { + pc.Str().append(ctx.get()); + } + parse_suffix(ctx, pc); + return(true); + } + + if (ctx.peek() == '\n') + { + pc.Str().append(ctx.get()); + pc.SetNlCount(pc.GetNlCount() + 1); + pc.SetType(CT_STRING_MULTI); + } + else + { + pc.Str().append(ctx.get()); + } + } + ctx.restore(); + return(false); +} // parse_cr_string + + +/** + * Count the number of characters in a word. + * The first character is already valid for a keyword + * + * @param pc The structure to update, str is an input. + * @return Whether a word was parsed (always true) + */ +static bool parse_word(tok_ctx &ctx, Chunk &pc, bool skipcheck) +{ + static unc_text intr_txt("@interface"); + + // The first character is already valid + pc.Str().clear(); + pc.Str().append(ctx.get()); + + while (ctx.more()) + { + size_t ch = ctx.peek(); + + if (CharTable::IsKw2(ch)) + { + pc.Str().append(ctx.get()); + } + else if ( (ch == '\\') + && (unc_tolower(ctx.peek(1)) == 'u')) + { + pc.Str().append(ctx.get()); + pc.Str().append(ctx.get()); + skipcheck = true; + } + else + { + break; + } + + // HACK: Non-ASCII character are only allowed in identifiers + if (ch > 0x7f) + { + skipcheck = true; + } + } + pc.SetType(CT_WORD); + + if (skipcheck) + { + return(true); + } + + // Detect pre-processor functions now + if ( cpd.in_preproc == CT_PP_DEFINE + && cpd.preproc_ncnl_count == 1) + { + if (ctx.peek() == '(') + { + pc.SetType(CT_MACRO_FUNC); + } + else + { + pc.SetType(CT_MACRO); + + log_rule_B("pp_ignore_define_body"); + + if (options::pp_ignore_define_body()) + { + /* + * We are setting the PP_IGNORE preproc state because the following + * chunks are part of the macro body and will have to be ignored. + */ + cpd.in_preproc = CT_PP_IGNORE; + } + } + } + else + { + // '@interface' is reserved, not an interface itself + if ( language_is_set(LANG_JAVA) + && pc.GetStr().startswith("@") + && !pc.GetStr().equals(intr_txt)) + { + pc.SetType(CT_ANNOTATION); + } + else + { + // Turn it into a keyword now + // Issue #1460 will return "COMMENT_CPP" + pc.SetType(find_keyword_type(pc.Text(), pc.GetStr().size())); + + /* Special pattern: if we're trying to redirect a preprocessor directive to PP_IGNORE, + * then ensure we're actually part of a preprocessor before doing the swap, or we'll + * end up with a function named 'define' as PP_IGNORE. This is necessary because with + * the config 'set' feature, there's no way to do a pair of tokens as a word + * substitution. */ + if ( pc.GetType() == CT_PP_IGNORE + && !cpd.in_preproc) + { + pc.SetType(find_keyword_type(pc.Text(), pc.GetStr().size())); + } + else if (pc.GetType() == CT_COMMENT_CPP) // Issue #1460 + { + size_t ch; + bool is_cs = language_is_set(LANG_CS); + + // read until EOL + while (true) + { + int bs_cnt = 0; + + while (ctx.more()) + { + ch = ctx.peek(); + + if ( (ch == '\r') + || (ch == '\n')) + { + break; + } + + if ( (ch == '\\') + && !is_cs) // backslashes aren't special in comments in C# + { + bs_cnt++; + } + else + { + bs_cnt = 0; + } + pc.Str().append(ctx.get()); + } + + /* + * If we hit an odd number of backslashes right before the newline, + * then we keep going. + */ + if ( ((bs_cnt & 1) == 0) + || !ctx.more()) + { + break; + } + + if (ctx.peek() == '\r') + { + pc.Str().append(ctx.get()); + } + + if (ctx.peek() == '\n') + { + pc.Str().append(ctx.get()); + } + pc.SetNlCount(pc.GetNlCount() + 1); + cpd.did_newline = true; + } + // Store off the end column + pc.SetOrigColEnd(ctx.c.col); + } + } + } + return(true); +} // parse_word + + +static size_t parse_attribute_specifier_sequence(tok_ctx &ctx) +{ + size_t nested = 0; + size_t offset = 0; + size_t parens = 0; + auto ch1 = ctx.peek(offset++); + + while (ch1) + { + auto ch2 = ctx.peek(offset++); + + while ( ch2 == ' ' + || ch2 == '\n' + || ch2 == '\r' + || ch2 == '\t') + { + ch2 = ctx.peek(offset++); + } + + if ( nested == 0 + && ch2 != '[') + { + break; + } + + if (ch1 == '(') + { + ++parens; + ch1 = ch2; + continue; + } + + if (ch1 == ')') + { + if (parens == 0) + { + break; + } + --parens; + ch1 = ch2; + continue; + } + + if ( ch1 != '[' + && ch1 != ']') + { + ch1 = ch2; + continue; + } + + if (ch2 != ch1) + { + if (parens == 0) + { + break; + } + ch1 = ch2; + continue; + } + + if (ch1 == '[') + { + if ( nested != 0 + && parens == 0) + { + break; + } + ++nested; + } + else if (--nested == 0) + { + return(offset); + } + ch1 = ctx.peek(offset++); + } + return(0); +} // parse_attribute_specifier_sequence + + +static bool extract_attribute_specifier_sequence(tok_ctx &ctx, Chunk &pc, size_t length) +{ + pc.Str().clear(); + + while (length--) + { + pc.Str().append(ctx.get()); + } + pc.SetType(CT_ATTRIBUTE); + return(true); +} // extract_attribute_specifier_sequence + + +static bool parse_whitespace(tok_ctx &ctx, Chunk &pc) +{ + size_t nl_count = 0; + size_t ch = 0; + + // REVISIT: use a better whitespace detector? + while ( ctx.more() + && unc_isspace(ctx.peek())) + { + int lastcol = ctx.c.col; + ch = ctx.get(); // throw away the whitespace char + + switch (ch) + { + case '\r': + + if (ctx.expect('\n')) + { + // CRLF ending + ++LE_COUNT(CRLF); + } + else + { + // CR ending + ++LE_COUNT(CR); + } + nl_count++; + pc.SetOrigPrevSp(0); + break; + + case '\n': + // LF ending + ++LE_COUNT(LF); + nl_count++; + pc.SetOrigPrevSp(0); + break; + + case '\t': + pc.SetOrigPrevSp(pc.GetOrigPrevSp() + ctx.c.col - lastcol); + break; + + case ' ': + pc.SetOrigPrevSp(pc.GetOrigPrevSp() + 1); + break; + + default: + break; + } + } + + if (ch != 0) + { + pc.Str().clear(); + pc.SetType(nl_count ? CT_NEWLINE : CT_WHITESPACE); + pc.SetNlCount(nl_count); + pc.SetAfterTab((ctx.c.last_ch == '\t')); + return(true); + } + return(false); +} // parse_whitespace + + +static bool parse_bs_newline(tok_ctx &ctx, Chunk &pc) +{ + ctx.save(); + ctx.get(); // skip the '\' + + size_t ch; + + while ( ctx.more() + && unc_isspace(ch = ctx.peek())) + { + ctx.get(); + + if ( (ch == '\r') + || (ch == '\n')) + { + if (ch == '\r') + { + ctx.expect('\n'); + } + pc.SetType(CT_NL_CONT); + pc.Str() = "\\"; + pc.SetNlCount(1); + return(true); + } + } + ctx.restore(); + return(false); +} + + +static bool parse_newline(tok_ctx &ctx) +{ + ctx.save(); + + // Eat whitespace + while ( (ctx.peek() == ' ') + || (ctx.peek() == '\t')) + { + ctx.get(); + } + + if ( (ctx.peek() == '\r') + || (ctx.peek() == '\n')) + { + if (!ctx.expect('\n')) + { + ctx.get(); + ctx.expect('\n'); + } + return(true); + } + ctx.restore(); + return(false); +} + + +static void parse_pawn_pattern(tok_ctx &ctx, Chunk &pc, E_Token tt) +{ + pc.Str().clear(); + pc.SetType(tt); + + while (!unc_isspace(ctx.peek())) + { + // end the pattern on an escaped newline + if (ctx.peek() == '\\') + { + size_t ch = ctx.peek(1); + + if ( (ch == '\n') + || (ch == '\r')) + { + break; + } + } + pc.Str().append(ctx.get()); + } +} + + +static bool parse_off_newlines(tok_ctx &ctx, Chunk &pc) +{ + size_t nl_count = 0; + + // Parse off newlines/blank lines + while (parse_newline(ctx)) + { + nl_count++; + } + + if (nl_count > 0) + { + pc.SetNlCount(nl_count); + pc.SetType(CT_NEWLINE); + return(true); + } + return(false); +} + + +static bool parse_macro(tok_ctx &ctx, Chunk &pc, const Chunk *prev_pc) +{ + if (parse_off_newlines(ctx, pc)) + { + return(true); + } + + if (parse_comment(ctx, pc)) // allow CT_COMMENT_MULTI within macros + { + return(true); + } + ctx.save(); + pc.Str().clear(); + + if (prev_pc == nullptr) + { + return(false); + } + bool continued = ( prev_pc->Is(CT_NL_CONT) + || prev_pc->Is(CT_COMMENT_MULTI)); + + while (ctx.more()) + { + size_t pk = ctx.peek(), pk1 = ctx.peek(1); + bool nl = ( pk == '\n' + || pk == '\r'); + bool nl_cont = ( pk == '\\' + && ( pk1 == '\n' + || pk1 == '\r')); + + if ( ( nl_cont + || ( continued + && nl)) + && pc.GetStr().size() > 0) + { + pc.SetType(CT_PP_IGNORE); + return(true); + } + else if (nl) + { + break; + } + pc.Str().append(ctx.get()); + } + pc.Str().clear(); + ctx.restore(); + return(false); +} // parse_macro + + +static bool parse_ignored(tok_ctx &ctx, Chunk &pc) +{ + if (parse_off_newlines(ctx, pc)) + { + return(true); + } + // See if the UO_enable_processing_cmt or #pragma endasm / #endasm text is on this line + ctx.save(); + pc.Str().clear(); + + while ( ctx.more() + && (ctx.peek() != '\r') + && (ctx.peek() != '\n')) + { + pc.Str().append(ctx.get()); + } + + if (pc.GetStr().size() == 0) + { + // end of file? + return(false); + } + + // HACK: turn on if we find '#endasm' or '#pragma' and 'endasm' separated by blanks + if ( ( ( (pc.GetStr().find("#pragma ") >= 0) + || (pc.GetStr().find("#pragma ") >= 0)) + && ( (pc.GetStr().find(" endasm") >= 0) + || (pc.GetStr().find(" endasm") >= 0))) + || (pc.GetStr().find("#endasm") >= 0)) + { + cpd.unc_off = false; + ctx.restore(); + pc.Str().clear(); + return(false); + } + // Note that we aren't actually making sure this is in a comment, yet + log_rule_B("enable_processing_cmt"); + const auto &ontext = options::enable_processing_cmt(); + + if (!ontext.empty()) + { + bool found_enable_pattern = false; + + if ( ontext != UNCRUSTIFY_ON_TEXT + && options::processing_cmt_as_regex()) + { + std::wstring pc_wstring(pc.GetStr().get().cbegin(), + pc.GetStr().get().cend()); + std::wregex criteria(std::wstring(ontext.cbegin(), + ontext.cend())); + + found_enable_pattern = std::regex_search(pc_wstring.cbegin(), + pc_wstring.cend(), + criteria); + } + else + { + found_enable_pattern = (pc.GetStr().find(ontext.c_str()) >= 0); + } + + if (!found_enable_pattern) + { + pc.SetType(CT_IGNORED); + return(true); + } + } + ctx.restore(); + + // parse off whitespace leading to the comment + if (parse_whitespace(ctx, pc)) + { + pc.SetType(CT_IGNORED); + return(true); + } + + // Look for the ending comment and let it pass + if ( parse_comment(ctx, pc) + && !cpd.unc_off) + { + return(true); + } + // Reset the chunk & scan to until a newline + pc.Str().clear(); + + while ( ctx.more() + && (ctx.peek() != '\r') + && (ctx.peek() != '\n')) + { + pc.Str().append(ctx.get()); + } + + if (pc.GetStr().size() > 0) + { + pc.SetType(CT_IGNORED); + return(true); + } + return(false); +} // parse_ignored + + +static bool parse_next(tok_ctx &ctx, Chunk &pc, const Chunk *prev_pc) +{ + if (!ctx.more()) + { + return(false); + } + // Save off the current column + pc.SetType(CT_NONE); + pc.SetOrigLine(ctx.c.row); + pc.SetColumn(ctx.c.col); + pc.SetOrigCol(ctx.c.col); + pc.SetNlCount(0); + pc.SetFlags(PCF_NONE); + + // If it is turned off, we put everything except newlines into CT_UNKNOWN + if (cpd.unc_off) + { + if (parse_ignored(ctx, pc)) + { + return(true); + } + } + log_rule_B("disable_processing_nl_cont"); + + // Parse macro blocks + if (options::disable_processing_nl_cont()) + { + if (parse_macro(ctx, pc, prev_pc)) + { + return(true); + } + } + + // Parse whitespace + if (parse_whitespace(ctx, pc)) + { + return(true); + } + + // Handle unknown/unhandled preprocessors + if ( cpd.in_preproc > CT_PP_BODYCHUNK + && cpd.in_preproc <= CT_PP_OTHER) + { + pc.Str().clear(); + tok_info ss; + ctx.save(ss); + // Chunk to a newline or comment + pc.SetType(CT_PREPROC_BODY); + size_t last = 0; + + while (ctx.more()) + { + size_t ch = ctx.peek(); + + // Fix for issue #1752 + // Ignoring extra spaces after ' \ ' for preproc body continuations + if ( last == '\\' + && ch == ' ') + { + ctx.get(); + continue; + } + + if ( (ch == '\n') + || (ch == '\r')) + { + // Back off if this is an escaped newline + if (last == '\\') + { + ctx.restore(ss); + pc.Str().pop_back(); + } + break; + } + + // Quit on a C or C++ comment start Issue #1966 + if ( (ch == '/') + && ( (ctx.peek(1) == '/') + || (ctx.peek(1) == '*'))) + { + break; + } + last = ch; + ctx.save(ss); + + pc.Str().append(ctx.get()); + } + + if (pc.GetStr().size() > 0) + { + return(true); + } + } + + // Detect backslash-newline + if ( (ctx.peek() == '\\') + && parse_bs_newline(ctx, pc)) + { + return(true); + } + + // Parse comments + if (parse_comment(ctx, pc)) + { + return(true); + } + + // Parse code placeholders + if (parse_code_placeholder(ctx, pc)) + { + return(true); + } + + if (language_is_set(LANG_CS)) + { + if (parse_cs_string(ctx, pc)) + { + return(true); + } + } + + if (language_is_set(LANG_CS | LANG_VALA)) + { + // check for non-keyword identifiers such as @if @switch, etc + // Vala also allows numeric identifiers if prefixed with '@' + if ( ctx.peek() == '@' + && ( CharTable::IsKw1(ctx.peek(1)) + || ( language_is_set(LANG_VALA) + && CharTable::IsKw2(ctx.peek(1))))) + { + parse_word(ctx, pc, true); + return(true); + } + } + + // handle VALA """ strings """ + if ( language_is_set(LANG_VALA) + && (ctx.peek() == '"') + && (ctx.peek(1) == '"') + && (ctx.peek(2) == '"')) + { + parse_verbatim_string(ctx, pc); + return(true); + } + /* + * handle C++(11) string/char literal prefixes u8|u|U|L|R including all + * possible combinations and optional R delimiters: R"delim(x)delim" + */ + auto ch = ctx.peek(); + + if ( language_is_set(LANG_C | LANG_CPP) + && ( ch == 'u' + || ch == 'U' + || ch == 'R' + || ch == 'L')) + { + auto idx = size_t{}; + auto is_real = false; + + if ( ch == 'u' + && ctx.peek(1) == '8') + { + idx = 2; + } + else if ( unc_tolower(ch) == 'u' + || ch == 'L') + { + idx++; + } + + if ( language_is_set(LANG_C | LANG_CPP) + && ctx.peek(idx) == 'R') + { + idx++; + is_real = true; + } + const auto quote = ctx.peek(idx); + + if (is_real) + { + if ( quote == '"' + && parse_cr_string(ctx, pc, idx)) + { + return(true); + } + } + else if ( ( quote == '"' + || quote == '\'') + && parse_string(ctx, pc, idx, true)) + { + return(true); + } + } + + // PAWN specific stuff + if (language_is_set(LANG_PAWN)) + { + if ( cpd.preproc_ncnl_count == 1 + && ( cpd.in_preproc == CT_PP_DEFINE + || cpd.in_preproc == CT_PP_EMIT)) + { + parse_pawn_pattern(ctx, pc, CT_MACRO); + return(true); + } + + // Check for PAWN strings: \"hi" or !"hi" or !\"hi" or \!"hi" + if ( (ctx.peek() == '\\') + || (ctx.peek() == '!')) + { + if (ctx.peek(1) == '"') + { + parse_string(ctx, pc, 1, (ctx.peek() == '!')); + return(true); + } + + if ( ( (ctx.peek(1) == '\\') + || (ctx.peek(1) == '!')) + && (ctx.peek(2) == '"')) + { + parse_string(ctx, pc, 2, false); + return(true); + } + } + + // handle PAWN preprocessor args %0 .. %9 + if ( cpd.in_preproc == CT_PP_DEFINE + && (ctx.peek() == '%') + && unc_isdigit(ctx.peek(1))) + { + pc.Str().clear(); + pc.Str().append(ctx.get()); + pc.Str().append(ctx.get()); + pc.SetType(CT_WORD); + return(true); + } + } + // Parse strings and character constants + +//parse_word(ctx, pc_temp, true); +//ctx.restore(ctx.c); + if (parse_number(ctx, pc)) + { + return(true); + } + + if (language_is_set(LANG_D)) + { + // D specific stuff + if (d_parse_string(ctx, pc)) + { + return(true); + } + } + else + { + // Not D stuff + + // Check for L'a', L"abc", 'a', "abc", <abc> strings + ch = ctx.peek(); + size_t ch1 = ctx.peek(1); + + if ( ( ( (ch == 'L') + || (ch == 'S')) + && ( (ch1 == '"') + || (ch1 == '\''))) + || (ch == '"') + || (ch == '\'') + || ( (ch == '<') + && cpd.in_preproc == CT_PP_INCLUDE)) + { + parse_string(ctx, pc, unc_isalpha(ch) ? 1 : 0, true); + + if (cpd.in_preproc == CT_PP_INCLUDE) + { + pc.SetParentType(CT_PP_INCLUDE); + } + return(true); + } + + if ( (ch == '<') + && cpd.in_preproc == CT_PP_DEFINE) + { + if (Chunk::GetTail()->Is(CT_MACRO)) + { + // We have "#define XXX <", assume '<' starts an include string + parse_string(ctx, pc, 0, false); + return(true); + } + } + /* Inside clang's __has_include() could be "path/to/file.h" or system-style <path/to/file.h> */ + Chunk *tail = Chunk::GetTail(); + + if ( (ch == '(') + && (tail->IsNotNullChunk()) + && ( tail->Is(CT_CNG_HASINC) + || tail->Is(CT_CNG_HASINCN))) + { + parse_string(ctx, pc, 0, false); + return(true); + } + } + + // Check for Vala string templates + if ( language_is_set(LANG_VALA) + && (ctx.peek() == '@')) + { + size_t nc = ctx.peek(1); + + if (nc == '"') + { + // literal string + parse_string(ctx, pc, 1, true); + return(true); + } + } + + // Check for Objective C literals + if ( language_is_set(LANG_OC) + && (ctx.peek() == '@')) + { + size_t nc = ctx.peek(1); + + if (nc == 'R') // Issue #2720 + { + if (ctx.peek(2) == '"') + { + if (parse_cr_string(ctx, pc, 2)) // Issue #3027 + { + return(true); + } + // parse string without escaping + parse_string(ctx, pc, 2, false); + return(true); + } + } + + if ( (nc == '"') + || (nc == '\'')) + { + // literal string + parse_string(ctx, pc, 1, true); + return(true); + } + + if ( (nc >= '0') + && (nc <= '9')) + { + // literal number + pc.Str().append(ctx.get()); // store the '@' + parse_number(ctx, pc); + return(true); + } + } + + // Check for pawn/ObjectiveC/Java and normal identifiers + if ( CharTable::IsKw1(ctx.peek()) + || ( (ctx.peek() == '\\') + && (unc_tolower(ctx.peek(1)) == 'u')) + || ( (ctx.peek() == '@') + && CharTable::IsKw1(ctx.peek(1)))) + { + parse_word(ctx, pc, false); + return(true); + } + + // Check for C++11/14/17/20 attribute specifier sequences + if ( language_is_set(LANG_CPP) + && ctx.peek() == '[') + { + if ( !language_is_set(LANG_OC) + || ( prev_pc != nullptr + && !prev_pc->Is(CT_OC_AT))) + { + if (auto length = parse_attribute_specifier_sequence(ctx)) + { + extract_attribute_specifier_sequence(ctx, pc, length); + return(true); + } + } + } + // see if we have a punctuator + char punc_txt[7]; + + punc_txt[0] = ctx.peek(); + punc_txt[1] = ctx.peek(1); + punc_txt[2] = ctx.peek(2); + punc_txt[3] = ctx.peek(3); + punc_txt[4] = ctx.peek(4); + punc_txt[5] = ctx.peek(5); + punc_txt[6] = '\0'; + const chunk_tag_t *punc; + + if ((punc = find_punctuator(punc_txt, cpd.lang_flags)) != nullptr) + { + int cnt = strlen(punc->tag); + + while (cnt--) + { + pc.Str().append(ctx.get()); + } + pc.SetType(punc->type); + pc.SetFlagBits(PCF_PUNCTUATOR); + return(true); + } + /* When parsing C/C++ files and running into some unknown token, + * check if matches Objective-C as a last resort, before + * considering it as garbage. + */ + int probe_lang_flags = 0; + + if (language_is_set(LANG_C | LANG_CPP)) + { + probe_lang_flags = cpd.lang_flags | LANG_OC; + } + + if (probe_lang_flags != 0) + { + if ((punc = find_punctuator(punc_txt, probe_lang_flags)) != nullptr) + { + cpd.lang_flags = probe_lang_flags; + int cnt = strlen(punc->tag); + + while (cnt--) + { + pc.Str().append(ctx.get()); + } + pc.SetType(punc->type); + pc.SetFlagBits(PCF_PUNCTUATOR); + return(true); + } + } + // throw away this character + pc.SetType(CT_UNKNOWN); + pc.Str().append(ctx.get()); + + LOG_FMT(LWARN, "%s:%zu Garbage in col %zu: %x\n", + cpd.filename.c_str(), pc.GetOrigLine(), ctx.c.col, pc.GetStr()[0]); + exit(EX_SOFTWARE); +} // parse_next + + +int find_disable_processing_comment_marker(const unc_text &text, + std::size_t start_idx) +{ + log_rule_B("disable_processing_cmt"); + const auto &offtext = options::disable_processing_cmt(); + int idx = -1; + + if ( !offtext.empty() + && start_idx < text.size()) + { + if ( offtext != UNCRUSTIFY_OFF_TEXT + && options::processing_cmt_as_regex()) + { + std::wsmatch match; + std::wstring pc_wstring(text.get().cbegin() + start_idx, + text.get().cend()); + std::wregex criteria(std::wstring(offtext.cbegin(), + offtext.cend())); + + std::regex_search(pc_wstring.cbegin(), + pc_wstring.cend(), + match, + criteria); + + if (!match.empty()) + { + idx = int(match.position() + start_idx); + } + } + else + { + idx = text.find(offtext.c_str(), + start_idx); + + if (idx >= 0) + { + idx += int(offtext.size()); + } + } + + /** + * update the position to the start of the current line + */ + while ( idx > 0 + && text[idx - 1] != '\n') + { + --idx; + } + } + return(idx); +} // find_disable_processing_comment_marker + + +int find_enable_processing_comment_marker(const unc_text &text, + std::size_t start_idx) +{ + log_rule_B("enable_processing_cmt"); + const auto &ontext = options::enable_processing_cmt(); + int idx = -1; + + if ( !ontext.empty() + && start_idx < text.size()) + { + if ( ontext != UNCRUSTIFY_ON_TEXT + && options::processing_cmt_as_regex()) + { + std::wsmatch match; + std::wstring pc_wstring(text.get().cbegin() + start_idx, + text.get().cend()); + std::wregex criteria(std::wstring(ontext.cbegin(), + ontext.cend())); + + std::regex_search(pc_wstring.cbegin(), + pc_wstring.cend(), + match, + criteria); + + if (!match.empty()) + { + idx = int(start_idx + match.position() + match.size()); + } + } + else + { + idx = text.find(ontext.c_str(), + start_idx); + + if (idx >= 0) + { + idx += int(ontext.size()); + } + } + + /** + * update the position to the end of the current line + */ + if (idx >= 0) + { + while ( idx < int(text.size()) + && text[idx] != '\n') + { + ++idx; + } + } + } + return(idx); +} // find_enable_processing_comment_marker + + +void tokenize(const deque<int> &data, Chunk *ref) +{ + tok_ctx ctx(data); + Chunk chunk; + Chunk *pc = nullptr; + Chunk *rprev = nullptr; + bool last_was_tab = false; + size_t prev_sp = 0; + int num_stripped = 0; // Issue #1966 + + cpd.unc_stage = unc_stage_e::TOKENIZE; + + while (ctx.more()) + { + chunk.Reset(); + chunk.SetPpLevel(0); + + if (!parse_next(ctx, chunk, pc)) + { + LOG_FMT(LERR, "%s:%zu Bailed before the end?\n", + cpd.filename.c_str(), ctx.c.row); + exit(EX_SOFTWARE); + } + + if ( language_is_set(LANG_JAVA) + && chunk.GetType() == CT_MEMBER + && !memcmp(chunk.Text(), "->", 2)) + { + chunk.SetType(CT_LAMBDA); + } + + // Don't create an entry for whitespace + if (chunk.GetType() == CT_WHITESPACE) + { + last_was_tab = chunk.GetAfterTab(); + prev_sp = chunk.GetOrigPrevSp(); + continue; + } + chunk.SetOrigPrevSp(prev_sp); + prev_sp = 0; + + if (chunk.GetType() == CT_NEWLINE) + { + last_was_tab = chunk.GetAfterTab(); + chunk.SetAfterTab(false); + chunk.Str().clear(); + } + else if (chunk.GetType() == CT_NL_CONT) + { + last_was_tab = chunk.GetAfterTab(); + chunk.SetAfterTab(false); + chunk.Str() = "\\\n"; + } + else + { + chunk.SetAfterTab(last_was_tab); + last_was_tab = false; + } + num_stripped = 0; // Issue #1966 and #3565 + + if (chunk.GetType() != CT_IGNORED) + { + // Issue #1338 + // Strip trailing whitespace (for CPP comments and PP blocks) + while ( (chunk.GetStr().size() > 0) + && ( (chunk.GetStr()[chunk.GetStr().size() - 1] == ' ') + || (chunk.GetStr()[chunk.GetStr().size() - 1] == '\t'))) + { + // If comment contains backslash '\' followed by whitespace chars, keep last one; + // this will prevent it from turning '\' into line continuation. + if ( (chunk.GetStr().size() > 1) + && (chunk.GetStr()[chunk.GetStr().size() - 2] == '\\')) + { + break; + } + chunk.Str().pop_back(); + num_stripped++; // Issue #1966 + } + } + // Store off the end column + chunk.SetOrigColEnd(ctx.c.col - num_stripped); // Issue #1966 and #3565 + + // Make the whitespace we disposed of be attributed to the next chunk + prev_sp = num_stripped; + + // Add the chunk to the list + rprev = pc; + + if (rprev != nullptr) + { + pc->SetFlagBits(rprev->GetFlags() & PCF_COPY_FLAGS); + + // a newline can't be in a preprocessor + if (pc->Is(CT_NEWLINE)) + { + pc->ResetFlagBits(PCF_IN_PREPROC); + } + } + + if (ref != nullptr) + { + chunk.SetFlagBits(PCF_INSERTED); + } + else + { + chunk.ResetFlagBits(PCF_INSERTED); + } + pc = chunk.CopyAndAddBefore(ref); + + // A newline marks the end of a preprocessor + if (pc->Is(CT_NEWLINE)) // || pc->Is(CT_COMMENT_MULTI)) + { + cpd.in_preproc = CT_NONE; + cpd.preproc_ncnl_count = 0; + } + + // Disable indentation when #asm directive found + if (pc->Is(CT_PP_ASM)) + { + LOG_FMT(LBCTRL, "Found a directive %s on line %zu\n", "#asm", pc->GetOrigLine()); + cpd.unc_off = true; + } + + // Special handling for preprocessor stuff + if (cpd.in_preproc != CT_NONE) + { + pc->SetFlagBits(PCF_IN_PREPROC); + + // Count words after the preprocessor + if (!pc->IsCommentOrNewline()) + { + cpd.preproc_ncnl_count++; + } + + // Disable indentation if a #pragma asm directive is found + if (cpd.in_preproc == CT_PP_PRAGMA) + { + if (memcmp(pc->Text(), "asm", 3) == 0) + { + LOG_FMT(LBCTRL, "Found a pragma %s on line %zu\n", "asm", pc->GetOrigLine()); + cpd.unc_off = true; + } + } + + // Figure out the type of preprocessor for #include parsing + if (cpd.in_preproc == CT_PREPROC) + { + if ( pc->GetType() < CT_PP_DEFINE + || pc->GetType() > CT_PP_OTHER) + { + pc->SetType(CT_PP_OTHER); + } + cpd.in_preproc = pc->GetType(); + } + else if (cpd.in_preproc == CT_PP_IGNORE) + { + if ( !pc->Is(CT_NL_CONT) + && !pc->IsComment()) // Issue #1966 + { + pc->SetType(CT_PP_IGNORE); + } + } + else if ( cpd.in_preproc == CT_PP_DEFINE + && pc->Is(CT_PAREN_CLOSE) + && options::pp_ignore_define_body()) + { + log_rule_B("pp_ignore_define_body"); + // When we have a PAREN_CLOSE in a PP_DEFINE we should be terminating a MACRO_FUNC + // arguments list. Therefore we can enter the PP_IGNORE state and ignore next chunks. + cpd.in_preproc = CT_PP_IGNORE; + } + } + else + { + // Check for a preprocessor start + if ( pc->Is(CT_POUND) + && ( rprev == nullptr + || rprev->Is(CT_NEWLINE))) + { + pc->SetType(CT_PREPROC); + pc->SetFlagBits(PCF_IN_PREPROC); + cpd.in_preproc = CT_PREPROC; + } + } + + if (pc->Is(CT_NEWLINE)) + { + LOG_FMT(LGUY, "%s(%d): orig line is %zu, orig col is %zu, <Newline>, nl is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->GetNlCount()); + } + else if (pc->Is(CT_VBRACE_OPEN)) + { + LOG_FMT(LGUY, "%s(%d): orig line is %zu, orig col is %zu, type is %s, orig col end is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), get_token_name(pc->GetType()), pc->GetOrigColEnd()); + } + else + { + char copy[1000]; + LOG_FMT(LGUY, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s', type is %s, orig col end is %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->ElidedText(copy), get_token_name(pc->GetType()), pc->GetOrigColEnd()); + } + } + // Set the cpd.newline string for this file + log_rule_B("newlines"); + + if ( options::newlines() == LE_LF + || ( options::newlines() == LE_AUTO + && (LE_COUNT(LF) >= LE_COUNT(CRLF)) + && (LE_COUNT(LF) >= LE_COUNT(CR)))) + { + // LF line ends + cpd.newline = "\n"; + LOG_FMT(LLINEENDS, "Using LF line endings\n"); + } + else if ( options::newlines() == LE_CRLF + || ( options::newlines() == LE_AUTO + && (LE_COUNT(CRLF) >= LE_COUNT(LF)) + && (LE_COUNT(CRLF) >= LE_COUNT(CR)))) + { + // CRLF line ends + cpd.newline = "\r\n"; + LOG_FMT(LLINEENDS, "Using CRLF line endings\r\n"); + } + else + { + // CR line ends + cpd.newline = "\r"; + LOG_FMT(LLINEENDS, "Using CR line endings\n"); + } +} // tokenize diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/tokenize.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/tokenize.h new file mode 100644 index 00000000..a111143b --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/tokenize.h @@ -0,0 +1,55 @@ +/** + * @file tokenize.h + * prototypes for tokenize.c + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef TOKENIZE_H_INCLUDED +#define TOKENIZE_H_INCLUDED + +#include "uncrustify_types.h" + + +/** + * Test the input string to see if it satisfies the criteria + * specified by the disable_processing_cmt option + * @param text the string to which a match will be attempted + * @param start_idx the starting index within the string from which the + * search will be performed + * @return returns a non-negative position index that points to the beginning + * of the line containing the marker, if found + */ +int find_disable_processing_comment_marker(const unc_text &text, std::size_t start_idx = 0); + + +/** + * Test the input string to see if it satisfies the criteria + * specified by the enable_processing_cmt option + * @param text the string to which a match will be attempted + * @param start_idx the starting index within the string from which the + * search will be performed + * @return returns a non-negative position index that points to the end + * of the line containing the marker, if found + */ +int find_enable_processing_comment_marker(const unc_text &text, std::size_t start_idx = 0); + + +/** + * @brief Parse the text into chunks + * + * This function parses or tokenizes the whole buffer into a list. + * It has to do some tricks to parse preprocessors. + * + * If output_text() were called immediately after, two things would happen: + * - trailing whitespace are removed. + * - leading space & tabs are converted to the appropriate format. + * + * All the tokens are inserted before ref. If ref is NULL, they are inserted + * at the end of the list. Line numbers are relative to the start of the data. + */ +void tokenize(const std::deque<int> &data, Chunk *ref); + + +#endif /* TOKENIZE_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/tokenize_cleanup.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/tokenize_cleanup.cpp new file mode 100644 index 00000000..4a8e6773 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/tokenize_cleanup.cpp @@ -0,0 +1,1776 @@ +/** + * @file tokenize_cleanup.cpp + * Looks at simple sequences to refine the chunk types. + * Examples: + * - change '[' + ']' into '[]'/ + * - detect "version = 10;" vs "version (xxx) {" + * + * @author Ben Gardner + * @author Guy Maurel 2015, 2021 + * @license GPL v2+ + */ + +#include "tokenize_cleanup.h" + +#include "combine.h" +#include "combine_skip.h" +#include "flag_braced_init_list.h" +#include "flag_decltype.h" +#include "keywords.h" +#include "prototypes.h" +#include "punctuators.h" +#include "space.h" +#include "unc_ctype.h" + + +using namespace uncrustify; + + +/** + * Mark types in a single template argument. + * + * @param start chunk to start check at + * @param end chunk to end check at + */ +static void check_template_arg(Chunk *start, Chunk *end); + + +/** + * Mark types in template argument(s). + * + * @param start chunk to start check at + * @param end chunk to end check at + */ +static void check_template_args(Chunk *start, Chunk *end); + + +/** + * If there is nothing but CT_WORD and CT_MEMBER, then it's probably a + * template thingy. Otherwise, it's likely a comparison. + * + * @param start chunk to start check at + */ +static void check_template(Chunk *start, bool in_type_cast); + + +/** + * Convert '>' + '>' into '>>' + * If we only have a single '>', then change it to CT_COMPARE. + * + * @param pc chunk to start at + */ +static Chunk *handle_double_angle_close(Chunk *pc); + + +/** + * Marks ObjC specific chunks in property declaration, by setting + * parent types and chunk types. + */ +static void cleanup_objc_property(Chunk *start); + + +/** + * Marks ObjC specific chunks in property declaration (getter/setter attribute) + * Will mark 'test4Setter'and ':' in '@property (setter=test4Setter:, strong) int test4;' as CT_OC_SEL_NAME + */ +static void mark_selectors_in_property_with_open_paren(Chunk *open_paren); + + +/** + * Marks ObjC specific chunks in property declaration ( attributes) + * Changes all the CT_WORD and CT_TYPE to CT_OC_PROPERTY_ATTR + */ +static void mark_attributes_in_property_with_open_paren(Chunk *open_paren); + + +static Chunk *handle_double_angle_close(Chunk *pc) +{ + if (pc == nullptr) + { + pc = Chunk::NullChunkPtr; + } + 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 split_off_angle_close(Chunk *pc) +{ + const chunk_tag_t *ct = find_punctuator(pc->Text() + 1, cpd.lang_flags); + + if (ct == nullptr) + { + return; + } + Chunk nc = *pc; + + pc->Str().resize(1); + pc->SetOrigColEnd(pc->GetOrigCol() + 1); + pc->SetType(CT_ANGLE_CLOSE); + + nc.SetType(ct->type); + nc.Str().pop_front(); + nc.SetOrigCol(nc.GetOrigCol() + 1); + nc.SetColumn(nc.GetColumn() + 1); + nc.CopyAndAddAfter(pc); +} + + +void tokenize_trailing_return_types() +{ + // Issue #2330 + // auto max(int a, int b) -> int; + // Issue #2460 + // auto f01() -> bool; + // auto f02() noexcept -> bool; + // auto f03() noexcept(true) -> bool; + // auto f04() noexcept(false) -> bool; + // auto f05() noexcept -> bool = delete; + // auto f06() noexcept(true) -> bool = delete; + // auto f07() noexcept(false) -> bool = delete; + // auto f11() const -> bool; + // auto f12() const noexcept -> bool; + // auto f13() const noexcept(true) -> bool; + // auto f14() const noexcept(false) -> bool; + // auto f15() const noexcept -> bool = delete; + // auto f16() const noexcept(true) -> bool = delete; + // auto f17() const noexcept(false) -> bool = delete; + // auto f21() throw() -> bool; + // auto f22() throw() -> bool = delete; + // auto f23() const throw() -> bool; + // auto f24() const throw() -> bool = delete; + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + char copy[1000]; + LOG_FMT(LNOTE, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->ElidedText(copy)); + + if ( pc->Is(CT_MEMBER) + && (strcmp(pc->Text(), "->") == 0)) + { + Chunk *tmp = pc->GetPrevNcNnl(); + Chunk *tmp_2; + Chunk *open_paren; + + if (tmp->Is(CT_QUALIFIER)) + { + // auto max(int a, int b) const -> int; + // auto f11() const -> bool; + tmp = tmp->GetPrevNcNnl(); + } + else if (tmp->Is(CT_NOEXCEPT)) + { + // noexcept is present + tmp_2 = tmp->GetPrevNcNnl(); + + if (tmp_2->Is(CT_QUALIFIER)) + { + // auto f12() const noexcept -> bool; + // auto f15() const noexcept -> bool = delete; + tmp = tmp_2->GetPrevNcNnl(); + } + else + { + // auto f02() noexcept -> bool; + // auto f05() noexcept -> bool = delete; + tmp = tmp_2; + } + } + else if (tmp->Is(CT_PAREN_CLOSE)) + { + open_paren = tmp->GetPrevType(CT_PAREN_OPEN, tmp->GetLevel()); + tmp = open_paren->GetPrevNcNnl(); + + if (tmp->Is(CT_NOEXCEPT)) + { + // noexcept is present + tmp_2 = tmp->GetPrevNcNnl(); + + if (tmp_2->Is(CT_QUALIFIER)) + { + // auto f13() const noexcept(true) -> bool; + // auto f14() const noexcept(false) -> bool; + // auto f16() const noexcept(true) -> bool = delete; + // auto f17() const noexcept(false) -> bool = delete; + tmp = tmp_2->GetPrevNcNnl(); + } + else + { + // auto f03() noexcept(true) -> bool; + // auto f04() noexcept(false) -> bool; + // auto f06() noexcept(true) -> bool = delete; + // auto f07() noexcept(false) -> bool = delete; + tmp = tmp_2; + } + } + else if (tmp->Is(CT_THROW)) + { + // throw is present + tmp_2 = tmp->GetPrevNcNnl(); + + if (tmp_2->Is(CT_QUALIFIER)) + { + // auto f23() const throw() -> bool; + // auto f24() const throw() -> bool = delete; + tmp = tmp_2->GetPrevNcNnl(); + } + else + { + // auto f21() throw() -> bool; + // auto f22() throw() -> bool = delete; + tmp = tmp_2; + } + } + else + { + LOG_FMT(LNOTE, "%s(%d): NOT COVERED\n", __func__, __LINE__); + } + } + else + { + LOG_FMT(LNOTE, "%s(%d): NOT COVERED\n", __func__, __LINE__); + } + + if ( tmp->Is(CT_FPAREN_CLOSE) + && ( tmp->GetParentType() == CT_FUNC_PROTO + || tmp->GetParentType() == CT_FUNC_DEF)) + { + pc->SetType(CT_TRAILING_RET); + LOG_FMT(LNOTE, "%s(%d): set trailing return type for Text() is '%s'\n", + __func__, __LINE__, pc->Text()); // Issue #3222 + // TODO + // https://en.cppreference.com/w/cpp/language/function + // noptr-declarator ( parameter-list ) cv(optional) ref(optional) except(optional) attr(optional) -> trailing + Chunk *next = pc->GetNextNcNnl(); + + if (next->Is(CT_DECLTYPE)) + { + // TODO + } + else if (next->Is(CT_WORD)) + { + next->SetType(CT_TYPE); // Issue #3222 + next = next->GetNextNcNnl(); + + if (next->Is(CT_ARITH)) + { + if (next->GetStr()[0] == '*') + { + next->SetType(CT_PTR_TYPE); + } + else if (next->GetStr()[0] == '&') // Issue #3407 + { + next->SetType(CT_BYREF); + } + } + } + else + { + // TODO + } + } + } + } +} // tokenize_trailing_return_types + + +void tokenize_cleanup() +{ + LOG_FUNC_ENTRY(); + + Chunk *prev = Chunk::NullChunkPtr; + Chunk *next; + bool in_type_cast = false; + + cpd.unc_stage = unc_stage_e::TOKENIZE_CLEANUP; + + /* + * Since [] is expected to be TSQUARE for the 'operator', we need to make + * this change in the first pass. + */ + Chunk *pc; + + for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + if (pc->Is(CT_SQUARE_OPEN)) + { + next = pc->GetNextNcNnl(); + + if (next->Is(CT_SQUARE_CLOSE)) + { + // Change '[' + ']' into '[]' + pc->SetType(CT_TSQUARE); + pc->Str() = "[]"; + /* + * bug #664: The original m_origColEnd of CT_SQUARE_CLOSE is + * stored at m_origColEnd of CT_TSQUARE. + * pc->SetOrigColEnd(pc->GetOrigColEnd() + 1); + */ + pc->SetOrigColEnd(next->GetOrigColEnd()); + Chunk::Delete(next); + } + } + + if ( pc->Is(CT_SEMICOLON) + && pc->TestFlags(PCF_IN_PREPROC) + && !pc->GetNextNcNnl(E_Scope::PREPROC)) + { + LOG_FMT(LNOTE, "%s(%d): %s:%zu Detected a macro that ends with a semicolon. Possible failures if used.\n", + __func__, __LINE__, cpd.filename.c_str(), pc->GetOrigLine()); + } + } + + // change := to CT_SQL_ASSIGN Issue #527 + for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl()) + { + if (pc->Is(CT_COLON)) + { + next = pc->GetNextNcNnl(); + + if (next->Is(CT_ASSIGN)) + { + // Change ':' + '=' into ':=' + pc->SetType(CT_SQL_ASSIGN); + pc->Str() = ":="; + pc->SetOrigColEnd(next->GetOrigColEnd()); + Chunk::Delete(next); + } + } + } + + // We can handle everything else in the second pass + pc = Chunk::GetHead(); + next = pc->GetNextNcNnl(); + + while ( pc->IsNotNullChunk() + && next->IsNotNullChunk()) + { + if ( pc->Is(CT_DOT) + && language_is_set(LANG_ALLC)) + { + pc->SetType(CT_MEMBER); + } + + if ( pc->Is(CT_NULLCOND) + && language_is_set(LANG_CS)) + { + pc->SetType(CT_MEMBER); + } + + // Determine the version stuff (D only) + if (pc->Is(CT_D_VERSION)) + { + if (next->Is(CT_PAREN_OPEN)) + { + pc->SetType(CT_D_VERSION_IF); + } + else + { + if (next->IsNot(CT_ASSIGN)) + { + LOG_FMT(LERR, "%s(%d): %s:%zu: version: Unexpected token %s\n", + __func__, __LINE__, cpd.filename.c_str(), pc->GetOrigLine(), get_token_name(next->GetType())); + exit(EX_SOFTWARE); + } + pc->SetType(CT_WORD); + } + } + + // Determine the scope stuff (D only) + if (pc->Is(CT_D_SCOPE)) + { + if (next->Is(CT_PAREN_OPEN)) + { + pc->SetType(CT_D_SCOPE_IF); + } + else + { + pc->SetType(CT_TYPE); + } + } + + /* + * Change CT_BASE before CT_PAREN_OPEN to CT_WORD. + * public myclass() : base() {} + * -or- + * var x = (T)base.y; + */ + if ( pc->Is(CT_BASE) + && ( next->Is(CT_PAREN_OPEN) + || next->Is(CT_DOT))) + { + pc->SetType(CT_WORD); + } + + if ( pc->Is(CT_ENUM) + && ( next->Is(CT_STRUCT) + || next->Is(CT_CLASS))) + { + next->SetType(CT_ENUM_CLASS); + } + Chunk *next_non_attr = language_is_set(LANG_CPP) ? skip_attribute_next(next) : next; + + /* + * Change CT_WORD after CT_ENUM, CT_UNION, CT_STRUCT, or CT_CLASS to CT_TYPE + * Change CT_WORD before CT_WORD to CT_TYPE + */ + if (next_non_attr->Is(CT_WORD)) + { + if (pc->IsClassEnumStructOrUnion()) + { + next_non_attr->SetType(CT_TYPE); + } + + if (pc->Is(CT_WORD)) + { + pc->SetType(CT_TYPE); + } + } + + /* + * change extern to qualifier if extern isn't followed by a string or + * an open parenthesis + */ + if (pc->Is(CT_EXTERN)) + { + if (next->Is(CT_STRING)) + { + // Probably 'extern "C"' + } + else if (next->Is(CT_PAREN_OPEN)) + { + // Probably 'extern (C)' + } + else + { + // Something else followed by a open brace + Chunk *tmp = next->GetNextNcNnl(); + + if ( tmp->IsNullChunk() + || tmp->IsNot(CT_BRACE_OPEN)) + { + pc->SetType(CT_QUALIFIER); + } + } + } + + /* + * Change CT_STAR to CT_PTR_TYPE if preceded by + * CT_TYPE, CT_QUALIFIER, or CT_PTR_TYPE + * or by a + * CT_WORD which is preceded by CT_DC_MEMBER: '::aaa *b' + */ + if ( (next->Is(CT_STAR)) + || ( language_is_set(LANG_CPP) + && (next->Is(CT_CARET))) + || ( language_is_set(LANG_CS | LANG_VALA) + && (next->Is(CT_QUESTION)) + && (strcmp(pc->Text(), "null") != 0))) + { + if ( pc->Is(CT_TYPE) + || pc->Is(CT_QUALIFIER) + || pc->Is(CT_PTR_TYPE)) + { + next->SetType(CT_PTR_TYPE); + } + } + + if ( pc->Is(CT_TYPE_CAST) + && next->Is(CT_ANGLE_OPEN)) + { + next->SetParentType(CT_TYPE_CAST); + in_type_cast = true; + } + + if (pc->Is(CT_DECLTYPE)) + { + flag_cpp_decltype(pc); + } + + // Change angle open/close to CT_COMPARE, if not a template thingy + if ( pc->Is(CT_ANGLE_OPEN) + && pc->GetParentType() != CT_TYPE_CAST) + { + /* + * pretty much all languages except C use <> for something other than + * comparisons. "#include<xxx>" is handled elsewhere. + */ + if (language_is_set(LANG_OC | LANG_CPP | LANG_CS | LANG_JAVA | LANG_VALA)) + { + // bug #663 + check_template(pc, in_type_cast); + } + else + { + // convert CT_ANGLE_OPEN to CT_COMPARE + pc->SetType(CT_COMPARE); + } + } + + if ( pc->Is(CT_ANGLE_CLOSE) + && pc->GetParentType() != CT_TEMPLATE) + { + if (in_type_cast) + { + in_type_cast = false; + pc->SetParentType(CT_TYPE_CAST); + } + else + { + next = handle_double_angle_close(pc); + } + } + + if (language_is_set(LANG_D)) + { + // Check for the D string concat symbol '~' + if ( pc->Is(CT_INV) + && ( prev->Is(CT_STRING) + || prev->Is(CT_WORD) + || next->Is(CT_STRING))) + { + pc->SetType(CT_CONCAT); + } + + // Check for the D template symbol '!' (word + '!' + word or '(') + if ( pc->Is(CT_NOT) + && prev->Is(CT_WORD) + && ( next->Is(CT_PAREN_OPEN) + || next->Is(CT_WORD) + || next->Is(CT_TYPE) + || next->Is(CT_NUMBER) + || next->Is(CT_NUMBER_FP) + || next->Is(CT_STRING) + || next->Is(CT_STRING_MULTI))) + { + pc->SetType(CT_D_TEMPLATE); + } + + // handle "version(unittest) { }" vs "unittest { }" + if ( pc->Is(CT_UNITTEST) + && prev->Is(CT_PAREN_OPEN)) + { + pc->SetType(CT_WORD); + } + + // handle 'static if' and merge the tokens + if ( pc->Is(CT_IF) + && prev->IsString("static")) + { + // delete PREV and merge with IF + pc->Str().insert(0, ' '); + pc->Str().insert(0, prev->GetStr()); + pc->SetOrigCol(prev->GetOrigCol()); + pc->SetOrigLine(prev->GetOrigLine()); + Chunk *to_be_deleted = prev; + prev = prev->GetPrevNcNnl(); + + if (prev->IsNotNullChunk()) + { + Chunk::Delete(to_be_deleted); + } + } + } + + if (language_is_set(LANG_CPP)) + { + // Change Word before '::' into a type + if ( pc->Is(CT_WORD) + && next->Is(CT_DC_MEMBER)) + { + prev = pc->GetPrev(); + + if (prev->IsNullChunk()) // Issue #3010 + { + pc->SetType(CT_TYPE); + } + else + { + if (prev->Is(CT_COLON)) + { + // nothing to do + } + else + { + pc->SetType(CT_TYPE); + } + } + } + + // Set parent type for 'if constexpr' + if ( prev->Is(CT_IF) + && pc->Is(CT_QUALIFIER) + && pc->IsString("constexpr")) + { + pc->SetType(CT_CONSTEXPR); + } + } + + // Change get/set to CT_WORD if not followed by a brace open + if ( pc->Is(CT_GETSET) + && next->IsNot(CT_BRACE_OPEN)) + { + if ( next->Is(CT_SEMICOLON) + && ( prev->Is(CT_BRACE_CLOSE) + || prev->Is(CT_BRACE_OPEN) + || prev->Is(CT_SEMICOLON))) + { + pc->SetType(CT_GETSET_EMPTY); + next->SetParentType(CT_GETSET); + } + else + { + pc->SetType(CT_WORD); + } + } + + /* + * Interface is only a keyword in MS land if followed by 'class' or 'struct' + * likewise, 'class' may be a member name in Java. + */ + if ( pc->Is(CT_CLASS) + && !CharTable::IsKw1(next->GetStr()[0])) + { + if ( next->IsNot(CT_DC_MEMBER) + && next->IsNot(CT_ATTRIBUTE)) // Issue #2570 + { + pc->SetType(CT_WORD); + } + else if ( prev->Is(CT_DC_MEMBER) + || prev->Is(CT_TYPE)) + { + pc->SetType(CT_TYPE); + } + else if (next->Is(CT_DC_MEMBER)) + { + Chunk *next2 = next->GetNextNcNnlNet(); + + if ( next2->Is(CT_INV) // CT_INV hasn't turned into CT_DESTRUCTOR just yet + || ( next2->Is(CT_CLASS) // constructor isn't turned into CT_FUNC* just yet + && !strcmp(pc->Text(), next2->Text()))) + { + pc->SetType(CT_TYPE); + } + } + } + + /* + * Change item after operator (>=, ==, etc) to a CT_OPERATOR_VAL + * Usually the next item is part of the operator. + * In a few cases the next few tokens are part of it: + * operator + - common case + * operator >> - need to combine '>' and '>' + * operator () + * operator [] - already converted to TSQUARE + * operator new [] + * operator delete [] + * operator const char * + * operator const B& + * operator std::allocator<U> + * + * In all cases except the last, this will put the entire operator value + * in one chunk. + */ + if (pc->Is(CT_OPERATOR)) + { + Chunk *tmp2 = next->GetNext(); + + // Handle special case of () operator -- [] already handled + if (next->Is(CT_PAREN_OPEN)) + { + Chunk *tmp = next->GetNext(); + + if (tmp->Is(CT_PAREN_CLOSE)) + { + next->Str() = "()"; + next->SetType(CT_OPERATOR_VAL); + Chunk::Delete(tmp); + next->SetOrigColEnd(next->GetOrigColEnd() + 1); + } + } + else if ( next->Is(CT_ANGLE_CLOSE) + && tmp2->Is(CT_ANGLE_CLOSE) + && tmp2->GetOrigCol() == next->GetOrigColEnd()) + { + next->Str().append('>'); + next->SetOrigColEnd(next->GetOrigColEnd() + 1); + next->SetType(CT_OPERATOR_VAL); + Chunk::Delete(tmp2); + } + else if (next->TestFlags(PCF_PUNCTUATOR)) + { + next->SetType(CT_OPERATOR_VAL); + } + else + { + next->SetType(CT_TYPE); + + /* + * Replace next with a collection of all tokens that are part of + * the type. + */ + tmp2 = next; + Chunk *tmp; + + while ((tmp = tmp2->GetNext())->IsNotNullChunk()) + { + if ( tmp->IsNot(CT_WORD) + && tmp->IsNot(CT_TYPE) + && tmp->IsNot(CT_QUALIFIER) + && tmp->IsNot(CT_STAR) + && tmp->IsNot(CT_CARET) + && tmp->IsNot(CT_AMP) + && tmp->IsNot(CT_TSQUARE)) + { + break; + } + // Change tmp into a type so that space_needed() works right + make_type(tmp); + size_t num_sp = space_needed(tmp2, tmp); + + while (num_sp-- > 0) + { + next->Str().append(" "); + } + next->Str().append(tmp->GetStr()); + tmp2 = tmp; + } + + while ((tmp2 = next->GetNext()) != tmp) + { + Chunk::Delete(tmp2); + } + next->SetType(CT_OPERATOR_VAL); + + next->SetOrigColEnd(next->GetOrigCol() + next->Len()); + } + next->SetParentType(CT_OPERATOR); + + LOG_FMT(LOPERATOR, "%s(%d): %zu:%zu operator '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), next->Text()); + } + + // Change private, public, protected into either a qualifier or label + if (pc->Is(CT_ACCESS)) + { + // Handle Qt slots - maybe should just check for a CT_WORD? + if ( next->IsString("slots") + || next->IsString("Q_SLOTS")) + { + Chunk *tmp = next->GetNext(); + + if (tmp->Is(CT_COLON)) + { + next = tmp; + } + } + + if (next->Is(CT_COLON)) + { + next->SetType(CT_ACCESS_COLON); + Chunk *tmp; + + if ((tmp = next->GetNextNcNnl())->IsNotNullChunk()) + { + tmp->SetFlagBits(PCF_STMT_START | PCF_EXPR_START); + } + } + else + { + pc->SetType(( pc->IsString("signals") + || pc->IsString("Q_SIGNALS")) + ? CT_WORD : CT_QUALIFIER); + } + } + + // Look for <newline> 'EXEC' 'SQL' + if ( ( pc->IsString("EXEC", false) + && next->IsString("SQL", false)) + || ( (*pc->GetStr().c_str() == '$') + && pc->IsNot(CT_SQL_WORD) + /* but avoid breaking tokenization for C# 6 interpolated strings. */ + && ( !language_is_set(LANG_CS) + || ( pc->Is(CT_STRING) + && (!pc->GetStr().startswith("$\"")) + && (!pc->GetStr().startswith("$@\"")))))) + { + Chunk *tmp = pc->GetPrev(); + + if (tmp->IsNewline()) + { + if (*pc->GetStr().c_str() == '$') + { + pc->SetType(CT_SQL_EXEC); + + if (pc->Len() > 1) + { + // SPLIT OFF '$' + Chunk nc; + + nc = *pc; + pc->Str().resize(1); + pc->SetOrigColEnd(pc->GetOrigCol() + 1); + + nc.SetType(CT_SQL_WORD); + nc.Str().pop_front(); + nc.SetOrigCol(nc.GetOrigCol() + 1); + nc.SetColumn(nc.GetColumn() + 1); + nc.CopyAndAddAfter(pc); + + next = pc->GetNext(); + } + } + tmp = next->GetNext(); + + if (tmp->IsString("BEGIN", false)) + { + pc->SetType(CT_SQL_BEGIN); + } + else if (tmp->IsString("END", false)) + { + pc->SetType(CT_SQL_END); + } + else + { + pc->SetType(CT_SQL_EXEC); + } + + // Change words into CT_SQL_WORD until CT_SEMICOLON + while (tmp->IsNotNullChunk()) + { + if (tmp->Is(CT_SEMICOLON)) + { + break; + } + + if ( (tmp->Len() > 0) + && ( unc_isalpha(*tmp->GetStr().c_str()) + || (*tmp->GetStr().c_str() == '$'))) + { + tmp->SetType(CT_SQL_WORD); + } + tmp = tmp->GetNextNcNnl(); + } + } + } + + // handle MS abomination 'for each' + if ( pc->Is(CT_FOR) + && next->IsString("each") + && (next == pc->GetNext())) + { + // merge the two with a space between + pc->Str().append(' '); + pc->Str() += next->GetStr(); + pc->SetOrigColEnd(next->GetOrigColEnd()); + Chunk::Delete(next); + next = pc->GetNextNcNnl(); + + // label the 'in' + if (next->Is(CT_PAREN_OPEN)) + { + Chunk *tmp = next->GetNextNcNnl(); + + while ( tmp->IsNotNullChunk() + && tmp->IsNot(CT_PAREN_CLOSE)) + { + if (tmp->IsString("in")) + { + tmp->SetType(CT_IN); + break; + } + tmp = tmp->GetNextNcNnl(); + } + } + } + + /* + * ObjectiveC allows keywords to be used as identifiers in some situations + * This is a dirty hack to allow some of the more common situations. + */ + if (language_is_set(LANG_OC)) + { + if ( ( pc->Is(CT_IF) + || pc->Is(CT_FOR) + || pc->Is(CT_WHILE)) + && !next->Is(CT_PAREN_OPEN)) + { + pc->SetType(CT_WORD); + } + + if ( pc->Is(CT_DO) + && ( prev->Is(CT_MINUS) + || next->Is(CT_SQUARE_CLOSE))) + { + pc->SetType(CT_WORD); + } + + // Fix self keyword back to word when mixing c++/objective-c + if ( pc->Is(CT_THIS) + && !strcmp(pc->Text(), "self") + && ( next->Is(CT_COMMA) + || next->Is(CT_PAREN_CLOSE))) + { + pc->SetType(CT_WORD); + } + + // Fix self keyword back to word when mixing c++/objective-c + if ( pc->Is(CT_THIS) + && !strcmp(pc->Text(), "self") + && ( next->Is(CT_COMMA) + || next->Is(CT_PAREN_CLOSE))) + { + pc->SetType(CT_WORD); + } + } + + // Vala allows keywords to be used as identifiers + if (language_is_set(LANG_VALA)) + { + if ( find_keyword_type(pc->Text(), pc->Len()) != CT_WORD + && ( prev->Is(CT_DOT) + || next->Is(CT_DOT) + || prev->Is(CT_MEMBER) + || next->Is(CT_MEMBER) + || prev->Is(CT_TYPE))) + { + pc->SetType(CT_WORD); + } + } + + // Another hack to clean up more keyword abuse + if ( pc->Is(CT_CLASS) + && ( prev->Is(CT_DOT) + || next->Is(CT_DOT) + || prev->Is(CT_MEMBER) // Issue #3031 + || next->Is(CT_MEMBER))) + { + pc->SetType(CT_WORD); + } + + // Detect Objective C class name + if ( pc->Is(CT_OC_IMPL) + || pc->Is(CT_OC_INTF) + || pc->Is(CT_OC_PROTOCOL)) + { + if (next->IsNot(CT_PAREN_OPEN)) + { + next->SetType(CT_OC_CLASS); + } + next->SetParentType(pc->GetType()); + + Chunk *tmp = next->GetNextNcNnl(); + + if (tmp->IsNotNullChunk()) + { + tmp->SetFlagBits(PCF_STMT_START | PCF_EXPR_START); + } + tmp = pc->GetNextType(CT_OC_END, pc->GetLevel()); + + if (tmp->IsNotNullChunk()) + { + tmp->SetParentType(pc->GetType()); + } + } + + if (pc->Is(CT_OC_INTF)) + { + Chunk *tmp = pc->GetNextNcNnl(E_Scope::PREPROC); + + while ( tmp->IsNotNullChunk() + && tmp->IsNot(CT_OC_END)) + { + if (get_token_pattern_class(tmp->GetType()) != pattern_class_e::NONE) + { + LOG_FMT(LOBJCWORD, "%s(%d): @interface %zu:%zu change '%s' (%s) to CT_WORD\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), tmp->Text(), + get_token_name(tmp->GetType())); + tmp->SetType(CT_WORD); + } + tmp = tmp->GetNextNcNnl(E_Scope::PREPROC); + } + } + + /* + * Detect Objective-C categories and class extensions: + * @interface ClassName (CategoryName) + * @implementation ClassName (CategoryName) + * @interface ClassName () + * @implementation ClassName () + */ + if ( ( pc->GetParentType() == CT_OC_IMPL + || pc->GetParentType() == CT_OC_INTF + || pc->Is(CT_OC_CLASS)) + && next->Is(CT_PAREN_OPEN)) + { + next->SetParentType(pc->GetParentType()); + + Chunk *tmp = next->GetNext(); + + if ( tmp->IsNotNullChunk() + && tmp->GetNext()->IsNotNullChunk()) + { + if (tmp->Is(CT_PAREN_CLOSE)) + { + //tmp->SetType(CT_OC_CLASS_EXT); + tmp->SetParentType(pc->GetParentType()); + } + else + { + tmp->SetType(CT_OC_CATEGORY); + tmp->SetParentType(pc->GetParentType()); + } + } + tmp = pc->GetNextType(CT_PAREN_CLOSE, pc->GetLevel()); + + if (tmp->IsNotNullChunk()) + { + tmp->SetParentType(pc->GetParentType()); + } + } + + /* + * Detect Objective C @property: + * @property NSString *stringProperty; + * @property(nonatomic, retain) NSMutableDictionary *shareWith; + */ + if (pc->Is(CT_OC_PROPERTY)) + { + if (next->IsNot(CT_PAREN_OPEN)) + { + next->SetFlagBits(PCF_STMT_START | PCF_EXPR_START); + } + else + { + cleanup_objc_property(pc); + } + } + + /* + * Detect Objective C @selector: + * @selector(msgNameWithNoArg) + * @selector(msgNameWith1Arg:) + * @selector(msgNameWith2Args:arg2Name:) + */ + if ( pc->Is(CT_OC_SEL) + && next->Is(CT_PAREN_OPEN)) + { + next->SetParentType(pc->GetType()); + + Chunk *tmp = next->GetNext(); + + if (tmp->IsNotNullChunk()) + { + tmp->SetType(CT_OC_SEL_NAME); + tmp->SetParentType(pc->GetType()); + + while ((tmp = tmp->GetNextNcNnl())->IsNotNullChunk()) + { + if (tmp->Is(CT_PAREN_CLOSE)) + { + tmp->SetParentType(CT_OC_SEL); + break; + } + tmp->SetType(CT_OC_SEL_NAME); + tmp->SetParentType(pc->GetType()); + } + } + } + + // Handle special preprocessor junk + if (pc->Is(CT_PREPROC)) + { + pc->SetParentType(next->GetType()); + } + + // Detect "pragma region" and "pragma endregion" + if ( pc->Is(CT_PP_PRAGMA) + && next->Is(CT_PREPROC_BODY)) + { + if ( (strncmp(next->GetStr().c_str(), "region", 6) == 0) + || (strncmp(next->GetStr().c_str(), "endregion", 9) == 0)) + // TODO: probably better use strncmp + { + pc->SetType((*next->GetStr().c_str() == 'r') ? CT_PP_REGION : CT_PP_ENDREGION); + + prev->SetParentType(pc->GetType()); + } + } + + // Change 'default(' into a sizeof-like statement + if ( language_is_set(LANG_CS) + && pc->Is(CT_DEFAULT) + && next->Is(CT_PAREN_OPEN)) + { + pc->SetType(CT_SIZEOF); + } + + if ( pc->Is(CT_UNSAFE) + && next->IsNot(CT_BRACE_OPEN)) + { + pc->SetType(CT_QUALIFIER); + } + + if ( ( pc->Is(CT_USING) + || ( pc->Is(CT_TRY) + && language_is_set(LANG_JAVA))) + && next->Is(CT_PAREN_OPEN)) + { + pc->SetType(CT_USING_STMT); + } + + // Add minimal support for C++0x rvalue references + if ( pc->Is(CT_BOOL) + && language_is_set(LANG_CPP) + && pc->IsString("&&")) + { + if (prev->Is(CT_TYPE)) + { + // Issue # 1002 + if (!pc->TestFlags(PCF_IN_TEMPLATE)) + { + pc->SetType(CT_BYREF); + } + } + } + + /* + * HACK: treat try followed by a colon as a qualifier to handle this: + * A::A(int) try : B() { } catch (...) { } + */ + if ( pc->Is(CT_TRY) + && pc->IsString("try") + && next->Is(CT_COLON)) + { + pc->SetType(CT_QUALIFIER); + } + + /* + * If Java's 'synchronized' is in a method declaration, it should be + * a qualifier. + */ + if ( language_is_set(LANG_JAVA) + && pc->Is(CT_SYNCHRONIZED) + && next->IsNot(CT_PAREN_OPEN)) + { + pc->SetType(CT_QUALIFIER); + } + + // change CT_DC_MEMBER + CT_FOR into CT_DC_MEMBER + CT_FUNC_CALL + if ( pc->Is(CT_FOR) + && pc->GetPrev()->Is(CT_DC_MEMBER)) + { + pc->SetType(CT_FUNC_CALL); + } + // TODO: determine other stuff here + + prev = pc; + pc = next; + next = pc->GetNextNcNnl(); + } +} // tokenize_cleanup + + +bool invalid_open_angle_template(Chunk *prev) +{ + if (prev == nullptr) + { + 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); +} + + +static 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 != nullptr) ? get_token_name(end->GetType()) : "<null>"); + start->SetType(CT_COMPARE); +} // check_template + + +static 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); + // a test "if (next == nullptr)" is not necessary + 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); + // a test "if (next == nullptr)" is not necessary + 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 + + +static 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 + + +static void cleanup_objc_property(Chunk *start) +{ + assert(start->Is(CT_OC_PROPERTY)); + + Chunk *open_paren = start->GetNextType(CT_PAREN_OPEN, start->GetLevel()); + + if (open_paren->IsNullChunk()) + { + LOG_FMT(LTEMPL, "%s(%d): Property is not followed by opening paren\n", __func__, __LINE__); + return; + } + open_paren->SetParentType(start->GetType()); + + Chunk *tmp = start->GetNextType(CT_PAREN_CLOSE, start->GetLevel()); + + if (tmp->IsNotNullChunk()) + { + tmp->SetParentType(start->GetType()); + tmp = tmp->GetNextNcNnl(); + + if (tmp->IsNotNullChunk()) + { + tmp->SetFlagBits(PCF_STMT_START | PCF_EXPR_START); + + tmp = tmp->GetNextType(CT_SEMICOLON, start->GetLevel()); + + if (tmp->IsNotNullChunk()) + { + tmp->SetParentType(start->GetType()); + } + } + } + mark_selectors_in_property_with_open_paren(open_paren); + mark_attributes_in_property_with_open_paren(open_paren); +} + + +static void mark_selectors_in_property_with_open_paren(Chunk *open_paren) +{ + assert(open_paren->Is(CT_PAREN_OPEN)); + + Chunk *tmp = open_paren; + + while (tmp->IsNot(CT_PAREN_CLOSE)) + { + if ( tmp->Is(CT_WORD) + && ( tmp->IsString("setter") + || tmp->IsString("getter"))) + { + tmp = tmp->GetNext(); + + while ( tmp->IsNotNullChunk() + && tmp->IsNot(CT_COMMA) + && tmp->IsNot(CT_PAREN_CLOSE)) + { + if ( tmp->Is(CT_WORD) + || tmp->IsString(":")) + { + tmp->SetType(CT_OC_SEL_NAME); + } + tmp = tmp->GetNext(); + } + } + else + { + tmp = tmp->GetNext(); + } + } +} + + +static void mark_attributes_in_property_with_open_paren(Chunk *open_paren) +{ + assert(open_paren->Is(CT_PAREN_OPEN)); + + Chunk *tmp = open_paren; + + while (tmp->IsNot(CT_PAREN_CLOSE)) + { + Chunk *next = tmp->GetNext(); + + if ( ( tmp->Is(CT_COMMA) + || tmp->Is(CT_PAREN_OPEN)) + && ( next->Is(CT_WORD) + || next->Is(CT_TYPE))) + { + next->SetType(CT_OC_PROPERTY_ATTR); + } + tmp = next; + } +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/tokenize_cleanup.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/tokenize_cleanup.h new file mode 100644 index 00000000..1789ee26 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/tokenize_cleanup.h @@ -0,0 +1,31 @@ +/** + * @file tokenize_cleanup.h + * prototypes for tokenize_cleanup.c + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef TOKENIZ_CLEANUP_H_INCLUDED +#define TOKENIZ_CLEANUP_H_INCLUDED + +#include "uncrustify_types.h" + + +/** + * @brief clean up tokens + * + * Change certain token types based on simple sequence. + * Example: change '[' + ']' to '[]' + * Note that level info is not yet available, so it is OK to do all + * processing that doesn't need to know level info. (that's very little!) + */ +void tokenize_cleanup(); + + +void tokenize_trailing_return_types(); + + +void split_off_angle_close(Chunk *pc); + + +#endif /* TOKENIZ_CLEANUP_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_ctype.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_ctype.cpp new file mode 100644 index 00000000..352b4efb --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_ctype.cpp @@ -0,0 +1,75 @@ +#include "options.h" + + +int unc_fix_ctype(int ch) +{ + if ( ch >= -1 + && ch <= 255) + { + return(ch); + } + return(0); // Issue #3025 +} + + +int unc_isspace(int ch) +{ + if ( (ch == 12) // Issue #2386 + && uncrustify::options::use_form_feed_no_more_as_whitespace_character()) + { + return(0); + } + else + { + return(isspace(unc_fix_ctype(ch))); + } +} + + +int unc_isprint(int ch) +{ + return(isprint(unc_fix_ctype(ch))); +} + + +int unc_isalpha(int ch) +{ + return(isalpha(unc_fix_ctype(ch))); +} + + +int unc_isalnum(int ch) +{ + return(isalnum(unc_fix_ctype(ch))); +} + + +int unc_toupper(int ch) +{ + return(toupper(unc_fix_ctype(ch))); +} + + +int unc_tolower(int ch) +{ + return(tolower(unc_fix_ctype(ch))); +} + + +int unc_isxdigit(int ch) +{ + return(isxdigit(unc_fix_ctype(ch))); +} + + +int unc_isdigit(int ch) +{ + return(isdigit(unc_fix_ctype(ch))); +} + + +int unc_isupper(int ch) +{ + return( isalpha(unc_fix_ctype(ch)) + && (unc_toupper(unc_fix_ctype(ch)) == ch)); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_ctype.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_ctype.h new file mode 100644 index 00000000..8cfcbf3b --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_ctype.h @@ -0,0 +1,49 @@ +/** + * @file unc_ctype.h + * The ctype function are only required to handle values 0-255 and EOF. + * A char is sign-extended when cast to an int. + * With some C libraries, these values cause a crash. + * These wrappers will properly handle all char values. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef UNC_CTYPE_H_INCLUDED +#define UNC_CTYPE_H_INCLUDED + +#include "options.h" + +#include <cctype> // to get std::tolower + +//! Test anything EOF (-1) to 0-255 +int unc_fix_ctype(int ch); + +//! check if a character is a space +int unc_isspace(int ch); + +//! check if a character is a printing character +int unc_isprint(int ch); + +//! check if a character is an alphabetic character (a letter). +int unc_isalpha(int ch); + +//! check if a character is an alphanumeric character. +int unc_isalnum(int ch); + +//! convert a character to upper case +int unc_toupper(int ch); + +//! convert a character to lower case +int unc_tolower(int ch); + +//! check if a character is a hexadecimal digit +int unc_isxdigit(int ch); + +//! check if a character is a decimal digit +int unc_isdigit(int ch); + +//! check if a character is upper case +int unc_isupper(int ch); + +#endif /* UNC_CTYPE_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_text.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_text.cpp new file mode 100644 index 00000000..1f96a67c --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_text.cpp @@ -0,0 +1,759 @@ +/** + * @file unc_text.cpp + * A simple class that handles the chunk text. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "unc_text.h" + +#include "unc_ctype.h" +#include "unicode.h" // encode_utf8() + +#include <algorithm> +#include <stdexcept> + + +using namespace std; + + +static constexpr const int_fast8_t UTF8_BLOCKS = 6; // 6 -> max utf8 blocks per char + + +static size_t fix_len_idx(size_t size, size_t idx, size_t len); + +//! converts \n and \r chars are into NL and CR UTF8 symbols before encode_utf8 is called +static void toLogTextUtf8(int c, unc_text::log_type &container); + +/** + * calculates the size a 'log_type' container needs to have in order to take + * in values of a 'unc_text::value_type' up to idx + * (without \0, with symbols for the converted \n and \r chars) + * + * throws if char is greater than 0x7fffffff + */ +static int getLogTextUtf8Len(unc_text::value_type &c0, size_t end); + +static int getLogTextUtf8Len(unc_text::value_type &c0, size_t start, size_t end); + + +static int getLogTextUtf8Len(unc_text::value_type &c0, size_t start, size_t end) +{ + size_t c1_idx = 0; + + for (size_t i = start; i < end; ++i) + { + auto ch = c0[i]; + + if (ch == '\n') + { + ch = 0x2424; // NL symbol + } + else if (ch == '\r') + { + ch = 0x240d; // CR symbol + } + + if (ch < 0x80) // 1-byte sequence + { + c1_idx += 1; + } + else if (ch < 0x0800) // 2-byte sequence + { + c1_idx += 2; + } + else if (ch < 0x10000) // 3-byte sequence + { + c1_idx += 3; + } + else if (ch < 0x200000) // 4-byte sequence + { + c1_idx += 4; + } + else if (ch < 0x4000000) // 5-byte sequence + { + c1_idx += 5; + } + else if (ch <= 0x7fffffff) // 6-byte sequence + { + c1_idx += 6; + } + else + { + throw out_of_range(string(__func__) + ":" + to_string(__LINE__) + + " - ch value too big, can't convert to utf8"); + } + } + + return(c1_idx); +} // getLogTextUTF8Len + + +static int getLogTextUtf8Len(unc_text::value_type &c0, size_t end) +{ + return(getLogTextUtf8Len(c0, 0, end)); +} + + +static void toLogTextUtf8(int c, unc_text::log_type &container) +{ + if (c == '\n') + { + c = 0x2424; // NL symbol + } + else if (c == '\r') + { + c = 0x240d; // CR symbol + } + encode_utf8(c, container); +} + + +static size_t fix_len_idx(size_t size, size_t idx, size_t len) +{ + if (idx >= size) + { + return(0); + } + const size_t left = size - idx; + + return((len > left) ? left : len); +} + + +unc_text::unc_text() +{ + m_logtext = log_type{ '\0' }; +} + + +unc_text::unc_text(const unc_text &ref) +{ + set(ref); +} + + +unc_text::unc_text(const unc_text &ref, size_t idx, size_t len) +{ + set(ref, idx, len); +} + + +unc_text::unc_text(const char *ascii_text) +{ + set(ascii_text); +} + + +unc_text::unc_text(const std::string &ascii_text) +{ + set(ascii_text); +} + + +unc_text::unc_text(const value_type &data, size_t idx, size_t len) +{ + set(data, idx, len); +} + + +size_t unc_text::size() const +{ + return(m_chars.size()); +} + + +unc_text &unc_text::operator=(int ch) +{ + set(ch); + return(*this); +} + + +unc_text &unc_text::operator=(const unc_text &ref) +{ + set(ref); + return(*this); +} + + +unc_text &unc_text::operator=(const std::string &ascii_text) +{ + set(ascii_text); + return(*this); +} + + +unc_text &unc_text::operator=(const char *ascii_text) +{ + set(ascii_text); + return(*this); +} + + +unc_text &unc_text::operator+=(int ch) +{ + append(ch); + return(*this); +} + + +unc_text &unc_text::operator+=(const unc_text &ref) +{ + append(ref); + return(*this); +} + + +unc_text &unc_text::operator+=(const std::string &ascii_text) +{ + append(ascii_text); + return(*this); +} + + +unc_text &unc_text::operator+=(const char *ascii_text) +{ + append(ascii_text); + return(*this); +} + + +const unc_text::value_type &unc_text::get() const +{ + return(m_chars); +} + + +int unc_text::operator[](size_t idx) const +{ + return((idx < m_chars.size()) ? m_chars[idx] : 0); +} + + +const int &unc_text::at(size_t idx) const +{ + return(m_chars.at(idx)); +} + + +const int &unc_text::back() const +{ + return(m_chars.back()); +} + + +void unc_text::push_back(int ch) +{ + append(ch); +} + + +void unc_text::pop_back() +{ + if (size() == 0) + { + return; + } + m_chars.pop_back(); + update_logtext(); +} + + +void unc_text::pop_front() +{ + if (size() == 0) + { + return; + } + m_chars.pop_front(); + update_logtext(); +} + + +void unc_text::update_logtext() +{ + // make a pessimistic guess at the size + m_logtext.clear(); + m_logtext.reserve(m_chars.size() * 3); + + for (int m_char : m_chars) + { + toLogTextUtf8(m_char, m_logtext); + } + + m_logtext.push_back(0); +} + + +int unc_text::compare(const unc_text &ref1, const unc_text &ref2, size_t len, bool tcare) +{ + const size_t len1 = ref1.size(); + const size_t len2 = ref2.size(); + const auto max_idx = std::min({ len, len1, len2 }); + size_t idx = 0; + + for ( ; idx < max_idx; idx++) + { + // exactly the same character ? + if (ref1.m_chars[idx] == ref2.m_chars[idx]) + { + continue; + } + int diff; // Issue #2091 + + if (tcare) + { + diff = ref1.m_chars[idx] - ref2.m_chars[idx]; + } + else + { + diff = unc_tolower(ref1.m_chars[idx]) - unc_tolower(ref2.m_chars[idx]); + } + + if (diff == 0) + { + /* + * if we're comparing the same character but in different case + * we want to favor lower case before upper case (e.g. a before A) + * so the order is the reverse of ASCII order (we negate). + */ + return(-(ref1.m_chars[idx] - ref2.m_chars[idx])); + } + // return the case-insensitive diff to sort alphabetically + return(diff); + } + + if (idx == len) + { + return(0); + } + // underflow save: return(len1 - len2); + return((len1 > len2) ? (len1 - len2) : -static_cast<int>(len2 - len1)); +} // unc_text::compare + + +bool unc_text::equals(const unc_text &ref) const +{ + const size_t len = size(); + + if (ref.size() != len) + { + return(false); + } + + for (size_t idx = 0; idx < len; idx++) + { + if (m_chars[idx] != ref.m_chars[idx]) + { + return(false); + } + } + + return(true); +} + + +const char *unc_text::c_str() const +{ + return(reinterpret_cast<const char *>(&m_logtext[0])); +} + + +void unc_text::set(int ch) +{ + m_logtext.clear(); + toLogTextUtf8(ch, m_logtext); + m_logtext.push_back('\0'); + + + m_chars.clear(); + m_chars.push_back(ch); +} + + +void unc_text::set(const unc_text &ref) +{ + m_chars = ref.m_chars; + m_logtext = ref.m_logtext; +} + + +void unc_text::set(const unc_text &ref, size_t idx, size_t len) +{ + const auto ref_size = ref.size(); + + if (len == ref_size) + { + m_chars = ref.m_chars; + update_logtext(); + return; + } + m_chars.resize(len); + + len = fix_len_idx(ref_size, idx, len); + + for (size_t di = 0; + len > 0; + di++, idx++, len--) + { + m_chars[di] = ref.m_chars[idx]; + } + + update_logtext(); +} + + +void unc_text::set(const string &ascii_text) +{ + const size_t len = ascii_text.size(); + + m_chars.resize(len); + + for (size_t idx = 0; idx < len; idx++) + { + m_chars[idx] = ascii_text[idx]; + } + + update_logtext(); +} + + +void unc_text::set(const char *ascii_text) +{ + const size_t len = strlen(ascii_text); + + m_chars.resize(len); + + for (size_t idx = 0; idx < len; idx++) + { + m_chars[idx] = *ascii_text++; + } + + update_logtext(); +} + + +void unc_text::set(const value_type &data, size_t idx, size_t len) +{ + m_chars.resize(len); + + len = fix_len_idx(data.size(), idx, len); + + for (size_t di = 0; + len > 0; + di++, idx++, len--) + { + m_chars[di] = data[idx]; + } + + update_logtext(); +} + + +void unc_text::resize(size_t new_size) +{ + if (size() == new_size) + { + return; + } + const auto log_new_size = getLogTextUtf8Len(m_chars, new_size); + + m_logtext.resize(log_new_size + 1); // one extra for \0 + m_logtext[log_new_size] = '\0'; + + + m_chars.resize(new_size); +} + + +void unc_text::clear() +{ + m_logtext.clear(); + m_logtext.push_back('\0'); + + + m_chars.clear(); +} + + +void unc_text::insert(size_t idx, int ch) +{ + if (idx >= m_chars.size()) + { + throw out_of_range(string(__func__) + ":" + to_string(__LINE__) + + " - idx >= m_chars.size()"); + } + log_type utf8converted; + + utf8converted.reserve(UTF8_BLOCKS); + toLogTextUtf8(ch, utf8converted); + + const auto utf8_idx = getLogTextUtf8Len(m_chars, idx); + + m_logtext.pop_back(); // remove '\0' + m_logtext.insert(std::next(std::begin(m_logtext), utf8_idx), + std::begin(utf8converted), std::end(utf8converted)); + m_logtext.push_back('\0'); + + + m_chars.insert(std::next(std::begin(m_chars), idx), ch); +} + + +void unc_text::insert(size_t idx, const unc_text &ref) +{ + if (ref.size() == 0) + { + return; + } + + if (idx >= m_chars.size()) + { + throw out_of_range(string(__func__) + ":" + to_string(__LINE__) + + " - idx >= m_chars.size()"); + } + const auto utf8_idx = getLogTextUtf8Len(m_chars, idx); + + // (A+B) remove \0 from both containers, add back a single at the end + m_logtext.pop_back(); // A + m_logtext.insert(std::next(std::begin(m_logtext), utf8_idx), + std::begin(ref.m_logtext), + std::prev(std::end(ref.m_logtext))); // B + m_logtext.push_back('\0'); + + + m_chars.insert(std::next(std::begin(m_chars), idx), + std::begin(ref.m_chars), std::end(ref.m_chars)); +} + + +void unc_text::append(int ch) +{ + m_logtext.pop_back(); + + if ( ch < 0x80 + && ch != '\n' + && ch != '\r') + { + m_logtext.push_back(ch); + } + else + { + log_type utf8converted; + utf8converted.reserve(UTF8_BLOCKS); + toLogTextUtf8(ch, utf8converted); + + m_logtext.insert(std::end(m_logtext), + std::begin(utf8converted), std::end(utf8converted)); + } + m_logtext.push_back('\0'); + + + m_chars.push_back(ch); +} + + +void unc_text::append(const unc_text &ref) +{ + if (ref.size() == 0) + { + return; + } + m_logtext.pop_back(); + m_logtext.insert(std::end(m_logtext), + std::begin(ref.m_logtext), std::end(ref.m_logtext)); + + m_chars.insert(m_chars.end(), ref.m_chars.begin(), ref.m_chars.end()); +} + + +void unc_text::append(const string &ascii_text) +{ + unc_text tmp(ascii_text); + + append(tmp); +} + + +void unc_text::append(const char *ascii_text) +{ + unc_text tmp(ascii_text); + + append(tmp); +} + + +void unc_text::append(const value_type &data, size_t idx, size_t len) +{ + unc_text tmp(data, idx, len); + + append(tmp); +} + + +bool unc_text::startswith(const char *text, size_t idx) const +{ + const auto orig_idx = idx; + + for ( ; + ( idx < size() + && *text); + idx++, text++) + { + if (*text != m_chars[idx]) + { + return(false); + } + } + + return( idx != orig_idx + && (*text == 0)); +} + + +bool unc_text::startswith(const unc_text &text, size_t idx) const +{ + size_t si = 0; + const auto orig_idx = idx; + + for ( ; + ( idx < size() + && si < text.size()); + idx++, si++) + { + if (text.m_chars[si] != m_chars[idx]) + { + return(false); + } + } + + return( idx != orig_idx + && (si == text.size())); +} + + +int unc_text::find(const char *search_txt, size_t start_idx) const +{ + const size_t t_len = strlen(search_txt); // the length of 'text' we are looking for + const size_t s_len = size(); // the length of the string we are looking in + + if ( s_len < t_len // search_txt longer than the string we are looking in + || start_idx + t_len - 1 >= s_len) // starting position to high to find search_txt + { + return(-1); + } + const size_t end_idx = s_len - t_len; + + for (size_t idx = start_idx; idx <= end_idx; idx++) + { + bool match = true; + + for (size_t ii = 0; ii < t_len; ii++) + { + if (m_chars[idx + ii] != search_txt[ii]) + { + match = false; + break; + } + } + + if (match) // 'text' found at position 'idx' + { + return(idx); + } + } + + return(-1); // 'text' not found +} + + +int unc_text::rfind(const char *search_txt, size_t start_idx) const +{ + const size_t t_len = strlen(search_txt); // the length of 'text' we are looking for + const size_t s_len = size(); // the length of the string we are looking in + + if ( s_len < t_len // search_txt longer than the string we are looking in + || start_idx < t_len - 1) // starting position to low to find search_txt + { + return(-1); + } + const size_t end_idx = s_len - t_len; + + if (start_idx > end_idx) + { + start_idx = end_idx; + } + + for (auto idx = static_cast<int>(start_idx); idx >= 0; idx--) + { + bool match = true; + + for (size_t ii = 0; ii < t_len; ii++) + { + if (m_chars[idx + ii] != search_txt[ii]) + { + match = false; + break; + } + } + + if (match) + { + return(idx); + } + } + + return(-1); +} + + +void unc_text::erase(size_t start_idx, size_t len) +{ + if (len == 0) + { + return; + } + const size_t end_idx = start_idx + len - 1; + + if (end_idx >= m_chars.size()) + { + throw out_of_range(string(__func__) + ":" + to_string(__LINE__) + + " - idx + len >= m_chars.size()"); + } + const auto pos_s = getLogTextUtf8Len(m_chars, start_idx); + const auto pos_e = pos_s + getLogTextUtf8Len(m_chars, start_idx, end_idx); + + m_logtext.pop_back(); + m_logtext.erase(std::next(std::begin(m_logtext), pos_s), + std::next(std::begin(m_logtext), pos_e + 1)); + m_logtext.push_back('\0'); + + + m_chars.erase(std::next(std::begin(m_chars), start_idx), + std::next(std::begin(m_chars), end_idx + 1)); +} + + +int unc_text::replace(const char *search_text, const unc_text &replace_text) +{ + const size_t s_len = strlen(search_text); + const size_t r_len = replace_text.size(); + + int rcnt = 0; + int fidx = find(search_text); + + while (fidx >= 0) + { + rcnt++; + erase(static_cast<size_t>(fidx), s_len); + + (static_cast<size_t>(fidx) >= m_chars.size()) + ? append(replace_text) + : insert(static_cast<size_t>(fidx), replace_text); + + fidx = find(search_text, static_cast<size_t>(fidx) + r_len); + } + return(rcnt); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_text.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_text.h new file mode 100644 index 00000000..dd678f16 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_text.h @@ -0,0 +1,196 @@ +/** + * @file unc_text.h + * A simple class that handles the chunk text. + * At the start of processing, the entire file is decoded into a std::vector of ints. + * This class is intended to hold sections of that large std::vector. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef UNC_TEXT_H_INCLUDED +#define UNC_TEXT_H_INCLUDED + +#include "base_types.h" + +#include <deque> +#include <string> +#include <vector> + + +/** + * abbreviations used: + * - unc_text - uncrustify text + */ + +class unc_text +{ +public: + typedef std::deque<int> value_type; // double encoded list of int values + typedef std::vector<UINT8> log_type; + + + unc_text(); + + unc_text(const unc_text &ref); + + unc_text(const unc_text &ref, size_t idx, size_t len = 0); + + unc_text(const char *ascii_text); + + unc_text(const std::string &ascii_text); + + unc_text(const value_type &data, size_t idx = 0, size_t len = 0); + + + ~unc_text() = default; + + + void resize(size_t new_size); + + + void clear(); + + + //! grab the number of characters + size_t size() const; + + + void set(int ch); + + void set(const unc_text &ref); + + void set(const unc_text &ref, size_t idx, size_t len = 0); + + void set(const std::string &ascii_text); + + void set(const char *ascii_text); + + void set(const value_type &data, size_t idx = 0, size_t len = 0); + + + unc_text &operator=(int ch); + + unc_text &operator=(const unc_text &ref); + + unc_text &operator=(const std::string &ascii_text); + + unc_text &operator=(const char *ascii_text); + + + void insert(size_t idx, int ch); + + void insert(size_t idx, const unc_text &ref); + + + void erase(size_t idx, size_t len = 1); + + + //! Add a unc_text character to an unc_text + void append(int ch); + + void append(const unc_text &ref); + + //! Add a string to an unc_text + void append(const std::string &ascii_text); + + /** + * Add a variable length string to an unc_text. + * The variable length string format is similar as for printf + * + * @note the overall length of the string must not exceed 256 characters + * + * @param ascii_text a variable length string + */ + void append(const char *ascii_text); + + void append(const value_type &data, size_t idx = 0, size_t len = 0); + + + unc_text &operator+=(int ch); + + unc_text &operator+=(const unc_text &ref); + + unc_text &operator+=(const std::string &ascii_text); + + unc_text &operator+=(const char *ascii_text); + + + //! Returns the UTF-8 string for logging + const char *c_str() const; + + + /** + * compares the content of two unc_text instances + * + * @param ref1 first instance to compare + * @param ref2 second instance to compare + * @param len number of character to compare + * @param tcare take care of case (lower case/ upper case) Issue #2091 + * + * @retval == 0 both text elements are equal + * @retval > 0 + * @retval < 0 + */ + static int compare(const unc_text &ref1, const unc_text &ref2, size_t len = 0, bool tcare = false); + + + bool equals(const unc_text &ref) const; + + + //! grab the data as a series of ints for outputting to a file + const value_type &get() const; + + + int operator[](size_t idx) const; + + + // throws an exception if out of bounds + const int &at(size_t idx) const; + + + //! returns the last element of the character list + const int &back() const; + + + void push_back(int ch); + + + void pop_back(); + + + void pop_front(); + + + bool startswith(const unc_text &text, size_t idx = 0) const; + + bool startswith(const char *text, size_t idx = 0) const; + + + /** + * look for 'text', beginning with position 'sidx' + * + * @param text text to search for + * @param idx position to start search + * + * @return == -1 if not found + * @return >= 0 the position + */ + int find(const char *text, size_t idx = 0) const; + + + int rfind(const char *text, size_t idx = 0) const; + + + int replace(const char *oldtext, const unc_text &newtext); + + +protected: + void update_logtext(); + + value_type m_chars; //! this contains the non-encoded 31-bit chars + log_type m_logtext; //! logging text, utf8 encoded - updated in c_str() +}; + + +#endif /* UNC_TEXT_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_tools.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_tools.cpp new file mode 100644 index 00000000..47425a83 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_tools.cpp @@ -0,0 +1,496 @@ +/** + * @file unc_tools.cpp + * This file contains lot of tools for debugging + * + * @author Guy Maurel + * October 2015- 2021 + * @license GPL v2+ + */ + +#include "unc_tools.h" + +#include "args.h" +#include "output.h" + + +/* + * the test suite Coveralls: https://coveralls.io + * will complains because these functions are only + * used at development time. + * Don't worry about unused lines for the functions: + * prot_the_line + * prot_the_source + * examine_Data + * dump_out + * dump_in + */ + +static size_t counter = 0; +static size_t tokenCounter; + + +/* protocol of the line + * examples: + * prot_the_line(__func__, __LINE__, pc->GetOrigLine(), 0); + * prot_the_line(__func__, __LINE__, 0, 0); + * prot_the_line(__func__, __LINE__, 6, 5); + * prot_the_source(__LINE__); + * log_pcf_flags(LSYS, pc->GetFlags()); + * + * if actual_line is zero, use the option debug_line_number_to_protocol. + * if the value is zero, don't make any protocol and return. + * + * if partNumber is zero, all the tokens of the line are shown, + * if partNumber is NOT zero, only the token with this partNumber is shown. + * + * prot_the_line_pc(pc_sub, __func__, __LINE__, 6, 5); + * to get a protocol of a sub branch, which begins with pc_sub + */ +void prot_the_line(const char *func_name, int theLine, unsigned int actual_line, size_t partNumber) +{ + prot_the_line_pc(Chunk::GetHead(), func_name, theLine, actual_line, partNumber); +} + + +void prot_the_line_pc(Chunk *pc_sub, const char *func_name, int theLine, unsigned int actual_line, size_t partNumber) +{ + if (actual_line == 0) + { + // use the option debug_line_number_to_protocol. + actual_line = options::debug_line_number_to_protocol(); + + if (actual_line == 0) + { + // don't make any protocol. + return; + } + } + counter++; + tokenCounter = 0; + LOG_FMT(LGUY, "Prot_the_line:(%s:%d)(%zu)\n", func_name, theLine, counter); + + for (Chunk *pc = pc_sub; pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if (pc->GetOrigLine() == actual_line) + { + tokenCounter++; + + if ( partNumber == 0 + || partNumber == tokenCounter) + { + LOG_FMT(LGUY, " orig line is %d, (%zu) ", actual_line, tokenCounter); + + if (pc->Is(CT_VBRACE_OPEN)) + { + LOG_FMT(LGUY, "<VBRACE_OPEN>, "); + } + else if (pc->Is(CT_NEWLINE)) + { + LOG_FMT(LGUY, "<NL>(new line count is %zu), ", pc->GetNlCount()); + } + else if (pc->Is(CT_VBRACE_CLOSE)) + { + LOG_FMT(LGUY, "<CT_VBRACE_CLOSE>, "); + } + else if (pc->Is(CT_VBRACE_OPEN)) + { + LOG_FMT(LGUY, "<CT_VBRACE_OPEN>, "); + } + else if (pc->Is(CT_SPACE)) + { + LOG_FMT(LGUY, "<CT_SPACE>, "); + } + else if (pc->Is(CT_IGNORED)) + { + LOG_FMT(LGUY, "<IGNORED> "); + } + else + { + LOG_FMT(LGUY, "Text() '%s', ", pc->Text()); + } + LOG_FMT(LGUY, " column is %zu, pp level is %zu, type is %s, parent type is %s, orig col is %zu,", + pc->GetColumn(), pc->GetPpLevel(), get_token_name(pc->GetType()), + get_token_name(pc->GetParentType()), pc->GetOrigCol()); + + if (pc->Is(CT_IGNORED)) + { + LOG_FMT(LGUY, "\n"); + } + else + { + LOG_FMT(LGUY, " pc->GetFlags(): "); + log_pcf_flags(LGUY, pc->GetFlags()); + } + + if (pc->GetTrackingData() != nullptr) + { + LOG_FMT(LGUY, " Tracking info are: \n"); + LOG_FMT(LGUY, " number of track(s) %zu\n", pc->GetTrackingData()->size()); + + for (size_t track = 0; track < pc->GetTrackingData()->size(); track++) + { + const track_list *A = pc->GetTrackingData(); + const Track_nr B = A->at(track); + size_t Bfirst = B.first; + char *Bsecond = B.second; + + LOG_FMT(LGUY, " %zu, tracking number is %zu\n", track, Bfirst); + LOG_FMT(LGUY, " %zu, rule is %s\n", track, Bsecond); + } + } + } + } + } + + LOG_FMT(LGUY, "\n"); +} // prot_the_line_pc + + +void prot_all_lines(const char *func_name, int theLine) +{ + counter++; + tokenCounter = 0; + size_t lineNumber = 1; + + LOG_FMT(LGUY, "Prot_all_lines:(%s:%d)(%zu)\n", func_name, theLine, counter); + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + tokenCounter++; + + LOG_FMT(LGUY, " orig line is %zu,%zu, pp level is %zu, ", lineNumber, tokenCounter, pc->GetPpLevel()); + + if (pc->Is(CT_VBRACE_OPEN)) + { + LOG_FMT(LGUY, "<VBRACE_OPEN>, "); + } + else if (pc->Is(CT_NEWLINE)) + { + LOG_FMT(LGUY, "<NL>(new line count is %zu), ", pc->GetNlCount()); + tokenCounter = 0; + lineNumber = lineNumber + pc->GetNlCount(); + } + else if (pc->Is(CT_VBRACE_CLOSE)) + { + LOG_FMT(LGUY, "<CT_VBRACE_CLOSE>, "); + } + else if (pc->Is(CT_VBRACE_OPEN)) + { + LOG_FMT(LGUY, "<CT_VBRACE_OPEN>, "); + } + else if (pc->Is(CT_SPACE)) + { + LOG_FMT(LGUY, "<CT_SPACE>, "); + } + else if (pc->Is(CT_IGNORED)) + { + LOG_FMT(LGUY, "<IGNORED> "); + } + else + { + LOG_FMT(LGUY, "Text() '%s', ", pc->Text()); + } + LOG_FMT(LGUY, " column is %zu, type is %s\n", + pc->GetColumn(), get_token_name(pc->GetType())); + } +} // prot_all_lines + + +void prot_the_source(int theLine) +{ + counter++; + LOG_FMT(LGUY, "Prot_the_source:(%d)(%zu)\n", theLine, counter); + output_text(stderr); +} + + +// examples: +// examine_Data(__func__, __LINE__, n); +void examine_Data(const char *func_name, int theLine, int what) +{ + LOG_FMT(LGUY, "\n%s:", func_name); + + Chunk *pc; + + switch (what) + { + case 1: + + for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if ( pc->Is(CT_SQUARE_CLOSE) + || pc->Is(CT_TSQUARE)) + { + LOG_FMT(LGUY, "\n"); + LOG_FMT(LGUY, "1:(%d),", theLine); + LOG_FMT(LGUY, "%s, orig col=%zu, orig col end=%zu\n", pc->Text(), pc->GetOrigCol(), pc->GetOrigColEnd()); + } + } + + break; + + case 2: + LOG_FMT(LGUY, "2:(%d)\n", theLine); + + for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if (pc->GetOrigLine() == 7) + { + if (pc->Is(CT_NEWLINE)) + { + LOG_FMT(LGUY, "(%zu)<NL> col=%zu\n\n", pc->GetOrigLine(), pc->GetOrigCol()); + } + else + { + LOG_FMT(LGUY, "(%zu)%s %s, col=%zu, column=%zu\n", pc->GetOrigLine(), pc->Text(), get_token_name(pc->GetType()), pc->GetOrigCol(), pc->GetColumn()); + } + } + } + + break; + + case 3: + LOG_FMT(LGUY, "3:(%d)\n", theLine); + + for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if (pc->Is(CT_NEWLINE)) + { + LOG_FMT(LGUY, "(%zu)<NL> col=%zu\n\n", pc->GetOrigLine(), pc->GetOrigCol()); + } + else + { + LOG_FMT(LGUY, "(%zu)%s %s, col=%zu, column=%zu\n", pc->GetOrigLine(), pc->Text(), get_token_name(pc->GetType()), pc->GetOrigCol(), pc->GetColumn()); + } + } + + break; + + case 4: + LOG_FMT(LGUY, "4:(%d)\n", theLine); + + for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if (pc->GetOrigLine() == 6) + { + if (pc->Is(CT_NEWLINE)) + { + LOG_FMT(LGUY, "(%zu)<NL> col=%zu\n\n", pc->GetOrigLine(), pc->GetOrigCol()); + } + else + { + LOG_FMT(LGUY, "(%zu)%s %s, col=%zu, column=%zu\n", pc->GetOrigLine(), pc->Text(), get_token_name(pc->GetType()), pc->GetOrigCol(), pc->GetColumn()); + } + } + } + + break; + + default: + break; + } // switch +} // examine_Data + + +void dump_out(unsigned int type) +{ + char dumpFileName[300]; + + if (cpd.dumped_file == nullptr) + { + sprintf(dumpFileName, "%s.%u", cpd.filename.c_str(), type); + } + else + { + sprintf(dumpFileName, "%s.%u", cpd.dumped_file, type); + } + FILE *D_file = fopen(dumpFileName, "w"); + + if (D_file != nullptr) + { + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + fprintf(D_file, "[%p]\n", pc); + fprintf(D_file, " type %s\n", get_token_name(pc->GetType())); + fprintf(D_file, " orig line %zu\n", pc->GetOrigLine()); + fprintf(D_file, " orig col %zu\n", pc->GetOrigCol()); + fprintf(D_file, " orig col end %zu\n", pc->GetOrigColEnd()); + + if (pc->GetOrigPrevSp() != 0) + { + fprintf(D_file, " orig prev sp %zu\n", pc->GetOrigPrevSp()); + } + + if (pc->GetColumn() != 0) + { + fprintf(D_file, " column %zu\n", pc->GetColumn()); + } + + if (pc->GetColumnIndent() != 0) + { + fprintf(D_file, " column indent %zu\n", pc->GetColumnIndent()); + } + + if (pc->GetNlCount() != 0) + { + fprintf(D_file, " nl_count %zu\n", pc->GetNlCount()); + } + + if (pc->GetLevel() != 0) + { + fprintf(D_file, " level %zu\n", pc->GetLevel()); + } + + if (pc->GetBraceLevel() != 0) + { + fprintf(D_file, " brace level %zu\n", pc->GetBraceLevel()); + } + + if (pc->GetPpLevel() != 0) + { + fprintf(D_file, " pp level %zu\n", pc->GetPpLevel()); + } + + if (pc->GetAfterTab() != 0) + { + fprintf(D_file, " after tab %d\n", pc->GetAfterTab()); + } + + if (pc->IsNot(CT_NEWLINE)) + { + fprintf(D_file, " Text %s\n", pc->Text()); + } + } + + fclose(D_file); + } +} // dump_out + + +void dump_in(unsigned int type) +{ + char buffer[256]; + bool aNewChunkIsFound = false; + Chunk chunk; + char dumpFileName[300]; + + if (cpd.dumped_file == nullptr) + { + sprintf(dumpFileName, "%s.%u", cpd.filename.c_str(), type); + } + else + { + sprintf(dumpFileName, "%s.%u", cpd.dumped_file, type); + } + FILE *D_file = fopen(dumpFileName, "r"); + + if (D_file != nullptr) + { + unsigned int lineNumber = 0; + + while (fgets(buffer, sizeof(buffer), D_file) != nullptr) + { + ++lineNumber; + + if (aNewChunkIsFound) + { + // look for the next chunk + char first = buffer[0]; + + if (first == '[') + { + aNewChunkIsFound = false; + // add the chunk in the list + chunk.CopyAndAddBefore(Chunk::NullChunkPtr); + chunk.Reset(); + aNewChunkIsFound = true; + continue; + } + // the line as the form + // part value + // Split the line + const int max_parts_count = 3; + char *parts[max_parts_count]; + int parts_count = Args::SplitLine(buffer, parts, max_parts_count - 1); + + if (parts_count != 2) + { + exit(EX_SOFTWARE); + } + + if (strcasecmp(parts[0], "type") == 0) + { + E_Token tokenName = find_token_name(parts[1]); + chunk.SetType(tokenName); + } + else if (strcasecmp(parts[0], "orig line") == 0) + { + chunk.SetOrigLine(strtol(parts[1], nullptr, 0)); + } + else if (strcasecmp(parts[0], "orig col") == 0) + { + chunk.SetOrigCol(strtol(parts[1], nullptr, 0)); + } + else if (strcasecmp(parts[0], "orig col end") == 0) + { + chunk.SetOrigColEnd(strtol(parts[1], nullptr, 0)); + } + else if (strcasecmp(parts[0], "orig prev sp") == 0) + { + chunk.SetOrigPrevSp(strtol(parts[1], nullptr, 0)); + } + else if (strcasecmp(parts[0], "column") == 0) + { + chunk.SetColumn(strtol(parts[1], nullptr, 0)); + } + else if (strcasecmp(parts[0], "nl_count") == 0) + { + chunk.SetNlCount(strtol(parts[1], nullptr, 0)); + } + else if (strcasecmp(parts[0], "text") == 0) + { + if (chunk.GetType() != CT_NEWLINE) + { + chunk.Str() = parts[1]; + } + } + else + { + fprintf(stderr, "on line=%d, for '%s'\n", lineNumber, parts[0]); + log_flush(true); + exit(EX_SOFTWARE); + } + } + else + { + // look for a new chunk + char first = buffer[0]; + + if (first == '[') + { + aNewChunkIsFound = true; + chunk.Reset(); + } + } + } + // add the last chunk in the list + chunk.CopyAndAddBefore(Chunk::NullChunkPtr); + fclose(D_file); + } + else + { + fprintf(stderr, "FATAL: file not found '%s'\n", dumpFileName); + log_flush(true); + exit(EX_SOFTWARE); + } +} // dump_in + + +size_t number = 0; + + +size_t get_A_Number() +{ + number = number + 1; + return(number); +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_tools.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_tools.h new file mode 100644 index 00000000..acd199b9 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unc_tools.h @@ -0,0 +1,46 @@ +/** + * @file unc_tools.h + * + * @author Guy Maurel + * October 2015, 2016, 2017, 2018, 2019, 2020, 2021 + * @license GPL v2+ + */ + +#ifndef UNC_TOOLS_H_INCLUDED +#define UNC_TOOLS_H_INCLUDED + +#include "prototypes.h" + +#if defined DEBUG +#define PROT_THE_LINE prot_the_line(__func__, __LINE__, 0, 0); +#else +#define PROT_THE_LINE /* do nothing */; +#endif + + +void prot_the_line(const char *func_name, int theLine, unsigned int actual_line, size_t partNumber); + + +void prot_the_line_pc(Chunk *pc_sub, const char *func_name, int theLine, unsigned int actual_line, size_t partNumber); + + +void prot_all_lines(const char *func_name, int theLine); + + +void prot_the_source(int theLine); + + +void examine_Data(const char *func_name, int theLine, int what); + + +//! dump the chunk list to a file +void dump_out(unsigned int type); + + +//! create chunk list from a file +void dump_in(unsigned int type); + + +size_t get_A_Number(); + +#endif /* UNC_TOOLS_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify.cpp new file mode 100644 index 00000000..523dd2c3 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify.cpp @@ -0,0 +1,2757 @@ +/** + * @file uncrustify.cpp + * This file takes an input C/C++/D/Java file and reformats it. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#define DEFINE_CHAR_TABLE + +#include "uncrustify.h" + +#include "align.h" +#include "align_nl_cont.h" +#include "align_preprocessor.h" +#include "align_trailing_comments.h" +#include "args.h" +#include "backup.h" +#include "brace_cleanup.h" +#include "braces.h" +#include "change_int_types.h" +#include "combine.h" +#include "compat.h" +#include "detect.h" +#include "enum_cleanup.h" +#include "indent.h" +#include "keywords.h" +#include "lang_pawn.h" +#include "newlines.h" +#include "output.h" +#include "parameter_pack_cleanup.h" +#include "parens.h" +#include "parent_for_pp.h" +#include "remove_duplicate_include.h" +#include "remove_extra_returns.h" +#include "rewrite_infinite_loops.h" +#include "semicolons.h" +#include "sorting.h" +#include "space.h" +#include "token_names.h" +#include "tokenize.h" +#include "tokenize_cleanup.h" +#include "unc_ctype.h" +#include "unc_tools.h" +#include "uncrustify_version.h" +#include "unicode.h" +#include "universalindentgui.h" +#include "width.h" + +#include <cerrno> +#include <fcntl.h> +#include <map> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_STRINGS_H +#include <strings.h> // provides strcasecmp() +#endif +#ifdef HAVE_UTIME_H +#include <time.h> +#endif + + +// VS throws an error if an attribute newer than the requested standard level +// is used; everyone else just ignores it (or warns) like they are supposed to + +#if __cplusplus >= 201703L +#define NODISCARD [[nodiscard]] +#elif defined (__has_cpp_attribute) +#if __has_cpp_attribute(nodiscard) +#define NODISCARD [[nodiscard]] +#else +#define NODISCARD +#endif +#else +#define NODISCARD +#endif + +constexpr static auto LCURRENT = LUNC; + +using namespace std; +using namespace uncrustify; + + +// Global data +cp_data_t cpd; + + +static size_t language_flags_from_name(const char *tag); + + +/** + * Find the language for the file extension + * Defaults to C + * + * @param filename The name of the file + * @return LANG_xxx + */ +static size_t language_flags_from_filename(const char *filename); + + +static bool read_stdin(file_mem &fm); + + +static void uncrustify_start(const deque<int> &data); + + +static bool ends_with(const char *filename, const char *tag, bool case_sensitive); + + +/** + * Does a source file. + * + * @param filename_in the file to read + * @param filename_out nullptr (stdout) or the file to write + * @param parsed_file nullptr or the filename for the parsed debug info + * @param dump_file nullptr or the filename prefix for dumping formatting steps debug info + * @param no_backup don't create a backup, if filename_out == filename_in + * @param keep_mtime don't change the mtime (dangerous) + */ +static void do_source_file(const char *filename_in, const char *filename_out, const char *parsed_file, const char *dump_file, bool no_backup, bool keep_mtime); + + +static void add_file_header(); + + +static void add_file_footer(); + + +static void add_func_header(E_Token type, file_mem &fm); + + +static void add_msg_header(E_Token type, file_mem &fm); + + +static void process_source_list(const char *source_list, const char *prefix, const char *suffix, bool no_backup, bool keep_mtime); + + +static const char *make_output_filename(char *buf, size_t buf_size, const char *filename, const char *prefix, const char *suffix); + + +//! compare the content of two files +static bool file_content_matches(const string &filename1, const string &filename2); + + +static string fix_filename(const char *filename); + + +static bool bout_content_matches(const file_mem &fm, bool report_status); + + +/** + * Loads a file into memory + * + * @param filename name of file to load + * + * @retval true file was loaded successfully + * @retval false file could not be loaded + */ +static int load_mem_file(const char *filename, file_mem &fm); + + +/** + * Try to load the file from the config folder first and then by name + * + * @param filename name of file to load + * + * @retval true file was loaded successfully + * @retval false file could not be loaded + */ +static int load_mem_file_config(const std::string &filename, file_mem &fm); + + +//! print uncrustify version number and terminate +static void version_exit(); + + +const char *path_basename(const char *path) +{ + if (path == nullptr) + { + return(""); + } + const char *last_path = path; + char ch; + + while ((ch = *path) != 0) // check for end of string + { + path++; + + // Check both slash types to support Linux and Windows + if ( (ch == '/') + || (ch == '\\')) + { + last_path = path; + } + } + return(last_path); +} + + +int path_dirname_len(const char *filename) +{ + if (filename == nullptr) + { + return(0); + } + // subtracting addresses like this works only on big endian systems + return(static_cast<int>(path_basename(filename) - filename)); +} + + +void usage_error(const char *msg) +{ + if (msg != nullptr) + { + fprintf(stderr, "%s\n", msg); + log_flush(true); + } + fprintf(stderr, "Try running with -h for usage information\n"); + log_flush(true); +} + + +static void tease() +{ + fprintf(stdout, + "There are currently %zu options and minimal documentation.\n" + "Try UniversalIndentGUI and good luck.\n", get_option_count()); +} + + +void usage(const char *argv0) +{ + fprintf(stdout, + "Usage:\n" + "%s [options] [files ...]\n" + "\n" + "If no input files are specified, the input is read from stdin\n" + "If reading from stdin, you should specify the language using -l\n" + "or specify a filename using --assume for automatic language detection.\n" + "\n" + "If -F is used or files are specified on the command line,\n" + "the output filename is 'prefix/filename' + suffix\n" + "\n" + "When reading from stdin or doing a single file via the '-f' option,\n" + "the output is dumped to stdout, unless redirected with -o FILE.\n" + "\n" + "Errors are always dumped to stderr\n" + "\n" + "The '-f' and '-o' options may not be used with '-F' or '--replace'.\n" + "The '--prefix' and '--suffix' options may not be used with '--replace'.\n" + "\n" + "Basic Options:\n" + " -c CFG : Use the config file CFG, or defaults if CFG is set to '-'.\n" + " -f FILE : Process the single file FILE (output to stdout, use with -o).\n" + " -o FILE : Redirect stdout to FILE.\n" + " -F FILE : Read files to process from FILE, one filename per line (- is stdin).\n" + " --check : Do not output the new text, instead verify that nothing changes when\n" + " the file(s) are processed.\n" + " The status of every file is printed to stderr.\n" + " The exit code is EXIT_SUCCESS if there were no changes, EXIT_FAILURE otherwise.\n" + " files : Files to process (can be combined with -F).\n" + " --suffix SFX : Append SFX to the output filename. The default is '.uncrustify'\n" + " --prefix PFX : Prepend PFX to the output filename path.\n" + " --replace : Replace source files (creates a backup).\n" + " --no-backup : Do not create backup and md5 files. Useful if files are under source control.\n" + " --if-changed : Write to stdout (or create output FILE) only if a change was detected.\n" +#ifdef HAVE_UTIME_H + " --mtime : Preserve mtime on replaced files.\n" +#endif + " -l : Language override: C, CPP, D, CS, JAVA, PAWN, OC, OC+, VALA.\n" + " -t : Load a file with types (usually not needed).\n" + " -q : Quiet mode - no output on stderr (-L will override).\n" + " --frag : Code fragment, assume the first line is indented correctly.\n" + " --assume FN : Uses the filename FN for automatic language detection if reading\n" + " from stdin unless -l is specified.\n" + "\n" + "Config/Help Options:\n" + " -h -? --help --usage : Print this message and exit.\n" + " --version : Print the version and exit.\n" + " --count-options : Print the number of available options and exit.\n" + " --show-config : Print out option documentation and exit.\n" + " --update-config : Output a new config file. Use with -o FILE.\n" + " --update-config-with-doc : Output a new config file. Use with -o FILE.\n" + " --universalindent : Output a config file for Universal Indent GUI.\n" + " --detect : Detects the config from a source file. Use with '-f FILE'.\n" + " Detection is fairly limited.\n" + " --set <option>=<value> : Sets a new value to a config option.\n" + "\n" + "Debug Options:\n" + " -p FILE : Dump debug info into FILE, or to stdout if FILE is set to '-'.\n" + " Must be used in combination with '-f FILE'\n" + " -ds FILE : Dump parsing info at various moments of the formatting process.\n" + " --dump-steps FILE This creates a series of files named 'FILE_nnn.log', each\n" + " corresponding to a formatting step in uncrustify.\n" + " The file 'FILE_000.log' lists the formatting options in use.\n" + " Must be used in combination with '-f FILE'\n" + " -L SEV : Set the log severity (see log_levels.h; note 'A' = 'all')\n" + " -s : Show the log severity in the logs.\n" + " --decode : Decode remaining args (chunk flags) and exit.\n" + " --tracking_space FILE : Prepare space tracking information for debugging.\n" + " --tracking_nl FILE : Prepare newline tracking information for debugging.\n" + " Cannot be used with the -o option'\n" + "\n" + "Usage Examples\n" + "cat foo.d | uncrustify -q -c my.cfg -l d\n" + "uncrustify -c my.cfg -f foo.d\n" + "uncrustify -c my.cfg -f foo.d -L0-2,20-23,51\n" + "uncrustify -c my.cfg -f foo.d -o foo.d\n" + "uncrustify -c my.cfg -f foo.d -o foo.d -ds dump\n" + "uncrustify -c my.cfg foo.d\n" + "uncrustify -c my.cfg --replace foo.d\n" + "uncrustify -c my.cfg --no-backup foo.d\n" + "uncrustify -c my.cfg --prefix=out -F files.txt\n" + "\n" + "Note: Use comments containing ' *INDENT-OFF*' and ' *INDENT-ON*' to disable\n" + " processing of parts of the source file (these can be overridden with\n" + " enable_processing_cmt and disable_processing_cmt).\n" + "\n" + , + path_basename(argv0)); + tease(); +} // usage + + +static void version_exit() +{ + printf("%s\n", UNCRUSTIFY_VERSION); + exit(EX_OK); +} + + +NODISCARD static int redir_stdout(const char *output_file) +{ + FILE *my_stdout = stdout; // Reopen stdout + + if (output_file != nullptr) + { + my_stdout = freopen(output_file, "wb", stdout); + + if (my_stdout == nullptr) + { + LOG_FMT(LERR, "Unable to open %s for write: %s (%d)\n", + output_file, strerror(errno), errno); + usage_error(); + exit(EX_IOERR); + } + LOG_FMT(LNOTE, "Redirecting output to %s\n", output_file); + } + return(EXIT_SUCCESS); +} + +// Currently, the crash handler is only supported while building under MSVC +#if defined (WIN32) && defined (_MSC_VER) + + +void setup_crash_handling() +{ + // prevent crash popup. uncrustify is a batch processing tool and a popup is unacceptable. + ::SetErrorMode(::GetErrorMode() | SEM_NOGPFAULTERRORBOX); + + struct local + { + static LONG WINAPI crash_filter(_In_ struct _EXCEPTION_POINTERS *exceptionInfo) + { + __try + { + LOG_FMT(LERR, "crash_filter: exception 0x%08X at [%d:%d] (ip=%p)", + exceptionInfo->ExceptionRecord->ExceptionCode, + cpd.line_number, cpd.column, + exceptionInfo->ExceptionRecord->ExceptionAddress); + log_func_stack(LERR, " [CallStack:", "]\n", 0); + + // treat an exception the same as a parse failure. exceptions can result from parse failures where we + // do not have specific handling (null-checks for particular parse paths etc.) and callers generally + // won't care about the difference. they just want to know it failed. + exit(EXIT_FAILURE); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + // have to be careful of crashes in crash handling code + } + + // safety - note that this will not flush like we need, but at least will get the right return code + ::ExitProcess(EXIT_FAILURE); + } + }; + + // route all crashes through our own handler + ::SetUnhandledExceptionFilter(local::crash_filter); +} + +#else + + +void setup_crash_handling() +{ + // TODO: unixes +} + +#endif + + +int main(int argc, char *argv[]) +{ + // initialize the global data + cpd.unc_off_used = false; + + setup_crash_handling(); + + // Build options map + register_options(); + + // If ran without options show the usage info and exit */ + if (argc == 1) + { + usage(argv[0]); + return(EXIT_SUCCESS); + } +#ifdef DEBUG + // make sure we have 'name' not too big + const int max_name_length = 19; + + // maxLengthOfTheName must be consider at the format line at the file + // output.cpp, line 427: fprintf(pfile, "# Line Tag Parent... + // and 430: ... fprintf(pfile, "%s# %3zu>%19.19s[%19.19s] ... + // here xx xx xx xx + for (const auto &token_name : token_names) + { + const size_t name_length = strlen(token_name); + + if (name_length > max_name_length) + { + fprintf(stderr, "%s(%d): The token name '%s' is too long (%d)\n", + __func__, __LINE__, token_name, static_cast<int>(name_length)); + fprintf(stderr, "%s(%d): the max token name length is %d\n", + __func__, __LINE__, max_name_length); + log_flush(true); + exit(EX_SOFTWARE); + } + } + + // make sure we have token_names.h in sync with token_enum.h + static_assert(ARRAY_SIZE(token_names) == CT_TOKEN_COUNT_, ""); +#endif // DEBUG + + Args arg(argc, argv); + + if ( arg.Present("--version") + || arg.Present("-v")) + { + version_exit(); + } + + if ( arg.Present("--help") + || arg.Present("-h") + || arg.Present("--usage") + || arg.Present("-?")) + { + usage(argv[0]); + return(EXIT_SUCCESS); + } + + if (arg.Present("--count-options")) + { + tease(); + return(EXIT_SUCCESS); + } + + if (arg.Present("--show-config")) + { + save_option_file(stdout, true); + return(EXIT_SUCCESS); + } + cpd.do_check = arg.Present("--check"); + cpd.if_changed = arg.Present("--if-changed"); + +#ifdef WIN32 + // tell Windows not to change what I write to stdout + UNUSED(_setmode(_fileno(stdout), _O_BINARY)); +#endif + + // Init logging + log_init(cpd.do_check ? stdout : stderr); + log_mask_t mask; + + if (arg.Present("-q")) + { + logmask_from_string("", mask); + log_set_mask(mask); + } + const char *p_arg; + + if ( ((p_arg = arg.Param("-L")) != nullptr) + || ((p_arg = arg.Param("--log")) != nullptr)) + { + logmask_from_string(p_arg, mask); + log_set_mask(mask); + } + cpd.frag = arg.Present("--frag"); + + if (arg.Present("--decode")) + { + size_t idx = 1; + + while ((p_arg = arg.Unused(idx)) != nullptr) + { + log_pcf_flags(LSYS, static_cast<E_PcfFlag>(strtoul(p_arg, nullptr, 16))); + } + return(EXIT_SUCCESS); + } + // Get the config file name + string cfg_file; + + if ( ((p_arg = arg.Param("--config")) != nullptr) + || ((p_arg = arg.Param("-c")) != nullptr)) + { + cfg_file = p_arg; + } + else if (!unc_getenv("UNCRUSTIFY_CONFIG", cfg_file)) + { + // Try to find a config file at an alternate location + string home; + + if (unc_homedir(home)) + { + struct stat tmp_stat = {}; + + const auto path0 = home + "/.uncrustify.cfg"; + const auto path1 = home + "/uncrustify.cfg"; + + if (stat(path0.c_str(), &tmp_stat) == 0) + { + cfg_file = path0; + } + else if (stat(path1.c_str(), &tmp_stat) == 0) + { + cfg_file = path1; + } + } + } + // Get the parsed file name + const char *parsed_file; + + if ( ((parsed_file = arg.Param("--parsed")) != nullptr) + || ((parsed_file = arg.Param("-p")) != nullptr)) + { + if ( parsed_file[0] == '-' + && !parsed_file[1]) + { + LOG_FMT(LNOTE, "Will print parsed data to stdout\n"); + } + else + { + LOG_FMT(LNOTE, "Will export parsed data to: %s\n", parsed_file); + } + } + // Get the dump file name prefix + const char *dump_file; + + if ( ((dump_file = arg.Param("--dump-steps")) != nullptr) + || ((dump_file = arg.Param("-ds")) != nullptr)) + { + LOG_FMT(LNOTE, "Will export formatting steps data to '%s_nnn.log' files\n", dump_file); + } + + // Enable log severities + if ( arg.Present("-s") + || arg.Present("--show")) + { + log_show_sev(true); + } + // Load type files + size_t idx = 0; + + while ((p_arg = arg.Params("-t", idx)) != nullptr) + { + load_keyword_file(p_arg); + } + // add types + idx = 0; + + while ((p_arg = arg.Params("--type", idx)) != nullptr) + { + add_keyword(p_arg, CT_TYPE); + } + bool arg_l_is_set = false; + + // Check for a language override + if ((p_arg = arg.Param("-l")) != nullptr) + { + arg_l_is_set = true; + cpd.lang_flags = language_flags_from_name(p_arg); + + if (cpd.lang_flags == 0) + { + LOG_FMT(LWARN, "Ignoring unknown language: %s\n", p_arg); + } + else + { + cpd.lang_forced = true; + } + } + // Get the source file name + const char *source_file; + + if ( ((source_file = arg.Param("--file")) == nullptr) + && ((source_file = arg.Param("-f")) == nullptr)) + { + // not using a single file, source_file is nullptr + } + // Get a source file list + const char *source_list; + + if ( ((source_list = arg.Param("--files")) == nullptr) + && ((source_list = arg.Param("-F")) == nullptr)) + { + // not using a file list, source_list is nullptr + } + const char *prefix = arg.Param("--prefix"); + const char *suffix = arg.Param("--suffix"); + const char *assume = arg.Param("--assume"); + + bool no_backup = arg.Present("--no-backup"); + bool replace = arg.Present("--replace"); + bool keep_mtime = arg.Present("--mtime"); + bool update_config = arg.Present("--update-config"); + bool update_config_wd = arg.Present("--update-config-with-doc"); + bool detect = arg.Present("--detect"); + bool pfile_csv = arg.Present("--debug-csv-format"); + + std::string parsed_file_csv; + + if (pfile_csv) + { + if ( parsed_file == nullptr + || ( parsed_file[0] == '-' + && !parsed_file[1])) + { + fprintf(stderr, + "FAIL: --debug-csv-format option must be used in combination with '-p FILE', where FILE\n" + " is not set to '-'\n"); + log_flush(true); + exit(EX_CONFIG); + } + else if (!ends_with(parsed_file, ".csv", false)) + { + parsed_file_csv = parsed_file; + + // user-specified parsed filename does not end in a ".csv" extension, so add it + parsed_file_csv += ".csv"; + parsed_file = parsed_file_csv.c_str(); + } + } + // Grab the output override + const char *output_file = arg.Param("-o"); + + // for debugging tracking + const char *html_file = nullptr; + html_file = arg.Param("--tracking_space"); + + if (html_file != nullptr) + { + cpd.html_type = tracking_type_e::TT_SPACE; + cpd.html_file = html_file; + html_file = arg.Param("--tracking_nl"); + bool try_it = html_file != nullptr; + + if (try_it) + { + usage_error("Cannot specify both --tracking_space and --tracking_nl."); + return(EX_NOUSER); + } + } + else + { + html_file = arg.Param("--tracking_nl"); + bool try_it = html_file != nullptr; + + if (try_it) + { + cpd.html_type = tracking_type_e::TT_NEWLINE; + cpd.html_file = html_file; + } + } + LOG_FMT(LDATA, "%s\n", UNCRUSTIFY_VERSION); + LOG_FMT(LDATA, "config_file = %s\n", cfg_file.c_str()); + LOG_FMT(LDATA, "output_file = %s\n", (output_file != nullptr) ? output_file : "null"); + LOG_FMT(LDATA, "source_file = %s\n", (source_file != nullptr) ? source_file : "null"); + LOG_FMT(LDATA, "source_list = %s\n", (source_list != nullptr) ? source_list : "null"); + LOG_FMT(LDATA, "tracking = %s\n", (cpd.html_file != nullptr) ? cpd.html_file : "null"); + LOG_FMT(LDATA, "prefix = %s\n", (prefix != nullptr) ? prefix : "null"); + LOG_FMT(LDATA, "suffix = %s\n", (suffix != nullptr) ? suffix : "null"); + LOG_FMT(LDATA, "assume = %s\n", (assume != nullptr) ? assume : "null"); + LOG_FMT(LDATA, "replace = %s\n", replace ? "true" : "false"); + LOG_FMT(LDATA, "no_backup = %s\n", no_backup ? "true" : "false"); + LOG_FMT(LDATA, "detect = %s\n", detect ? "true" : "false"); + LOG_FMT(LDATA, "check = %s\n", cpd.do_check ? "true" : "false"); + LOG_FMT(LDATA, "if_changed = %s\n", cpd.if_changed ? "true" : "false"); + + if ( cpd.do_check + && ( output_file + || replace + || no_backup + || keep_mtime + || update_config + || update_config_wd + || detect + || prefix + || suffix + || cpd.if_changed)) + { + usage_error("Cannot use --check with output options."); + return(EX_NOUSER); + } + + if (!cpd.do_check) + { + if (replace) + { + if ( prefix != nullptr + || suffix != nullptr) + { + usage_error("Cannot use --replace with --prefix or --suffix"); + return(EX_NOINPUT); + } + + if ( source_file != nullptr + || output_file != nullptr) + { + usage_error("Cannot use --replace with -f or -o"); + return(EX_NOINPUT); + } + } + else if (!no_backup) + { + if ( prefix == nullptr + && suffix == nullptr) + { + suffix = ".uncrustify"; + } + } + } + + /* + * Try to load the config file, if available. + * It is optional for "--universalindent", "--parsed" and "--detect", but + * required for everything else. + */ + if ( !cfg_file.empty() + && cfg_file[0] != '-') + { + cpd.filename = cfg_file; + + if (!load_option_file(cpd.filename.c_str())) + { + usage_error("Unable to load the config file"); + return(EX_IOERR); + } + // test if all options are compatible to each other + log_rule_B("nl_max"); + + if (options::nl_max() > 0) + { + // test if one/some option(s) is/are not too big for that + log_rule_B("nl_var_def_blk_end_func_top"); + + if (options::nl_var_def_blk_end_func_top() >= options::nl_max()) + { + fprintf(stderr, "The option 'nl_var_def_blk_end_func_top' is too big against the option 'nl_max'\n"); + log_flush(true); + exit(EX_CONFIG); + } + } + } + // Set config options using command line arguments. + idx = 0; + + const size_t max_args_length = 256; + + while ((p_arg = arg.Params("--set", idx)) != nullptr) + { + size_t argLength = strlen(p_arg); + + if (argLength > max_args_length) + { + fprintf(stderr, "The buffer is to short for the set argument '%s'\n", p_arg); + log_flush(true); + exit(EX_SOFTWARE); + } + char buffer[max_args_length]; + strcpy(buffer, p_arg); + + // Tokenize and extract key and value + const char *token = strtok(buffer, "="); + const char *option = token; + + token = strtok(nullptr, "="); + const char *value = token; + + if ( option != nullptr + && value != nullptr + && strtok(nullptr, "=") == nullptr) // end of argument reached + { + if (auto *opt = uncrustify::find_option(option)) + { + if (!opt->read(value)) + { + return(EXIT_FAILURE); + } + } + else + { + fprintf(stderr, "Unknown option '%s' to override.\n", buffer); + log_flush(true); + return(EXIT_FAILURE); + } + } + else + { + // TODO: consider using defines like EX_USAGE from sysexits.h + usage_error("Error while parsing --set"); + return(EX_USAGE); + } + } + + if (arg.Present("--universalindent")) + { + FILE *pfile = stdout; + + if (output_file != nullptr) + { + pfile = fopen(output_file, "w"); + + if (pfile == nullptr) + { + fprintf(stderr, "Unable to open %s for write: %s (%d)\n", + output_file, strerror(errno), errno); + log_flush(true); + return(EXIT_FAILURE); + } + } + print_universal_indent_cfg(pfile); + fclose(pfile); + + return(EXIT_SUCCESS); + } + // Set the number of second(s) before terminating formatting the current file. +#ifdef WIN32 + if (options::debug_timeout() > 0) + { + fprintf(stderr, "The option 'debug_timeout' is not available under Windows.\n"); + log_flush(true); + exit(EX_SOFTWARE); + } +#else + if (options::debug_timeout() > 0) + { + alarm(options::debug_timeout()); + } +#endif // ifdef WIN32 + + if (detect) + { + file_mem fm; + + if ( source_file == nullptr + || source_list != nullptr) + { + fprintf(stderr, "The --detect option requires a single input file\n"); + log_flush(true); + return(EXIT_FAILURE); + } + + // Do some simple language detection based on the filename extension + if ( !cpd.lang_forced + || cpd.lang_flags == 0) + { + cpd.lang_flags = language_flags_from_filename(source_file); + } + + // Try to read in the source file + if (load_mem_file(source_file, fm) < 0) + { + LOG_FMT(LERR, "Failed to load (%s)\n", source_file); + exit(EX_IOERR); + } + uncrustify_start(fm.data); + detect_options(); + uncrustify_end(); + + if (auto error = redir_stdout(output_file)) + { + return(error); + } + save_option_file(stdout, update_config_wd); + return(EXIT_SUCCESS); + } + + if ( update_config + || update_config_wd) + { + // TODO: complain if file-processing related options are present + if (auto error = redir_stdout(output_file)) + { + return(error); + } + save_option_file(stdout, update_config_wd); + return(EXIT_SUCCESS); + } + + /* + * Everything beyond this point aside from dumping the parse tree is silly + * without a config file, so complain and bail if we don't have one. + */ + if ( cfg_file.empty() + && !parsed_file) + { + usage_error("Specify the config file with '-c file' or set UNCRUSTIFY_CONFIG"); + return(EX_IOERR); + } + // Done parsing args + + // Check for unused args (ignore them) + idx = 1; + p_arg = arg.Unused(idx); + + // Check args - for multifile options + if ( source_list != nullptr + || p_arg != nullptr) + { + if (source_file != nullptr) + { + usage_error("Cannot specify both the single file option and a multi-file option."); + return(EX_NOUSER); + } + + if (output_file != nullptr) + { + usage_error("Cannot specify -o with a multi-file option."); + return(EX_NOHOST); + } + } + // This relies on cpd.filename being the config file name + load_header_files(); + + if ( cpd.do_check + || cpd.if_changed) + { + cpd.bout = new deque<UINT8>(); + } + idx = 1; + + if ( source_file == nullptr + && source_list == nullptr + && arg.Unused(idx) == nullptr) + { + if (!arg_l_is_set) // Issue #3064 + { + if (assume == nullptr) + { + LOG_FMT(LERR, "If reading from stdin, you should specify the language using -l\n"); + LOG_FMT(LERR, "or specify a filename using --assume for automatic language detection.\n"); + return(EXIT_FAILURE); + } + } + + if (cpd.lang_flags == 0) + { + if (assume != nullptr) + { + cpd.lang_flags = language_flags_from_filename(assume); + } + else + { + cpd.lang_flags = LANG_C; + } + } + + if (!cpd.do_check) + { + if (auto error = redir_stdout(output_file)) + { + return(error); + } + } + file_mem fm; + + if (!read_stdin(fm)) + { + LOG_FMT(LERR, "Failed to read stdin\n"); + exit(EX_IOERR); + } + cpd.filename = "stdin"; + + // Done reading from stdin + LOG_FMT(LSYS, "%s(%d): Parsing: %zu bytes (%zu chars) from stdin as language %s\n", + __func__, __LINE__, fm.raw.size(), fm.data.size(), + language_name_from_flags(cpd.lang_flags)); + + // Issue #3427 + init_keywords_for_language(); + uncrustify_file(fm, stdout, parsed_file, dump_file); + } + else if (source_file != nullptr) + { + // Doing a single file + do_source_file(source_file, output_file, parsed_file, dump_file, no_backup, keep_mtime); + } + else + { + if (parsed_file != nullptr) // Issue #930 + { + fprintf(stderr, "FAIL: -p option must be used with the -f option\n"); + log_flush(true); + exit(EX_CONFIG); + } + + if (dump_file != nullptr) + { + fprintf(stderr, "FAIL: -ds/--dump-steps option must be used with the -f option\n"); + log_flush(true); + exit(EX_CONFIG); + } + + // Doing multiple files, TODO: multiple threads for parallel processing + if (prefix != nullptr) + { + LOG_FMT(LSYS, "Output prefix: %s/\n", prefix); + } + + if (suffix != nullptr) + { + LOG_FMT(LSYS, "Output suffix: %s\n", suffix); + } + // Do the files on the command line first + idx = 1; + + while ((p_arg = arg.Unused(idx)) != nullptr) + { + char outbuf[1024]; + do_source_file(p_arg, + make_output_filename(outbuf, sizeof(outbuf), p_arg, prefix, suffix), + nullptr, nullptr, no_backup, keep_mtime); + } + + if (source_list != nullptr) + { + process_source_list(source_list, prefix, suffix, no_backup, keep_mtime); + } + } + clear_keyword_file(); + + if ( cpd.do_check + && cpd.check_fail_cnt != 0) + { + return(EXIT_FAILURE); + } + return(EXIT_SUCCESS); +} // main + + +static void process_source_list(const char *source_list, + const char *prefix, const char *suffix, + bool no_backup, bool keep_mtime) +{ + bool from_stdin = strcmp(source_list, "-") == 0; + FILE *p_file = from_stdin ? stdin : fopen(source_list, "r"); + + if (p_file == nullptr) + { + LOG_FMT(LERR, "%s: fopen(%s) failed: %s (%d)\n", + __func__, source_list, strerror(errno), errno); + exit(EX_IOERR); + } + char linebuf[256]; + int line = 0; + + while (fgets(linebuf, sizeof(linebuf), p_file) != nullptr) + { + line++; + char *fname = linebuf; + int len = strlen(fname); + + while ( len > 0 + && unc_isspace(*fname)) + { + fname++; + len--; + } + + while ( len > 0 + && unc_isspace(fname[len - 1])) + { + len--; + } + fname[len] = 0; + + while (len-- > 0) + { + if (fname[len] == '\\') + { + fname[len] = '/'; + } + } + LOG_FMT(LFILELIST, "%3d file to uncrustify: %s\n", line, fname); + + if (fname[0] != '#') + { + char outbuf[1024]; + do_source_file(fname, + make_output_filename(outbuf, sizeof(outbuf), fname, prefix, suffix), + nullptr, nullptr, no_backup, keep_mtime); + } + } + + if (!from_stdin) + { + fclose(p_file); + } +} // process_source_list + + +static bool read_stdin(file_mem &fm) +{ + deque<UINT8> dq; + char buf[4096]; + + fm.raw.clear(); + fm.data.clear(); + fm.enc = char_encoding_e::e_ASCII; + + // Re-open stdin in binary mode to preserve newline characters +#ifdef WIN32 + _setmode(_fileno(stdin), _O_BINARY); +#endif + + while (!feof(stdin)) + { + int len = fread(buf, 1, sizeof(buf), stdin); + + for (int idx = 0; idx < len; idx++) + { + dq.push_back(buf[idx]); + } + } + // Copy the raw data from the deque to the vector + fm.raw.insert(fm.raw.end(), dq.begin(), dq.end()); + return(decode_unicode(fm.raw, fm.data, fm.enc, fm.bom)); +} + + +static void make_folders(const string &filename) +{ + int last_idx = 0; + char outname[4096]; + + snprintf(outname, sizeof(outname), "%s", filename.c_str()); + + for (int idx = 0; outname[idx] != 0; idx++) + { + if ( (outname[idx] == '/') + || (outname[idx] == '\\')) + { + outname[idx] = PATH_SEP; + } + + // search until end of subpath is found + if ( idx > last_idx + && (outname[idx] == PATH_SEP)) + { + outname[idx] = 0; // mark the end of the subpath + + // create subfolder if it is not the start symbol of a path + // and not a Windows drive letter + if ( (strcmp(&outname[last_idx], ".") != 0) + && (strcmp(&outname[last_idx], "..") != 0) + && (!( last_idx == 0 + && idx == 2 + && outname[1] == ':'))) + { + int status; // Coverity CID 75999 + status = mkdir(outname, 0750); + + if ( status != 0 + && errno != EEXIST) + { + LOG_FMT(LERR, "%s: Unable to create %s: %s (%d)\n", + __func__, outname, strerror(errno), errno); + exit(EX_IOERR); + } + } + outname[idx] = PATH_SEP; // reconstruct full path to search for next subpath + } + + if (outname[idx] == PATH_SEP) + { + last_idx = idx + 1; + } + } +} // make_folders + + +static int load_mem_file(const char *filename, file_mem &fm) +{ + int retval = -1; + struct stat my_stat; + FILE *p_file; + + fm.raw.clear(); + fm.data.clear(); + fm.enc = char_encoding_e::e_ASCII; + + // Grab the stat info for the file, return if it cannot be read + if (stat(filename, &my_stat) < 0) + { + return(-1); + } +#ifdef HAVE_UTIME_H + // Save off modification time (mtime) + fm.utb.modtime = my_stat.st_mtime; +#endif + + // Try to read in the file + p_file = fopen(filename, "rb"); + + if (p_file == nullptr) + { + return(-1); + } + fm.raw.resize(my_stat.st_size); + + if (my_stat.st_size == 0) // check if file is empty + { + retval = 0; + fm.bom = false; + fm.enc = char_encoding_e::e_ASCII; + fm.data.clear(); + } + else + { + // read the raw data + if (fread(&fm.raw[0], fm.raw.size(), 1, p_file) != 1) + { + LOG_FMT(LERR, "%s: fread(%s) failed: %s (%d)\n", + __func__, filename, strerror(errno), errno); + exit(EX_IOERR); + } + else if (!decode_unicode(fm.raw, fm.data, fm.enc, fm.bom)) + { + LOG_FMT(LERR, "%s: failed to decode the file '%s'\n", __func__, filename); + exit(EX_IOERR); + } + else + { + LOG_FMT(LNOTE, "%s: '%s' encoding looks like %s (%d)\n", __func__, filename, + fm.enc == char_encoding_e::e_ASCII ? "ASCII" : + fm.enc == char_encoding_e::e_BYTE ? "BYTES" : + fm.enc == char_encoding_e::e_UTF8 ? "UTF-8" : + fm.enc == char_encoding_e::e_UTF16_LE ? "UTF-16-LE" : + fm.enc == char_encoding_e::e_UTF16_BE ? "UTF-16-BE" : "Error", + (int)fm.enc); + retval = 0; + } + } + fclose(p_file); + return(retval); +} // load_mem_file + + +static int load_mem_file_config(const std::string &filename, file_mem &fm) +{ + int retval; + char buf[1024]; + + snprintf(buf, sizeof(buf), "%.*s%s", + path_dirname_len(cpd.filename.c_str()), cpd.filename.c_str(), filename.c_str()); + + retval = load_mem_file(buf, fm); + + if (retval < 0) + { + retval = load_mem_file(filename.c_str(), fm); + + if (retval < 0) + { + LOG_FMT(LERR, "Failed to load (%s) or (%s)\n", buf, filename.c_str()); + exit(EX_IOERR); + } + } + return(retval); +} + + +int load_header_files() +{ + int retval = 0; + + log_rule_B("cmt_insert_file_header"); + + if (!options::cmt_insert_file_header().empty()) + { + // try to load the file referred to by the options string + retval |= load_mem_file_config(options::cmt_insert_file_header(), + cpd.file_hdr); + } + log_rule_B("cmt_insert_file_footer"); + + if (!options::cmt_insert_file_footer().empty()) + { + retval |= load_mem_file_config(options::cmt_insert_file_footer(), + cpd.file_ftr); + } + log_rule_B("cmt_insert_func_header"); + + if (!options::cmt_insert_func_header().empty()) + { + retval |= load_mem_file_config(options::cmt_insert_func_header(), + cpd.func_hdr); + } + log_rule_B("cmt_insert_class_header"); + + if (!options::cmt_insert_class_header().empty()) + { + retval |= load_mem_file_config(options::cmt_insert_class_header(), + cpd.class_hdr); + } + log_rule_B("cmt_insert_oc_msg_header"); + + if (!options::cmt_insert_oc_msg_header().empty()) + { + retval |= load_mem_file_config(options::cmt_insert_oc_msg_header(), + cpd.oc_msg_hdr); + } + log_rule_B("cmt_reflow_fold_regex_file"); + + if (!options::cmt_reflow_fold_regex_file().empty()) + { + retval |= load_mem_file_config(options::cmt_reflow_fold_regex_file(), + cpd.reflow_fold_regex); + } + return(retval); +} // load_header_files + + +static const char *make_output_filename(char *buf, size_t buf_size, + const char *filename, + const char *prefix, + const char *suffix) +{ + int len = 0; + + if (prefix != nullptr) + { + len = snprintf(buf, buf_size, "%s/", prefix); + } + snprintf(&buf[len], buf_size - len, "%s%s", filename, + (suffix != nullptr) ? suffix : ""); + + return(buf); +} + + +static bool file_content_matches(const string &filename1, const string &filename2) +{ + struct stat st1, st2; + int fd1, fd2; + + // Check the file sizes first + if ( (stat(filename1.c_str(), &st1) != 0) + || (stat(filename2.c_str(), &st2) != 0) + || st1.st_size != st2.st_size) + { + return(false); + } + + if ((fd1 = open(filename1.c_str(), O_RDONLY)) < 0) + { + return(false); + } + + if ((fd2 = open(filename2.c_str(), O_RDONLY)) < 0) + { + close(fd1); + return(false); + } + int len1 = 0; + int len2 = 0; + UINT8 buf1[1024]; + UINT8 buf2[1024]; + + memset(buf1, 0, sizeof(buf1)); + memset(buf2, 0, sizeof(buf2)); + + while ( len1 >= 0 + && len2 >= 0) + { + if (len1 == 0) + { + len1 = read(fd1, buf1, sizeof(buf1)); + } + + if (len2 == 0) + { + len2 = read(fd2, buf2, sizeof(buf2)); + } + + if ( len1 <= 0 + || len2 <= 0) + { + break; // reached end of either files + // TODO: what is if one file is longer than the other, do we miss that ? + } + int minlen = (len1 < len2) ? len1 : len2; + + if (memcmp(buf1, buf2, minlen) != 0) + { + break; // found a difference + } + len1 -= minlen; + len2 -= minlen; + } + close(fd1); + close(fd2); + + return( len1 == 0 + && len2 == 0); +} // file_content_matches + + +static string fix_filename(const char *filename) +{ + char *tmp_file; + string rv; + + // Create 'outfile.uncrustify' + tmp_file = new char[strlen(filename) + 16 + 1]; // + 1 for '// + 1 for '/* + 1 for '\0' */' ' + + if (tmp_file != nullptr) + { + sprintf(tmp_file, "%s.uncrustify", filename); + } + rv = tmp_file; + delete[] tmp_file; + return(rv); +} + + +static bool bout_content_matches(const file_mem &fm, bool report_status) +{ + bool is_same = true; + + // compare the old data vs the new data + if (cpd.bout->size() != fm.raw.size()) + { + if (report_status) + { + fprintf(stderr, "FAIL: %s (File size changed from %u to %u)\n", + cpd.filename.c_str(), static_cast<int>(fm.raw.size()), + static_cast<int>(cpd.bout->size())); + log_flush(true); + } + is_same = false; + } + else + { + for (int idx = 0; idx < static_cast<int>(fm.raw.size()); idx++) + { + if (fm.raw[idx] != (*cpd.bout)[idx]) + { + if (report_status) + { + fprintf(stderr, "FAIL: %s (Difference at byte %u)\n", + cpd.filename.c_str(), idx); + log_flush(true); + } + is_same = false; + break; + } + } + } + + if ( is_same + && report_status) + { + fprintf(stdout, "PASS: %s (%u bytes)\n", + cpd.filename.c_str(), static_cast<int>(fm.raw.size())); + } + return(is_same); +} // bout_content_matches + + +static void do_source_file(const char *filename_in, + const char *filename_out, + const char *parsed_file, + const char *dump_file, + bool no_backup, + bool keep_mtime) +{ + FILE *pfout = nullptr; + bool did_open = false; + bool need_backup = false; + file_mem fm; + string filename_tmp; + + // Do some simple language detection based on the filename extension + if ( !cpd.lang_forced + || cpd.lang_flags == 0) + { + cpd.lang_flags = language_flags_from_filename(filename_in); + } + + // Try to read in the source file + if (load_mem_file(filename_in, fm) < 0) + { + LOG_FMT(LERR, "Failed to load (%s)\n", filename_in); + exit(EX_IOERR); + } + LOG_FMT(LSYS, "%s(%d): Parsing: %s as language %s\n", + __func__, __LINE__, filename_in, language_name_from_flags(cpd.lang_flags)); + + // check keyword sort + assert(keywords_are_sorted()); + + // Issue #3353 + init_keywords_for_language(); + + cpd.filename = filename_in; + + /* + * If we're only going to write on an actual change, then build the output + * buffer now and if there were changes, run it through the normal file + * write path. + * + * Future: many code paths could be simplified if 'bout' were always used and not + * optionally selected in just for do_check and if_changed. + */ + if (cpd.if_changed) + { + /* + * Cleanup is deferred because we need 'bout' preserved long enough + * to write it to a file (if it changed). + */ + uncrustify_file(fm, nullptr, parsed_file, dump_file, true); + + if (bout_content_matches(fm, false)) + { + uncrustify_end(); + return; + } + } + + if (!cpd.do_check) + { + if (filename_out == nullptr) + { + pfout = stdout; + } + else + { + // If the out file is the same as the in file, then use a temp file + filename_tmp = filename_out; + + if (strcmp(filename_in, filename_out) == 0) + { + // Create 'outfile.uncrustify' + filename_tmp = fix_filename(filename_out); + + if (!no_backup) + { + if (backup_copy_file(filename_in, fm.raw) != EX_OK) + { + LOG_FMT(LERR, "%s: Failed to create backup file for %s\n", + __func__, filename_in); + exit(EX_IOERR); + } + need_backup = true; + } + } + make_folders(filename_tmp); + + pfout = fopen(filename_tmp.c_str(), "wb"); + + if (pfout == nullptr) + { + LOG_FMT(LERR, "%s: Unable to create %s: %s (%d)\n", + __func__, filename_tmp.c_str(), strerror(errno), errno); + exit(EX_IOERR); + } + did_open = true; + //LOG_FMT(LSYS, "Output file %s\n", filename_out); + } + } + + if (cpd.if_changed) + { + for (UINT8 i : *cpd.bout) + { + fputc(i, pfout); + } + + uncrustify_end(); + } + else + { + uncrustify_file(fm, pfout, parsed_file, dump_file); + } + + if (did_open) + { + fclose(pfout); + + if (need_backup) + { + backup_create_md5_file(filename_in); + } + + if (filename_tmp != filename_out) + { + // We need to compare and then do a rename (but avoid redundant test when if_changed set) + if ( !cpd.if_changed + && file_content_matches(filename_tmp, filename_out)) + { + // No change - remove tmp file + UNUSED(unlink(filename_tmp.c_str())); + } + else + { + // Change - rename filename_tmp to filename_out + +#ifdef WIN32 + /* + * Atomic rename in windows can't go through stdio rename() func because underneath + * it calls MoveFileExW without MOVEFILE_REPLACE_EXISTING. + */ + if (!MoveFileEx(filename_tmp.c_str(), filename_out, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED)) +#else + if (rename(filename_tmp.c_str(), filename_out) != 0) +#endif + { + LOG_FMT(LERR, "%s: Unable to rename '%s' to '%s'\n", + __func__, filename_tmp.c_str(), filename_out); + exit(EX_IOERR); + } + } + } + + if (keep_mtime) + { +#ifdef HAVE_UTIME_H + // update mtime -- don't care if it fails + fm.utb.actime = time(nullptr); + UNUSED(utime(filename_in, &fm.utb)); +#endif + } + } +} // do_source_file + + +static void add_file_header() +{ + // don't add the file header if running as frag + if ( !Chunk::GetHead()->IsComment() + && !cpd.frag) + { + // TODO: detect the typical #ifndef FOO / #define FOO sequence + tokenize(cpd.file_hdr.data, Chunk::GetHead()); + } +} + + +static void add_file_footer() +{ + Chunk *pc = Chunk::GetTail(); + + // Back up if the file ends with a newline + if ( pc->IsNotNullChunk() + && pc->IsNewline()) + { + pc = pc->GetPrev(); + } + + if ( pc->IsNotNullChunk() + && ( !pc->IsComment() + || !pc->GetPrev()->IsNewline())) + { + pc = Chunk::GetTail(); + + if (!pc->IsNewline()) + { + LOG_FMT(LSYS, "Adding a newline at the end of the file\n"); + newline_add_after(pc); + } + tokenize(cpd.file_ftr.data, nullptr); + } +} + + +static void add_func_header(E_Token type, file_mem &fm) +{ + Chunk *pc; + Chunk *ref; + Chunk *tmp; + bool do_insert; + + for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnlNpp()) + { + if (pc->GetType() != type) + { + continue; + } + log_rule_B("cmt_insert_before_inlines"); + + if ( pc->TestFlags(PCF_IN_CLASS) + && !options::cmt_insert_before_inlines()) + { + continue; + } + // Check for one liners for classes. Declarations only. Walk down the chunks. + ref = pc; + + if ( ref->Is(CT_CLASS) + && ref->GetParentType() == CT_NONE + && ref->GetNext()) + { + ref = ref->GetNext(); + + if ( ref->Is(CT_TYPE) + && ref->GetParentType() == type + && ref->GetNext()) + { + ref = ref->GetNext(); + + if ( ref->Is(CT_SEMICOLON) + && ref->GetLevel() == pc->GetLevel()) + { + continue; + } + } + } + // Check for one liners for functions. There'll be a closing brace w/o any newlines. Walk down the chunks. + ref = pc; + + if ( ref->Is(CT_FUNC_DEF) + && ref->GetParentType() == CT_NONE + && ref->GetNext()) + { + int found_brace = 0; // Set if a close brace is found before a newline + + while ( ref->IsNot(CT_NEWLINE) + && (ref = ref->GetNext())) // TODO: is the assignment of ref wanted here?, better move it to the loop + { + if (ref->Is(CT_BRACE_CLOSE)) + { + found_brace = 1; + break; + } + } + + if (found_brace) + { + continue; + } + } + do_insert = false; + + /* + * On a function proto or def. Back up to a close brace or semicolon on + * the same level + */ + ref = pc; + + while ( (ref = ref->GetPrev()) + && ref->IsNotNullChunk()) + { + // Bail if we change level or find an access specifier colon + if ( ref->GetLevel() != pc->GetLevel() + || ref->Is(CT_ACCESS_COLON)) + { + do_insert = true; + break; + } + + // If we hit an angle close, back up to the angle open + if (ref->Is(CT_ANGLE_CLOSE)) + { + ref = ref->GetPrevType(CT_ANGLE_OPEN, ref->GetLevel(), E_Scope::PREPROC); + continue; + } + + // Bail if we hit a preprocessor and cmt_insert_before_preproc is false + if (ref->TestFlags(PCF_IN_PREPROC)) + { + tmp = ref->GetPrevType(CT_PREPROC, ref->GetLevel()); + + if ( tmp->IsNotNullChunk() + && tmp->GetParentType() == CT_PP_IF) + { + tmp = tmp->GetPrevNnl(); + + log_rule_B("cmt_insert_before_preproc"); + + if ( tmp->IsComment() + && !options::cmt_insert_before_preproc()) + { + break; + } + } + } + + // Ignore 'right' comments + if ( ref->IsComment() + && ref->GetPrev()->IsNewline()) + { + break; + } + + if ( ref->GetLevel() == pc->GetLevel() + && ( ref->TestFlags(PCF_IN_PREPROC) + || ref->Is(CT_SEMICOLON) + || ref->Is(CT_BRACE_CLOSE))) + { + do_insert = true; + break; + } + } + + if ( ref->IsNullChunk() + && !Chunk::GetHead()->IsComment() + && Chunk::GetHead()->GetParentType() == type) + { + /** + * In addition to testing for preceding semicolons, closing braces, etc., + * we need to also account for the possibility that the function declaration + * or definition occurs at the very beginning of the file + */ + tokenize(fm.data, Chunk::GetHead()); + } + else if (do_insert) + { + // Insert between after and ref + Chunk *after = ref->GetNextNcNnl(); + tokenize(fm.data, after); + + for (tmp = ref->GetNext(); tmp != after; tmp = tmp->GetNext()) + { + tmp->SetLevel(after->GetLevel()); + } + } + } +} // add_func_header + + +static void add_msg_header(E_Token type, file_mem &fm) +{ + Chunk *pc; + Chunk *ref; + Chunk *tmp; + bool do_insert; + + for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnlNpp()) + { + if (pc->GetType() != type) + { + continue; + } + do_insert = false; + + /* + * On a message declaration back up to a Objective-C scope + * the same level + */ + ref = pc; + + while ((ref = ref->GetPrev())->IsNotNullChunk()) + { + // ignore the CT_TYPE token that is the result type + if ( ref->GetLevel() != pc->GetLevel() + && ( ref->Is(CT_TYPE) + || ref->Is(CT_PTR_TYPE))) + { + continue; + } + + // If we hit a parentheses around return type, back up to the open parentheses + if (ref->Is(CT_PAREN_CLOSE)) + { + ref = ref->GetPrevType(CT_PAREN_OPEN, ref->GetLevel(), E_Scope::PREPROC); + continue; + } + + // Bail if we hit a preprocessor and cmt_insert_before_preproc is false + if (ref->TestFlags(PCF_IN_PREPROC)) + { + tmp = ref->GetPrevType(CT_PREPROC, ref->GetLevel()); + + if ( tmp->IsNotNullChunk() + && tmp->GetParentType() == CT_PP_IF) + { + tmp = tmp->GetPrevNnl(); + + log_rule_B("cmt_insert_before_preproc"); + + if ( tmp->IsComment() + && !options::cmt_insert_before_preproc()) + { + break; + } + } + } + + if ( ref->GetLevel() == pc->GetLevel() + && ( ref->TestFlags(PCF_IN_PREPROC) + || ref->Is(CT_OC_SCOPE))) + { + ref = ref->GetPrev(); + + if (ref->IsNotNullChunk()) + { + // Ignore 'right' comments + if ( ref->IsNewline() + && ref->GetPrev()->IsComment()) + { + break; + } + do_insert = true; + } + break; + } + } + + if (do_insert) + { + // Insert between after and ref + Chunk *after = ref->GetNextNcNnl(); + tokenize(fm.data, after); + + for (tmp = ref->GetNext(); tmp != after; tmp = tmp->GetNext()) + { + tmp->SetLevel(after->GetLevel()); + } + } + } +} // add_msg_header + + +static void uncrustify_start(const deque<int> &data) +{ + // Parse the text into chunks + tokenize(data, nullptr); + PROT_THE_LINE + + cpd.unc_stage = unc_stage_e::HEADER; + + // Get the column for the fragment indent + if (cpd.frag) + { + Chunk *pc = Chunk::GetHead(); + + cpd.frag_cols = pc->GetOrigCol(); + } + + // Add the file header + if (!cpd.file_hdr.data.empty()) + { + add_file_header(); + } + + // Add the file footer + if (!cpd.file_ftr.data.empty()) + { + add_file_footer(); + } + /* + * Change certain token types based on simple sequence. + * Example: change '[' + ']' to '[]' + * Note that level info is not yet available, so it is OK to do all + * processing that doesn't need to know level info. (that's very little!) + */ + tokenize_cleanup(); + + /* + * Detect the brace and paren levels and insert virtual braces. + * This handles all that nasty preprocessor stuff + */ + brace_cleanup(); + + parameter_pack_cleanup(); + + // At this point, the level information is available and accurate. + + if (language_is_set(LANG_PAWN)) + { + pawn_prescan(); + } + mark_question_colon(); + + // Re-type chunks, combine chunks + fix_symbols(); + + tokenize_trailing_return_types(); + + mark_comments(); + + // Look at all colons ':' and mark labels, :? sequences, etc. + combine_labels(); + + enum_cleanup(); +} // uncrustify_start + + +void uncrustify_file(const file_mem &fm, FILE *pfout, const char *parsed_file, + const char *dump_file, bool defer_uncrustify_end) +{ + const deque<int> &data = fm.data; + + // Save off the encoding and whether a BOM is required + cpd.bom = fm.bom; + cpd.enc = fm.enc; + + log_rule_B("utf8_force"); + log_rule_B("utf8_byte"); + + if ( options::utf8_force() + || ( (cpd.enc == char_encoding_e::e_BYTE) + && options::utf8_byte())) + { + cpd.enc = char_encoding_e::e_UTF8; + } + iarf_e av; + + switch (cpd.enc) + { + case char_encoding_e::e_UTF8: + log_rule_B("utf8_bom"); + av = options::utf8_bom(); + break; + + case char_encoding_e::e_UTF16_LE: + case char_encoding_e::e_UTF16_BE: + av = IARF_FORCE; + break; + + default: + av = IARF_IGNORE; + break; + } + + if (av == IARF_REMOVE) + { + cpd.bom = false; + } + else if (av != IARF_IGNORE) + { + cpd.bom = true; + } + // Check for embedded 0's (represents a decoding failure or corrupt file) + size_t count_line = 1; + size_t count_column = 1; + + for (int idx = 0; idx < static_cast<int>(data.size()) - 1; idx++) + { + if (data[idx] == 0) + { + LOG_FMT(LERR, "An embedded 0 was found in '%s' %zu:%zu.\n", + cpd.filename.c_str(), count_line, count_column); + LOG_FMT(LERR, "The file may be encoded in an unsupported Unicode format.\n"); + LOG_FMT(LERR, "Aborting.\n"); + exit(EX_IOERR); + } + count_column++; + + if (data[idx] == '\n') + { + count_line++; + count_column = 1; + } + } + + uncrustify_start(data); + dump_step(dump_file, "After uncrustify_start()"); + + cpd.unc_stage = unc_stage_e::OTHER; + + /* + * Done with detection. Do the rest only if the file will go somewhere. + * The detection code needs as few changes as possible. + */ + { + // Add comments before function defs and classes + if (!cpd.func_hdr.data.empty()) + { + add_func_header(CT_FUNC_DEF, cpd.func_hdr); + + log_rule_B("cmt_insert_before_ctor_dtor"); + + if (options::cmt_insert_before_ctor_dtor()) + { + add_func_header(CT_FUNC_CLASS_DEF, cpd.func_hdr); + } + } + + if (!cpd.class_hdr.data.empty()) + { + add_func_header(CT_CLASS, cpd.class_hdr); + } + + if (!cpd.oc_msg_hdr.data.empty()) + { + add_msg_header(CT_OC_MSG_DECL, cpd.oc_msg_hdr); + } + do_parent_for_pp(); + + // Rewrite infinite loops + log_rule_B("mod_infinite_loop"); + + if (options::mod_infinite_loop()) + { + rewrite_infinite_loops(); + } + do_braces(); // Change virtual braces into real braces... + + // Scrub extra semicolons + log_rule_B("mod_remove_extra_semicolon"); + + if (options::mod_remove_extra_semicolon()) + { + remove_extra_semicolons(); + } + // Remove unnecessary returns + log_rule_B("mod_remove_empty_return"); + + if (options::mod_remove_empty_return()) + { + remove_extra_returns(); + } + // Add or remove redundant 'int' keyword of integer types + log_rule_B("mod_int_short"); + log_rule_B("mod_short_int"); + log_rule_B("mod_int_long"); + log_rule_B("mod_long_int"); + log_rule_B("mod_int_signed"); + log_rule_B("mod_signed_int"); + log_rule_B("mod_int_unsigned"); + log_rule_B("mod_unsigned_int"); + + if ( ( language_is_set(LANG_C) + || language_is_set(LANG_CPP)) + && ( options::mod_int_short() != IARF_IGNORE + || options::mod_short_int() != IARF_IGNORE + || options::mod_int_long() != IARF_IGNORE + || options::mod_long_int() != IARF_IGNORE + || options::mod_int_signed() != IARF_IGNORE + || options::mod_signed_int() != IARF_IGNORE + || options::mod_int_unsigned() != IARF_IGNORE + || options::mod_unsigned_int() != IARF_IGNORE)) + { + change_int_types(); + } + // Remove duplicate include + log_rule_B("mod_remove_duplicate_include"); + + if (options::mod_remove_duplicate_include()) + { + remove_duplicate_include(); + } + // Add parens + do_parens(); + do_parens_assign(); + do_parens_return(); + + // Modify line breaks as needed + bool first = true; + int old_changes; + + log_rule_B("nl_remove_extra_newlines"); + + if (options::nl_remove_extra_newlines() == 2) + { + newlines_remove_newlines(); + } + cpd.pass_count = 3; + + dump_step(dump_file, "Before first while loop"); + + do + { + old_changes = cpd.changes; + + LOG_FMT(LNEWLINE, "Newline loop start: %d\n", cpd.changes); + + annotations_newlines(); + newlines_cleanup_dup(); + newlines_sparens(); + newlines_cleanup_braces(first); + newlines_cleanup_angles(); // Issue #1167 + + log_rule_B("nl_after_multiline_comment"); + + if (options::nl_after_multiline_comment()) + { + newline_after_multiline_comment(); + } + log_rule_B("nl_after_label_colon"); + + if (options::nl_after_label_colon()) + { + newline_after_label_colon(); + } + newlines_insert_blank_lines(); + + log_rule_B("pos_bool"); + + if (options::pos_bool() != TP_IGNORE) + { + newlines_chunk_pos(CT_BOOL, options::pos_bool()); + } + log_rule_B("pos_compare"); + + if (options::pos_compare() != TP_IGNORE) + { + newlines_chunk_pos(CT_COMPARE, options::pos_compare()); + } + log_rule_B("pos_conditional"); + + if (options::pos_conditional() != TP_IGNORE) + { + newlines_chunk_pos(CT_COND_COLON, options::pos_conditional()); + newlines_chunk_pos(CT_QUESTION, options::pos_conditional()); + } + log_rule_B("pos_comma"); + log_rule_B("pos_enum_comma"); + + if ( options::pos_comma() != TP_IGNORE + || options::pos_enum_comma() != TP_IGNORE) + { + newlines_chunk_pos(CT_COMMA, options::pos_comma()); + } + log_rule_B("pos_assign"); + + if (options::pos_assign() != TP_IGNORE) + { + newlines_chunk_pos(CT_ASSIGN, options::pos_assign()); + } + log_rule_B("pos_arith"); + + if (options::pos_arith() != TP_IGNORE) + { + newlines_chunk_pos(CT_ARITH, options::pos_arith()); + newlines_chunk_pos(CT_CARET, options::pos_arith()); + } + log_rule_B("pos_shift"); + + if (options::pos_shift() != TP_IGNORE) + { + newlines_chunk_pos(CT_SHIFT, options::pos_shift()); + } + newlines_class_colon_pos(CT_CLASS_COLON); + newlines_class_colon_pos(CT_CONSTR_COLON); + + log_rule_B("nl_squeeze_ifdef"); + + if (options::nl_squeeze_ifdef()) + { + newlines_squeeze_ifdef(); + } + log_rule_B("nl_squeeze_paren_close"); + + if (options::nl_squeeze_paren_close()) + { + newlines_squeeze_paren_close(); + } +//prot_the_line(__func__, __LINE__, 15, 4); + do_blank_lines(); +//prot_the_line(__func__, __LINE__, 15, 4); + newlines_eat_start_end(); + newlines_functions_remove_extra_blank_lines(); + newlines_cleanup_dup(); + first = false; + dump_step(dump_file, "Inside first while loop"); + } while ( old_changes != cpd.changes + && cpd.pass_count-- > 0); + + mark_comments(); + + // Add balanced spaces around nested params + log_rule_B("sp_balance_nested_parens"); + + if (options::sp_balance_nested_parens()) + { + space_text_balance_nested_parens(); + } + // Scrub certain added semicolons + log_rule_B("mod_pawn_semicolon"); + + if ( language_is_set(LANG_PAWN) + && options::mod_pawn_semicolon()) + { + pawn_scrub_vsemi(); + } + // Sort imports/using/include + log_rule_B("mod_sort_import"); + log_rule_B("mod_sort_include"); + log_rule_B("mod_sort_using"); + + if ( options::mod_sort_import() + || options::mod_sort_include() + || options::mod_sort_using()) + { + sort_imports(); + } + // Fix same-line inter-chunk spacing + space_text(); + + // Do any aligning of preprocessors + log_rule_B("align_pp_define_span"); + + if (options::align_pp_define_span() > 0) + { + align_preprocessor(); + } + // Indent the text + indent_preproc(); + indent_text(); + + // Insert trailing comments after certain close braces + log_rule_B("mod_add_long_switch_closebrace_comment"); + log_rule_B("mod_add_long_function_closebrace_comment"); + log_rule_B("mod_add_long_class_closebrace_comment"); + log_rule_B("mod_add_long_namespace_closebrace_comment"); + + if ( (options::mod_add_long_switch_closebrace_comment() > 0) + || (options::mod_add_long_function_closebrace_comment() > 0) + || (options::mod_add_long_class_closebrace_comment() > 0) + || (options::mod_add_long_namespace_closebrace_comment() > 0)) + { + add_long_closebrace_comment(); + } + // Insert trailing comments after certain preprocessor conditional blocks + log_rule_B("mod_add_long_ifdef_else_comment"); + log_rule_B("mod_add_long_ifdef_endif_comment"); + + if ( (options::mod_add_long_ifdef_else_comment() > 0) + || (options::mod_add_long_ifdef_endif_comment() > 0)) + { + add_long_preprocessor_conditional_block_comment(); + } + // Align everything else, reindent and break at code_width + first = true; + + dump_step(dump_file, "Before second while loop"); + + do + { + align_all(); + indent_text(); + old_changes = cpd.changes; + + log_rule_B("code_width"); + + if (options::code_width() > 0) + { + LOG_FMT(LNEWLINE, "%s(%d): Code_width loop start: %d\n", + __func__, __LINE__, cpd.changes); + log_rule_B("debug_max_number_of_loops"); + + if (options::debug_max_number_of_loops() > 0) + { + if (cpd.changes > options::debug_max_number_of_loops()) // Issue #2432 + { + LOG_FMT(LNEWLINE, "%s(%d): too many loops. Make a report, please.\n", + __func__, __LINE__); + log_flush(true); + exit(EX_SOFTWARE); + } + } + do_code_width(); + + if ( old_changes != cpd.changes + && first) + { + // retry line breaks caused by splitting 1-liners + newlines_cleanup_braces(false); + newlines_insert_blank_lines(); + newlines_functions_remove_extra_blank_lines(); + newlines_remove_disallowed(); + first = false; + } + } + dump_step(dump_file, "Inside second while loop"); + } while (old_changes != cpd.changes); + + // And finally, align the backslash newline stuff + align_right_comments(); + + log_rule_B("align_nl_cont"); + + if (options::align_nl_cont()) + { + align_backslash_newline(); + } + dump_step(dump_file, "Final version"); + + // which output is to be done? + if (cpd.html_file == nullptr) + { + // Now render it all to the output file + output_text(pfout); + } + else + { + // create the tracking file + FILE *t_file; + t_file = fopen(cpd.html_file, "wb"); + + if (t_file) + { + output_text(t_file); + fclose(t_file); + exit(EX_OK); + } + exit(EX_USAGE); + } + } + + // Special hook for dumping parsed data for debugging + if (parsed_file != nullptr) + { + FILE *p_file; + + if ( parsed_file[0] == '-' + && !parsed_file[1]) + { + p_file = stdout; + } + else + { + p_file = fopen(parsed_file, "wb"); + } + + if (p_file != nullptr) + { + if (ends_with(parsed_file, ".csv", false)) + { + output_parsed_csv(p_file); + } + else + { + output_parsed(p_file); + } + + if (p_file != stdout) + { + fclose(p_file); + } + } + else + { + LOG_FMT(LERR, "%s: Failed to open '%s' for write: %s (%d)\n", + __func__, parsed_file, strerror(errno), errno); + exit(EX_IOERR); + } + } + + if ( cpd.do_check + && !bout_content_matches(fm, true)) + { + cpd.check_fail_cnt++; + } + + if (!defer_uncrustify_end) + { + uncrustify_end(); + } +} // uncrustify_file + + +void uncrustify_end() +{ + // Free all the memory + Chunk *pc; + + cpd.unc_stage = unc_stage_e::CLEANUP; + + while ((pc = Chunk::GetHead())->IsNotNullChunk()) + { + Chunk::Delete(pc); + } + + if (cpd.bout) + { + cpd.bout->clear(); + } + // Clean up some state variables + cpd.unc_off = false; + cpd.al_cnt = 0; + cpd.did_newline = true; + cpd.pp_level = 0; + cpd.changes = 0; + cpd.in_preproc = CT_NONE; + memset(cpd.le_counts, 0, sizeof(cpd.le_counts)); + cpd.preproc_ncnl_count = 0; + cpd.ifdef_over_whole_file = 0; + cpd.warned_unable_string_replace_tab_chars = false; +} + + +const char *get_token_name(E_Token token) +{ + if ( token >= 0 + && (token < static_cast<int> ARRAY_SIZE(token_names)) + && (token_names[token] != nullptr)) + { + return(token_names[token]); + } + return("???"); +} + + +E_Token find_token_name(const char *text) +{ + if ( text != nullptr + && (*text != 0)) + { + for (int idx = 1; idx < static_cast<int> ARRAY_SIZE(token_names); idx++) + { + if (strcasecmp(text, token_names[idx]) == 0) + { + return(static_cast<E_Token>(idx)); + } + } + } + return(CT_NONE); +} + + +static bool ends_with(const char *filename, const char *tag, bool case_sensitive = true) +{ + int len1 = strlen(filename); + int len2 = strlen(tag); + + return( len2 <= len1 + && ( ( case_sensitive + && (strcmp(&filename[len1 - len2], tag) == 0)) + || ( !case_sensitive + && (strcasecmp(&filename[len1 - len2], tag) == 0)))); +} + + +struct lang_name_t +{ + const char *name; + size_t lang; +}; + +static lang_name_t language_names[] = +{ + { "C", LANG_C }, // 0x0001 + { "CPP", LANG_CPP }, // 0x0002 + { "D", LANG_D }, // 0x0004 + { "CS", LANG_CS }, // 0x0008 + { "JAVA", LANG_JAVA }, // 0x0010 + { "OC", LANG_OC }, // 0x0020 + { "VALA", LANG_VALA }, // 0x0040 + { "PAWN", LANG_PAWN }, // 0x0080 + { "ECMA", LANG_ECMA }, // 0x0100 + { "OC+", LANG_OC | LANG_CPP }, // 0x0020 + 0x0002 + { "CS+", LANG_CS | LANG_CPP }, // 0x0008 + 0x0002 + { "C-Header", LANG_C | LANG_CPP | FLAG_HDR }, // 0x0001 + 0x0002 + 0x2000 = 0x2022 +}; + + +static size_t language_flags_from_name(const char *name) +{ + for (const auto &language : language_names) + { + if (strcasecmp(name, language.name) == 0) + { + return(language.lang); + } + } + + return(0); +} + + +const char *language_name_from_flags(size_t lang) +{ + // Check for an exact match first + for (auto &language_name : language_names) + { + if (language_name.lang == lang) + { + return(language_name.name); + } + } + + // Check for the first set language bit + for (auto &language_name : language_names) + { + if ((language_name.lang & lang) != 0) + { + return(language_name.name); + } + } + + return("???"); +} + + +//! type to map a programming language to a typically used filename extension +struct lang_ext_t +{ + const char *ext; //! filename extension typically used for ... + const char *name; //! a programming language +}; + +//! known filename extensions linked to the corresponding programming language +struct lang_ext_t language_exts[] = +{ + { ".c", "C" }, + { ".c++", "CPP" }, + { ".cc", "CPP" }, + { ".cp", "CPP" }, + { ".cpp", "CPP" }, + { ".cs", "CS" }, + { ".cxx", "CPP" }, + { ".d", "D" }, + { ".di", "D" }, + { ".es", "ECMA" }, + { ".h", "C-Header" }, + { ".h++", "CPP" }, + { ".hh", "CPP" }, + { ".hp", "CPP" }, + { ".hpp", "CPP" }, + { ".hxx", "CPP" }, + { ".inl", "PAWN" }, + { ".java", "JAVA" }, + { ".js", "ECMA" }, + { ".m", "OC" }, + { ".mm", "OC+" }, + { ".p", "PAWN" }, + { ".pawn", "PAWN" }, + { ".sma", "PAWN" }, + { ".sqc", "C" }, // embedded SQL + { ".sql", "SQL" }, + { ".vala", "VALA" }, +}; + + +const char *get_file_extension(int &idx) +{ + const char *val = nullptr; + + if (idx < static_cast<int> ARRAY_SIZE(language_exts)) + { + val = language_exts[idx].ext; + } + idx++; + return(val); +} + + +typedef std::map<string, string> extension_map_t; +/** + * maps a file extension to a language flag. + * + * @note The "." need to be included, as in ".c". The file extensions + * ARE case sensitive. + */ +static extension_map_t g_ext_map; + + +const char *extension_add(const char *ext_text, const char *lang_text) +{ + size_t lang_flags = language_flags_from_name(lang_text); + + if (lang_flags) + { + const char *lang_name = language_name_from_flags(lang_flags); + g_ext_map[string(ext_text)] = lang_name; + return(lang_name); + } + return(nullptr); +} + + +void print_extensions(FILE *pfile) +{ + for (auto &language : language_names) + { + bool did_one = false; + + for (auto &extension_val : g_ext_map) + { + if (strcmp(extension_val.second.c_str(), language.name) == 0) + { + if (!did_one) + { + fprintf(pfile, "file_ext %s", extension_val.second.c_str()); + did_one = true; + } + fprintf(pfile, " %s", extension_val.first.c_str()); + } + } + + if (did_one) + { + fprintf(pfile, "\n"); + } + } +} + + +// TODO: better use enum lang_t for source file language +static size_t language_flags_from_filename(const char *filename) +{ + // check custom extensions first + for (const auto &extension_val : g_ext_map) + { + if (ends_with(filename, extension_val.first.c_str())) + { + return(language_flags_from_name(extension_val.second.c_str())); + } + } + + for (auto &language : language_exts) + { + if (ends_with(filename, language.ext)) + { + return(language_flags_from_name(language.name)); + } + } + + // check again without case sensitivity + for (auto &extension_val : g_ext_map) + { + if (ends_with(filename, extension_val.first.c_str(), false)) + { + return(language_flags_from_name(extension_val.second.c_str())); + } + } + + for (auto &language : language_exts) + { + if (ends_with(filename, language.ext, false)) + { + return(language_flags_from_name(language.name)); + } + } + + return(LANG_C); +} // language_flags_from_filename diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify.h new file mode 100644 index 00000000..0a584805 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify.h @@ -0,0 +1,94 @@ +/** + * @file uncrustify.h + * prototypes for uncrustify.c + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef UNCRUSTIFY_H_INCLUDED +#define UNCRUSTIFY_H_INCLUDED + +#include "uncrustify_types.h" + +#include <stdio.h> + +int load_header_files(); + + +void uncrustify_file(const file_mem &fm, FILE *pfout, const char *parsed_file, const char *dump_filename, bool defer_uncrustify_end = false); + + +void uncrustify_end(); + + +const char *get_token_name(E_Token token); + + +/** + * Gets the tag text for a language + * + * @param lang The LANG_xxx enum + * + * @return A string + */ +const char *language_name_from_flags(size_t lang); + + +/** + * Grab the token id for the text. + * + * @return token, will be CT_NONE on failure to match + */ +E_Token find_token_name(const char *text); + + +/** + * Replace the brain-dead and non-portable basename(). + * Returns a pointer to the character after the last '/'. + * The returned value always points into path, unless path is nullptr. + * + * Input Returns + * nullptr => "" + * "/some/path/" => "" + * "/some/path" => "path" + * "afile" => "afile" + * + * @param path The path to look at + * + * @return Pointer to the character after the last path separator + */ +const char *path_basename(const char *path); + + +/** + * Returns the length of the directory part of the filename. + * + * @param filename filename including full path + * + * @return character size of path + */ +int path_dirname_len(const char *filename); + + +void usage(const char *argv0); + + +void usage_error(const char *msg = nullptr); + + +/** + * Set idx = 0 before the first call. + * Done when returns nullptr + */ +const char *get_file_extension(int &idx); + + +//! Prints custom file extensions to the file +void print_extensions(FILE *pfile); + + +const char *extension_add(const char *ext_text, const char *lang_text); + + +#endif /* UNCRUSTIFY_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify_emscripten.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify_emscripten.cpp new file mode 100644 index 00000000..72206627 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify_emscripten.cpp @@ -0,0 +1,1212 @@ +/* + * uncrustify_emscripten.cpp - JavaScript Emscripten binding interface + * + * Created on: May 8, 2016 + * Author: Daniel Chumak + * + * INTERFACE: + * ============================================================================ + * unsure about these: + * --check TODO ??? + * --decode TODO ??? + * --detect TODO needs uncrustify start and end which both are static + * + * + * will not be included: + * ---------------------------------------------------------------------------- + * -t ( define via multiple --type ) + * -d ( define via multiple --define ) + * --assume ( no files available to guess the lang. based on the filename ending ) + * --files ( no batch processing will be available ) + * --prefix + * --suffix + * --assume + * --no-backup + * --replace + * --mtime + * --universalindent + * --ds/--dump-steps + * -help, -h, --usage, -? + * + * + * done: + * ---------------------------------------------------------------------------- + * --update-config ( use show_config() ) + * --update-config-with-doc ( show_config( bool withDoc = true ) ) + * --version, -v ( use get_version() ) + * --log, -L ( use log_type_enable( log_sev_t sev, bool value ) ) + * -q ( use quiet() ) + * --config, -c ( use loadConfig( string _cfg ) ) + * --file, -f ( use uncrustify( string _file ) ) + * --show ( use log_type_show_name( bool ) ) + * --frag ( use uncrustify( string _file, bool frag = true ) ) + * --type ( use add_keyword( string _type, E_Token type ) ) + * -l ( use uncrustify() ) + * --parsed, -p ( use debug() ) + */ + + +#if defined (__linux__) + + +#include "keywords.h" +#include "log_levels.h" +#include "logger.h" +#include "option.h" +#include "options.h" +#include "output.h" +#include "prototypes.h" +#include "uncrustify.h" +#include "uncrustify_version.h" +#include "unicode.h" + +#include <iostream> +#include <map> +#include <memory> +#include <stdio.h> +#include <stdlib.h> +#include <unordered_map> +#include <vector> + + +#ifdef EMSCRIPTEN +#include <emscripten/bind.h> +#include <emscripten/val.h> +using namespace emscripten; +#else +#define EMSCRIPTEN_BINDINGS(module) void dummyFcn() +template<class T> +struct base {}; +struct emscripten +{ + template<class... Args> + emscripten value(Args...) { return{}; } + + template<class... Args> + static emscripten function(Args...) { return{}; } + + template<class... Args> + emscripten property(Args...) { return{}; } +}; +using Dummy = emscripten; + + +template<class T> +Dummy enum_(char const *const) +{ + return(Dummy{}); +} + + +template<class T> +Dummy register_vector(char const *const) +{ + return(Dummy{}); +} + + +template<class... Args> +Dummy class_(char const *const) +{ + return(Dummy{}); +} + + +template<class T> +Dummy select_overload(T) +{ + return(Dummy{}); +} +#endif + +using namespace std; +using namespace uncrustify; + +namespace +{ + +/** + * Loads options from a file represented as a single char array. + * Modifies: input char array, cpd.line_number + * Expects: \0 terminated char array + * + * @param configString char array that holds the whole config + * @return EXIT_SUCCESS on success + */ +int load_option_fileChar(char *configString) +{ + char *delimPos = &configString[0]; + char *subStringStart = &configString[0]; + + cpd.line_number = 0; + + // TODO: handle compat_level + int compat_level = 0; + + while (true) + { + delimPos = strchr(delimPos, '\n'); + + if (delimPos == nullptr) + { + break; + } + // replaces \n with \0 -> string including multiple terminated substrings + *delimPos = '\0'; + + + process_option_line(subStringStart, "", compat_level); + + delimPos++; + subStringStart = delimPos; + } + //get last line, expectation: ends with \0 + process_option_line(subStringStart, "", compat_level); + + return(EXIT_SUCCESS); +} + + +/** + * adds a new keyword to Uncrustify's dynamic keyword map (dkwm, keywords.cpp) + * + * @param tag: keyword that is going to be added + * @param type: type of the keyword + */ +void _add_keyword(string tag, E_Token type) +{ + if (tag.empty()) + { + LOG_FMT(LERR, "%s: input string is empty\n", __func__); + return; + } + add_keyword(tag, type); +} + + +//! clears Uncrustify's dynamic keyword map (dkwm, keywords.cpp) +void clear_keywords() +{ + clear_keyword_file(); +} + + +/** + * Show or hide the severity prefix "<1>" + * + * @param b: true=show, false=hide + */ +void show_log_type(bool b) +{ + log_show_sev(b); +} + + +//! returns the UNCRUSTIFY_VERSION string +string get_version() +{ + return(UNCRUSTIFY_VERSION); +} + + +//! disables all logging messages +void set_quiet() +{ + // set empty mask + log_set_mask({}); +} + + +/** + * resets value of an option to its default + * + * @param name: name of the option + * @return options enum value of the found option or -1 if option was not found + */ +int reset_option(string name) +{ + if (name.empty()) + { + LOG_FMT(LERR, "%s: name string is empty\n", __func__); + return(-1); + } + const auto option = find_option(name.c_str()); + + if (option == nullptr) + { + LOG_FMT(LERR, "Option %s not found\n", name.c_str()); + return(-1); + } + option->reset(); + return(0); +} + + +/** + * sets value of an option + * + * @param name: name of the option + * @param value: value that is going to be set + * @return options enum value of the found option or -1 if option was not found + */ +int set_option(string name, string value) +{ + if (name.empty()) + { + LOG_FMT(LERR, "%s: name string is empty\n", __func__); + return(-1); + } + + if (value.empty()) + { + LOG_FMT(LERR, "%s: value string is empty\n", __func__); + return(-1); + } + const auto option = find_option(name.c_str()); + + if (option == nullptr) + { + LOG_FMT(LERR, "Option %s not found\n", name.c_str()); + return(-1); + } + + if (!option->read(value.c_str())) + { + LOG_FMT( + LERR, + "Failed to set value %s for option: %s of type: %s\n", + name.c_str(), + value.c_str(), + to_string(option->type()) + ); + return(-1); + } + return(0); +} + + +/** + * returns value of an option + * + * @param name: name of the option + * @return currently set value of the option + */ +string get_option(string name) +{ + if (name.empty()) + { + LOG_FMT(LERR, "%s: input string is empty\n", __func__); + return(""); + } + const auto option = find_option(name.c_str()); + + if (option == nullptr) + { + LOG_FMT(LWARN, "Option %s not found\n", name.c_str()); + return(""); + } + return(option->str()); +} + + +/** + * returns the config file string based on the current configuration + * + * @param withDoc: false=without documentation, + * true=with documentation text lines + * @param only_not_default: false=containing all options, + * true=containing only options with non default values + * @return returns the config file string based on the current configuration + */ +string show_config(bool withDoc, bool only_not_default) +{ + char *buf; + size_t len; + + FILE *stream = open_memstream(&buf, &len); + + if (stream == nullptr) + { + LOG_FMT(LERR, "Failed to open_memstream\n"); + fflush(stream); + fclose(stream); + free(buf); + return(""); + } + save_option_file(stream, withDoc, only_not_default); + + fflush(stream); + fclose(stream); + + string out(buf); + + free(buf); + + return(out); +} + + +/** + * returns the config file string with all options based on the current configuration + * + * @param withDoc: false= without documentation, true=with documentation text lines + * @return returns the config file string with all options based on the current configuration + */ +string show_config(bool withDoc) +{ + return(show_config(withDoc, false)); +} + + +//!returns the config file string with all options and without documentation based on the current configuration +string show_config() +{ + return(show_config(false, false)); +} + + +std::vector<OptionGroup *> get_groups() +{ + std::vector<OptionGroup *> groups; + + groups.reserve(5); + + for (size_t i = 0; true; ++i) + { + OptionGroup *group = get_option_group(i); + + if (!group) + { + break; + } + groups.push_back(group); + } + + return(groups); +} + + +std::vector<GenericOption *> get_options() +{ + std::vector<GenericOption *> options; + + options.reserve(get_option_count()); + + for (size_t i = 0; true; ++i) + { + OptionGroup *group = get_option_group(i); + + if (!group) + { + break; + } + options.insert( + end(options), + begin(group->options), + end(group->options) + ); + } + + return(options); +} + + +//! resets all options to their default values +void reset_options() +{ + auto options = get_options(); + + for (auto *option : options) + { + option->reset(); + } +} + + +/** + * initializes the current libUncrustify instance, + * used only for emscripten binding here and will be automatically called while + * module initialization + */ +void _initialize() +{ + register_options(); + log_init(stdout); + + LOG_FMT(LSYS, "Initialized libUncrustify - " UNCRUSTIFY_VERSION "\n"); +} + + +//! destroys the current libUncrustify instance +void destruct() +{ + clear_keyword_file(); +} + + +/** + * reads option file string, sets the defined options + * + * @return returns EXIT_SUCCESS on success + */ +int _loadConfig(intptr_t _cfg) +{ + // reset everything in case a config was loaded previously + clear_keyword_file(); + reset_options(); + + // embind complains about char* so we use an int to get the pointer and cast + // it, memory management is done in /emscripten/postfix_module.js + char *cfg = reinterpret_cast<char *>(_cfg); + + if (load_option_fileChar(cfg) != EXIT_SUCCESS) + { + LOG_FMT(LERR, "unable to load the config\n"); + return(EXIT_FAILURE); + } + // This relies on cpd.filename being the config file name + load_header_files(); + + LOG_FMT(LSYS, "finished loading config\n"); + return(EXIT_SUCCESS); +} + + +/** + * format string + * + * @param file: pointer to the file char* string that is going to be formatted + * @param langIDX: specifies in which language the input file is written + * @param frag: true=fragmented code input, false=unfragmented code input + * @param defer: true=do not perform cleanup of Uncrustify structures + * + * @return pointer to the formatted file char* string + */ +intptr_t _uncrustify(intptr_t _file, lang_flag_e langIDX, bool frag, bool defer) +{ + // Problem: uncrustify originally is not a lib and uses global vars such as + // cpd.error_count for the whole program execution + // to know if errors occurred during the formatting step we reset this var here + cpd.filename = "stdin"; + cpd.frag = frag; + + if (langIDX == 0) // 0 == undefined + { + LOG_FMT(LWARN, "language of input file not defined, C++ will be assumed\n"); + cpd.lang_flags = LANG_CPP; + } + else + { + cpd.lang_flags = langIDX; + } + // embind complains about char* so we use an intptr_t to get the pointer and + // cast it, memory management is done in /emscripten/postfix_module.js + char *file = reinterpret_cast<char *>(_file); + + file_mem fm; + + fm.raw.clear(); + fm.data.clear(); + fm.enc = char_encoding_e::e_ASCII; + fm.raw = vector<UINT8>(); + + char c; + + for (auto idx = 0; (c = file[idx]) != 0; ++idx) + { + fm.raw.push_back(c); + } + + if (!decode_unicode(fm.raw, fm.data, fm.enc, fm.bom)) + { + LOG_FMT(LERR, "Failed to read code\n"); + return(0); + } + // Done reading from stdin + LOG_FMT(LSYS, "Parsing: %zu bytes (%zu chars) from stdin as language %s\n", + fm.raw.size(), fm.data.size(), + language_name_from_flags(cpd.lang_flags)); + + + char *buf = nullptr; + size_t len = 0; + + // uncrustify uses FILE instead of streams for its outputs + // to redirect FILE writes into a char* open_memstream is used + // windows lacks open_memstream, only UNIX/BSD is supported + // apparently emscripten has its own implementation, if that is not working + // see: stackoverflow.com/questions/10305095#answer-10341073 + FILE *stream = open_memstream(&buf, &len); + + if (stream == nullptr) + { + LOG_FMT(LERR, "Failed to open_memstream\n"); + return(0); + } + // TODO One way to implement the --parsed, -p functionality would + // be to let the uncrustify_file function run, throw away the formatted + // output and return the debug as a string. For this uncrustify_file would + // need to accept a stream, FILE or a char array pointer in which the output + // will be stored. + // Another option would be to check, inside the uncrustify_file function, + // if the current filename string matches stdout or stderr and use those as + // output locations. This is the easier fix but the debug info in the + // browsers console is littered with other unneeded text. + // Finally, the ugliest solution, would be also possible to re-route + // either stdout or stderr inside the Module var of emscripten to a js + // function which passes the debug output into a dedicated output js target. + // This therefore would introduce the dependency on the user to always have + // the output js target available. + uncrustify_file(fm, stream, nullptr, nullptr, defer); + + fflush(stream); + fclose(stream); + + if (len == 0) + { + return(0); + } + // buf is deleted inside js code + return(reinterpret_cast<intptr_t>(buf)); +} // uncrustify + + +/** + * format string + * + * @param file: pointer to the file char* string that is going to be formatted + * @param langIDX: specifies in which language the input file is written + * @param frag: true=fragmented code input, false=unfragmented code input + * + * @return pointer to the formatted file char* string + */ +intptr_t _uncrustify(intptr_t file, lang_flag_e langIDX, bool frag) +{ + return(_uncrustify(file, langIDX, frag, false)); +} + + +/** + * format string, assume unfragmented code input + * + * @param file: pointer to the file char* string that is going to be formatted + * @param langIDX: specifies in which language the input file is written + * + * @return pointer to the formatted file char* string + */ +intptr_t _uncrustify(intptr_t file, lang_flag_e langIDX) +{ + return(_uncrustify(file, langIDX, false, false)); +} + + +/** + * generate debug output + * + * @param file: pointer to the file char* string that is going to be formatted + * @param langIDX: specifies in which language the input file is written + * @param frag: true=fragmented code input, false=unfragmented code input + * + * @return pointer to the debug file char* string + */ +intptr_t _debug(intptr_t _file, lang_flag_e langIDX, bool frag) +{ + auto formatted_str_ptr = _uncrustify(_file, langIDX, frag, true); + char *formatted_str = reinterpret_cast<char *>(formatted_str_ptr); + + // Lazy solution: Throw away the formatted file output. + // Maybe later add option to return both formatted file string and debug + // file string together ... somehow. + free(formatted_str); + + char *buf = nullptr; + size_t len = 0; + FILE *stream = open_memstream(&buf, &len); + + if (stream == nullptr) + { + LOG_FMT(LERR, "Failed to open_memstream\n"); + return(0); + } + output_parsed(stream); + fflush(stream); + fclose(stream); + + // start deferred _uncrustify cleanup + uncrustify_end(); + + if (len == 0) + { + return(0); + } + // buf is deleted inside js code + return(reinterpret_cast<intptr_t>(buf)); +} // uncrustify + + +/** + * generate debug output, assume unfragmented code input + * + * @param file: pointer to the file char* string that is going to be formatted + * @param langIDX: specifies in which language the input file is written + * + * @return pointer to the debug file char* string + */ +intptr_t _debug(intptr_t _file, lang_flag_e langIDX) +{ + return(_debug(_file, langIDX, false)); +} + +} // namespace + +EMSCRIPTEN_BINDINGS(MainModule) +{ + // region enum bindings + enum_<option_type_e>("OptionType") + .value("BOOL", option_type_e::BOOL) + .value("IARF", option_type_e::IARF) + .value("LINEEND", option_type_e::LINEEND) + .value("TOKENPOS", option_type_e::TOKENPOS) + .value("NUM", option_type_e::NUM) + .value("UNUM", option_type_e::UNUM) + .value("STRING", option_type_e::STRING); + + enum_<iarf_e>("IARF") + .value("IGNORE", IARF_IGNORE) + .value("ADD", IARF_ADD) + .value("REMOVE", IARF_REMOVE) + .value("FORCE", IARF_FORCE); + + enum_<line_end_e>("LineEnd") + .value("LF", line_end_e::LF) + .value("CRLF", line_end_e::CRLF) + .value("CR", line_end_e::CR) + .value("AUTO", line_end_e::AUTO); + + enum_<token_pos_e>("TokenPos") + .value("IGNORE", token_pos_e::IGNORE) + .value("BREAK", token_pos_e::BREAK) + .value("FORCE", token_pos_e::FORCE) + .value("LEAD", token_pos_e::LEAD) + .value("TRAIL", token_pos_e::TRAIL) + .value("JOIN", token_pos_e::JOIN) + .value("LEAD_BREAK", token_pos_e::LEAD_BREAK) + .value("LEAD_FORCE", token_pos_e::LEAD_FORCE) + .value("TRAIL_BREAK", token_pos_e::TRAIL_BREAK) + .value("TRAIL_FORCE", token_pos_e::TRAIL_FORCE); + + enum_<log_sev_t>("LogType") + .value("SYS", log_sev_t::LSYS) + .value("ERR", log_sev_t::LERR) + .value("WARN", log_sev_t::LWARN) + .value("NOTE", log_sev_t::LNOTE) + .value("INFO", log_sev_t::LINFO) + .value("DATA", log_sev_t::LDATA) + .value("FILELIST", log_sev_t::LFILELIST) + .value("LINEENDS", log_sev_t::LLINEENDS) + .value("CASTS", log_sev_t::LCASTS) + .value("ALBR", log_sev_t::LALBR) + .value("ALTD", log_sev_t::LALTD) + .value("ALPP", log_sev_t::LALPP) + .value("ALPROTO", log_sev_t::LALPROTO) + .value("ALNLC", log_sev_t::LALNLC) + .value("ALTC", log_sev_t::LALTC) + .value("ALADD", log_sev_t::LALADD) + .value("ALASS", log_sev_t::LALASS) + .value("FVD", log_sev_t::LFVD) + .value("FVD2", log_sev_t::LFVD2) + .value("INDENT", log_sev_t::LINDENT) + .value("INDENT2", log_sev_t::LINDENT2) + .value("INDPSE", log_sev_t::LINDPSE) + .value("INDPC", log_sev_t::LINDPC) + .value("NEWLINE", log_sev_t::LNEWLINE) + .value("PF", log_sev_t::LPF) + .value("STMT", log_sev_t::LSTMT) + .value("TOK", log_sev_t::LTOK) + .value("ALRC", log_sev_t::LALRC) + .value("CMTIND", log_sev_t::LCMTIND) + .value("INDLINE", log_sev_t::LINDLINE) + .value("SIB", log_sev_t::LSIB) + .value("RETURN", log_sev_t::LRETURN) + .value("BRDEL", log_sev_t::LBRDEL) + .value("FCN", log_sev_t::LFCN) + .value("FCNP", log_sev_t::LFCNP) + .value("PCU", log_sev_t::LPCU) + .value("DYNKW", log_sev_t::LDYNKW) + .value("OUTIND", log_sev_t::LOUTIND) + .value("BCSAFTER", log_sev_t::LBCSAFTER) + .value("BCSPOP", log_sev_t::LBCSPOP) + .value("BCSPUSH", log_sev_t::LBCSPUSH) + .value("BCSSWAP", log_sev_t::LBCSSWAP) + .value("FTOR", log_sev_t::LFTOR) + .value("AS", log_sev_t::LAS) + .value("PPIS", log_sev_t::LPPIS) + .value("TYPEDEF", log_sev_t::LTYPEDEF) + .value("VARDEF", log_sev_t::LVARDEF) + .value("DEFVAL", log_sev_t::LDEFVAL) + .value("PVSEMI", log_sev_t::LPVSEMI) + .value("PFUNC", log_sev_t::LPFUNC) + .value("SPLIT", log_sev_t::LSPLIT) + .value("FTYPE", log_sev_t::LFTYPE) + .value("TEMPL", log_sev_t::LTEMPL) + .value("PARADD", log_sev_t::LPARADD) + .value("PARADD2", log_sev_t::LPARADD2) + .value("BLANKD", log_sev_t::LBLANKD) + .value("TEMPFUNC", log_sev_t::LTEMPFUNC) + .value("SCANSEMI", log_sev_t::LSCANSEMI) + .value("DELSEMI", log_sev_t::LDELSEMI) + .value("FPARAM", log_sev_t::LFPARAM) + .value("NL1LINE", log_sev_t::LNL1LINE) + .value("PFCHK", log_sev_t::LPFCHK) + .value("AVDB", log_sev_t::LAVDB) + .value("SORT", log_sev_t::LSORT) + .value("SPACE", log_sev_t::LSPACE) + .value("ALIGN", log_sev_t::LALIGN) + .value("ALAGAIN", log_sev_t::LALAGAIN) + .value("OPERATOR", log_sev_t::LOPERATOR) + .value("ASFCP", log_sev_t::LASFCP) + .value("INDLINED", log_sev_t::LINDLINED) + .value("BCTRL", log_sev_t::LBCTRL) + .value("RMRETURN", log_sev_t::LRMRETURN) + .value("PPIF", log_sev_t::LPPIF) + .value("MCB", log_sev_t::LMCB) + .value("BRCH", log_sev_t::LBRCH) + .value("FCNR", log_sev_t::LFCNR) + .value("OCCLASS", log_sev_t::LOCCLASS) + .value("OCMSG", log_sev_t::LOCMSG) + .value("BLANK", log_sev_t::LBLANK) + .value("OBJCWORD", log_sev_t::LOBJCWORD) + .value("CHANGE", log_sev_t::LCHANGE) + .value("CONTTEXT", log_sev_t::LCONTTEXT) + .value("ANNOT", log_sev_t::LANNOT) + .value("OCBLK", log_sev_t::LOCBLK) + .value("FLPAREN", log_sev_t::LFLPAREN) + .value("OCMSGD", log_sev_t::LOCMSGD) + .value("INDENTAG", log_sev_t::LINDENTAG) + .value("NFD", log_sev_t::LNFD) + .value("JDBI", log_sev_t::LJDBI) + .value("SETPAR", log_sev_t::LSETPAR) + .value("SETTYP", log_sev_t::LSETTYP) + .value("SETFLG", log_sev_t::LSETFLG) + .value("NLFUNCT", log_sev_t::LNLFUNCT) + .value("CHUNK", log_sev_t::LCHUNK) + .value("GUY98", log_sev_t::LGUY98) + .value("GUY", log_sev_t::LGUY); + + enum_<E_Token>("TokenType") + .value("NONE", E_Token::CT_NONE) + .value("EOF", E_Token::CT_EOF) + .value("UNKNOWN", E_Token::CT_UNKNOWN) + .value("JUNK", E_Token::CT_JUNK) + .value("WHITESPACE", E_Token::CT_WHITESPACE) + .value("SPACE", E_Token::CT_SPACE) + .value("NEWLINE", E_Token::CT_NEWLINE) + .value("NL_CONT", E_Token::CT_NL_CONT) + .value("COMMENT_CPP", E_Token::CT_COMMENT_CPP) + .value("COMMENT", E_Token::CT_COMMENT) + .value("COMMENT_MULTI", E_Token::CT_COMMENT_MULTI) + .value("COMMENT_EMBED", E_Token::CT_COMMENT_EMBED) + .value("COMMENT_START", E_Token::CT_COMMENT_START) + .value("COMMENT_END", E_Token::CT_COMMENT_END) + .value("COMMENT_WHOLE", E_Token::CT_COMMENT_WHOLE) + .value("COMMENT_ENDIF", E_Token::CT_COMMENT_ENDIF) + .value("IGNORED", E_Token::CT_IGNORED) + .value("WORD", E_Token::CT_WORD) + .value("NUMBER", E_Token::CT_NUMBER) + .value("NUMBER_FP", E_Token::CT_NUMBER_FP) + .value("STRING", E_Token::CT_STRING) + .value("STRING_MULTI", E_Token::CT_STRING_MULTI) + .value("IF", E_Token::CT_IF) + .value("ELSE", E_Token::CT_ELSE) + .value("ELSEIF", E_Token::CT_ELSEIF) + .value("FOR", E_Token::CT_FOR) + .value("WHILE", E_Token::CT_WHILE) + .value("WHILE_OF_DO", E_Token::CT_WHILE_OF_DO) + .value("SWITCH", E_Token::CT_SWITCH) + .value("CASE", E_Token::CT_CASE) + .value("DO", E_Token::CT_DO) + .value("SYNCHRONIZED", E_Token::CT_SYNCHRONIZED) + .value("VOLATILE", E_Token::CT_VOLATILE) + .value("TYPEDEF", E_Token::CT_TYPEDEF) + .value("STRUCT", E_Token::CT_STRUCT) + .value("ENUM", E_Token::CT_ENUM) + .value("ENUM_CLASS", E_Token::CT_ENUM_CLASS) + .value("SIZEOF", E_Token::CT_SIZEOF) + .value("DECLTYPE", E_Token::CT_DECLTYPE) + .value("RETURN", E_Token::CT_RETURN) + .value("BREAK", E_Token::CT_BREAK) + .value("UNION", E_Token::CT_UNION) + .value("GOTO", E_Token::CT_GOTO) + .value("CONTINUE", E_Token::CT_CONTINUE) + .value("C_CAST", E_Token::CT_C_CAST) + .value("CPP_CAST", E_Token::CT_CPP_CAST) + .value("D_CAST", E_Token::CT_D_CAST) + .value("TYPE_CAST", E_Token::CT_TYPE_CAST) + .value("TYPENAME", E_Token::CT_TYPENAME) + .value("TEMPLATE", E_Token::CT_TEMPLATE) + .value("WHERE_SPEC", E_Token::CT_WHERE_SPEC) + .value("ASSIGN", E_Token::CT_ASSIGN) + .value("ASSIGN_NL", E_Token::CT_ASSIGN_NL) + .value("SASSIGN", E_Token::CT_SASSIGN) + .value("ASSIGN_DEFAULT_ARG", E_Token::CT_ASSIGN_DEFAULT_ARG) + .value("ASSIGN_FUNC_PROTO", E_Token::CT_ASSIGN_FUNC_PROTO) + .value("COMPARE", E_Token::CT_COMPARE) + .value("SCOMPARE", E_Token::CT_SCOMPARE) + .value("BOOL", E_Token::CT_BOOL) + .value("SBOOL", E_Token::CT_SBOOL) + .value("ARITH", E_Token::CT_ARITH) + .value("SARITH", E_Token::CT_SARITH) + .value("CARET", E_Token::CT_CARET) + .value("DEREF", E_Token::CT_DEREF) + .value("INCDEC_BEFORE", E_Token::CT_INCDEC_BEFORE) + .value("INCDEC_AFTER", E_Token::CT_INCDEC_AFTER) + .value("MEMBER", E_Token::CT_MEMBER) + .value("DC_MEMBER", E_Token::CT_DC_MEMBER) + .value("C99_MEMBER", E_Token::CT_C99_MEMBER) + .value("INV", E_Token::CT_INV) + .value("DESTRUCTOR", E_Token::CT_DESTRUCTOR) + .value("NOT", E_Token::CT_NOT) + .value("D_TEMPLATE", E_Token::CT_D_TEMPLATE) + .value("ADDR", E_Token::CT_ADDR) + .value("NEG", E_Token::CT_NEG) + .value("POS", E_Token::CT_POS) + .value("STAR", E_Token::CT_STAR) + .value("PLUS", E_Token::CT_PLUS) + .value("MINUS", E_Token::CT_MINUS) + .value("AMP", E_Token::CT_AMP) + .value("BYREF", E_Token::CT_BYREF) + .value("POUND", E_Token::CT_POUND) + .value("PREPROC", E_Token::CT_PREPROC) + .value("PREPROC_INDENT", E_Token::CT_PREPROC_INDENT) + .value("PREPROC_BODY", E_Token::CT_PREPROC_BODY) + .value("PP", E_Token::CT_PP) + .value("ELLIPSIS", E_Token::CT_ELLIPSIS) + .value("RANGE", E_Token::CT_RANGE) + .value("NULLCOND", E_Token::CT_NULLCOND) + .value("SEMICOLON", E_Token::CT_SEMICOLON) + .value("VSEMICOLON", E_Token::CT_VSEMICOLON) + .value("COLON", E_Token::CT_COLON) + .value("ASM_COLON", E_Token::CT_ASM_COLON) + .value("CASE_COLON", E_Token::CT_CASE_COLON) + .value("CLASS_COLON", E_Token::CT_CLASS_COLON) + .value("CONSTR_COLON", E_Token::CT_CONSTR_COLON) + .value("D_ARRAY_COLON", E_Token::CT_D_ARRAY_COLON) + .value("COND_COLON", E_Token::CT_COND_COLON) + .value("WHERE_COLON", E_Token::CT_WHERE_COLON) + .value("QUESTION", E_Token::CT_QUESTION) + .value("COMMA", E_Token::CT_COMMA) + .value("ASM", E_Token::CT_ASM) + .value("ATTRIBUTE", E_Token::CT_ATTRIBUTE) + .value("AUTORELEASEPOOL", E_Token::CT_AUTORELEASEPOOL) + .value("OC_AVAILABLE", E_Token::CT_OC_AVAILABLE) + .value("OC_AVAILABLE_VALUE", E_Token::CT_OC_AVAILABLE_VALUE) + .value("CATCH", E_Token::CT_CATCH) + .value("WHEN", E_Token::CT_WHEN) + .value("WHERE", E_Token::CT_WHERE) + .value("CLASS", E_Token::CT_CLASS) + .value("DELETE", E_Token::CT_DELETE) + .value("EXPORT", E_Token::CT_EXPORT) + .value("FRIEND", E_Token::CT_FRIEND) + .value("NAMESPACE", E_Token::CT_NAMESPACE) + .value("PACKAGE", E_Token::CT_PACKAGE) + .value("NEW", E_Token::CT_NEW) + .value("OPERATOR", E_Token::CT_OPERATOR) + .value("OPERATOR_VAL", E_Token::CT_OPERATOR_VAL) + .value("ASSIGN_OPERATOR", E_Token::CT_ASSIGN_OPERATOR) + .value("ACCESS", E_Token::CT_ACCESS) + .value("ACCESS_COLON", E_Token::CT_ACCESS_COLON) + .value("THROW", E_Token::CT_THROW) + .value("NOEXCEPT", E_Token::CT_NOEXCEPT) + .value("TRY", E_Token::CT_TRY) + .value("BRACED_INIT_LIST", E_Token::CT_BRACED_INIT_LIST) + .value("USING", E_Token::CT_USING) + .value("USING_STMT", E_Token::CT_USING_STMT) + .value("USING_ALIAS", E_Token::CT_USING_ALIAS) + .value("D_WITH", E_Token::CT_D_WITH) + .value("D_MODULE", E_Token::CT_D_MODULE) + .value("SUPER", E_Token::CT_SUPER) + .value("DELEGATE", E_Token::CT_DELEGATE) + .value("BODY", E_Token::CT_BODY) + .value("DEBUG", E_Token::CT_DEBUG) + .value("DEBUGGER", E_Token::CT_DEBUGGER) + .value("INVARIANT", E_Token::CT_INVARIANT) + .value("UNITTEST", E_Token::CT_UNITTEST) + .value("UNSAFE", E_Token::CT_UNSAFE) + .value("FINALLY", E_Token::CT_FINALLY) + .value("FIXED", E_Token::CT_FIXED) + .value("IMPORT", E_Token::CT_IMPORT) + .value("D_SCOPE", E_Token::CT_D_SCOPE) + .value("D_SCOPE_IF", E_Token::CT_D_SCOPE_IF) + .value("LAZY", E_Token::CT_LAZY) + .value("D_MACRO", E_Token::CT_D_MACRO) + .value("D_VERSION", E_Token::CT_D_VERSION) + .value("D_VERSION_IF", E_Token::CT_D_VERSION_IF) + .value("PAREN_OPEN", E_Token::CT_PAREN_OPEN) + .value("PAREN_CLOSE", E_Token::CT_PAREN_CLOSE) + .value("ANGLE_OPEN", E_Token::CT_ANGLE_OPEN) + .value("ANGLE_CLOSE", E_Token::CT_ANGLE_CLOSE) + .value("SPAREN_OPEN", E_Token::CT_SPAREN_OPEN) + .value("SPAREN_CLOSE", E_Token::CT_SPAREN_CLOSE) + .value("FPAREN_OPEN", E_Token::CT_FPAREN_OPEN) + .value("FPAREN_CLOSE", E_Token::CT_FPAREN_CLOSE) + .value("TPAREN_OPEN", E_Token::CT_TPAREN_OPEN) + .value("TPAREN_CLOSE", E_Token::CT_TPAREN_CLOSE) + .value("BRACE_OPEN", E_Token::CT_BRACE_OPEN) + .value("BRACE_CLOSE", E_Token::CT_BRACE_CLOSE) + .value("VBRACE_OPEN", E_Token::CT_VBRACE_OPEN) + .value("VBRACE_CLOSE", E_Token::CT_VBRACE_CLOSE) + .value("SQUARE_OPEN", E_Token::CT_SQUARE_OPEN) + .value("SQUARE_CLOSE", E_Token::CT_SQUARE_CLOSE) + .value("TSQUARE", E_Token::CT_TSQUARE) + .value("MACRO_OPEN", E_Token::CT_MACRO_OPEN) + .value("MACRO_CLOSE", E_Token::CT_MACRO_CLOSE) + .value("MACRO_ELSE", E_Token::CT_MACRO_ELSE) + .value("LABEL", E_Token::CT_LABEL) + .value("LABEL_COLON", E_Token::CT_LABEL_COLON) + .value("FUNCTION", E_Token::CT_FUNCTION) + .value("FUNC_CALL", E_Token::CT_FUNC_CALL) + .value("FUNC_CALL_USER", E_Token::CT_FUNC_CALL_USER) + .value("FUNC_DEF", E_Token::CT_FUNC_DEF) + .value("FUNC_TYPE", E_Token::CT_FUNC_TYPE) + .value("FUNC_VAR", E_Token::CT_FUNC_VAR) + .value("FUNC_PROTO", E_Token::CT_FUNC_PROTO) + .value("FUNC_START", E_Token::CT_FUNC_START) + .value("FUNC_CLASS_DEF", E_Token::CT_FUNC_CLASS_DEF) + .value("FUNC_CLASS_PROTO", E_Token::CT_FUNC_CLASS_PROTO) + .value("FUNC_CTOR_VAR", E_Token::CT_FUNC_CTOR_VAR) + .value("FUNC_WRAP", E_Token::CT_FUNC_WRAP) + .value("PROTO_WRAP", E_Token::CT_PROTO_WRAP) + .value("MACRO_FUNC", E_Token::CT_MACRO_FUNC) + .value("MACRO", E_Token::CT_MACRO) + .value("QUALIFIER", E_Token::CT_QUALIFIER) + .value("EXTERN", E_Token::CT_EXTERN) + .value("DECLSPEC", E_Token::CT_DECLSPEC) + .value("ALIGN", E_Token::CT_ALIGN) + .value("TYPE", E_Token::CT_TYPE) + .value("PTR_TYPE", E_Token::CT_PTR_TYPE) + .value("TYPE_WRAP", E_Token::CT_TYPE_WRAP) + .value("CPP_LAMBDA", E_Token::CT_CPP_LAMBDA) + .value("CPP_LAMBDA_RET", E_Token::CT_CPP_LAMBDA_RET) + .value("TRAILING_RET", E_Token::CT_TRAILING_RET) + .value("BIT_COLON", E_Token::CT_BIT_COLON) + .value("OC_DYNAMIC", E_Token::CT_OC_DYNAMIC) + .value("OC_END", E_Token::CT_OC_END) + .value("OC_IMPL", E_Token::CT_OC_IMPL) + .value("OC_INTF", E_Token::CT_OC_INTF) + .value("OC_PROTOCOL", E_Token::CT_OC_PROTOCOL) + .value("OC_PROTO_LIST", E_Token::CT_OC_PROTO_LIST) + .value("OC_GENERIC_SPEC", E_Token::CT_OC_GENERIC_SPEC) + .value("OC_PROPERTY", E_Token::CT_OC_PROPERTY) + .value("OC_CLASS", E_Token::CT_OC_CLASS) + .value("OC_CLASS_EXT", E_Token::CT_OC_CLASS_EXT) + .value("OC_CATEGORY", E_Token::CT_OC_CATEGORY) + .value("OC_SCOPE", E_Token::CT_OC_SCOPE) + .value("OC_MSG", E_Token::CT_OC_MSG) + .value("OC_MSG_CLASS", E_Token::CT_OC_MSG_CLASS) + .value("OC_MSG_FUNC", E_Token::CT_OC_MSG_FUNC) + .value("OC_MSG_NAME", E_Token::CT_OC_MSG_NAME) + .value("OC_MSG_SPEC", E_Token::CT_OC_MSG_SPEC) + .value("OC_MSG_DECL", E_Token::CT_OC_MSG_DECL) + .value("OC_RTYPE", E_Token::CT_OC_RTYPE) + .value("OC_ATYPE", E_Token::CT_OC_ATYPE) + .value("OC_COLON", E_Token::CT_OC_COLON) + .value("OC_DICT_COLON", E_Token::CT_OC_DICT_COLON) + .value("OC_SEL", E_Token::CT_OC_SEL) + .value("OC_SEL_NAME", E_Token::CT_OC_SEL_NAME) + .value("OC_BLOCK", E_Token::CT_OC_BLOCK) + .value("OC_BLOCK_ARG", E_Token::CT_OC_BLOCK_ARG) + .value("OC_BLOCK_TYPE", E_Token::CT_OC_BLOCK_TYPE) + .value("OC_BLOCK_EXPR", E_Token::CT_OC_BLOCK_EXPR) + .value("OC_BLOCK_CARET", E_Token::CT_OC_BLOCK_CARET) + .value("OC_AT", E_Token::CT_OC_AT) + .value("OC_PROPERTY_ATTR", E_Token::CT_OC_PROPERTY_ATTR) + .value("PP_DEFINE", E_Token::CT_PP_DEFINE) + .value("PP_DEFINED", E_Token::CT_PP_DEFINED) + .value("PP_INCLUDE", E_Token::CT_PP_INCLUDE) + .value("PP_IF", E_Token::CT_PP_IF) + .value("PP_ELSE", E_Token::CT_PP_ELSE) + .value("PP_ENDIF", E_Token::CT_PP_ENDIF) + .value("PP_ASSERT", E_Token::CT_PP_ASSERT) + .value("PP_EMIT", E_Token::CT_PP_EMIT) + .value("PP_ENDINPUT", E_Token::CT_PP_ENDINPUT) + .value("PP_ERROR", E_Token::CT_PP_ERROR) + .value("PP_FILE", E_Token::CT_PP_FILE) + .value("PP_LINE", E_Token::CT_PP_LINE) + .value("PP_SECTION", E_Token::CT_PP_SECTION) + .value("PP_ASM", E_Token::CT_PP_ASM) + .value("PP_UNDEF", E_Token::CT_PP_UNDEF) + .value("PP_PROPERTY", E_Token::CT_PP_PROPERTY) + .value("PP_BODYCHUNK", E_Token::CT_PP_BODYCHUNK) + .value("PP_PRAGMA", E_Token::CT_PP_PRAGMA) + .value("PP_REGION", E_Token::CT_PP_REGION) + .value("PP_ENDREGION", E_Token::CT_PP_ENDREGION) + .value("PP_REGION_INDENT", E_Token::CT_PP_REGION_INDENT) + .value("PP_IF_INDENT", E_Token::CT_PP_IF_INDENT) + .value("PP_IGNORE", E_Token::CT_PP_IGNORE) + .value("PP_OTHER", E_Token::CT_PP_OTHER) + .value("CHAR", E_Token::CT_CHAR) + .value("DEFINED", E_Token::CT_DEFINED) + .value("FORWARD", E_Token::CT_FORWARD) + .value("NATIVE", E_Token::CT_NATIVE) + .value("STATE", E_Token::CT_STATE) + .value("STOCK", E_Token::CT_STOCK) + .value("TAGOF", E_Token::CT_TAGOF) + .value("DOT", E_Token::CT_DOT) + .value("TAG", E_Token::CT_TAG) + .value("TAG_COLON", E_Token::CT_TAG_COLON) + .value("LOCK", E_Token::CT_LOCK) + .value("AS", E_Token::CT_AS) + .value("IN", E_Token::CT_IN) + .value("BRACED", E_Token::CT_BRACED) + .value("THIS", E_Token::CT_THIS) + .value("BASE", E_Token::CT_BASE) + .value("DEFAULT", E_Token::CT_DEFAULT) + .value("GETSET", E_Token::CT_GETSET) + .value("GETSET_EMPTY", E_Token::CT_GETSET_EMPTY) + .value("CONCAT", E_Token::CT_CONCAT) + .value("CS_SQ_STMT", E_Token::CT_CS_SQ_STMT) + .value("CS_SQ_COLON", E_Token::CT_CS_SQ_COLON) + .value("CS_PROPERTY", E_Token::CT_CS_PROPERTY) + .value("SQL_EXEC", E_Token::CT_SQL_EXEC) + .value("SQL_BEGIN", E_Token::CT_SQL_BEGIN) + .value("SQL_END", E_Token::CT_SQL_END) + .value("SQL_WORD", E_Token::CT_SQL_WORD) + .value("SQL_ASSIGN", E_Token::CT_SQL_ASSIGN) + .value("CONSTRUCT", E_Token::CT_CONSTRUCT) + .value("LAMBDA", E_Token::CT_LAMBDA) + .value("ASSERT", E_Token::CT_ASSERT) + .value("ANNOTATION", E_Token::CT_ANNOTATION) + .value("FOR_COLON", E_Token::CT_FOR_COLON) + .value("DOUBLE_BRACE", E_Token::CT_DOUBLE_BRACE) + .value("CNG_HASINC", E_Token::CT_CNG_HASINC) + .value("CNG_HASINCN", E_Token::CT_CNG_HASINCN) + .value("Q_EMIT", E_Token::CT_Q_EMIT) + .value("Q_FOREACH", E_Token::CT_Q_FOREACH) + .value("Q_FOREVER", E_Token::CT_Q_FOREVER) + .value("Q_GADGET", E_Token::CT_Q_GADGET) + .value("Q_OBJECT", E_Token::CT_Q_OBJECT) + .value("MODE", E_Token::CT_MODE) + .value("DI", E_Token::CT_DI) + .value("HI", E_Token::CT_HI) + .value("QI", E_Token::CT_QI) + .value("SI", E_Token::CT_SI) + .value("NOTHROW", E_Token::CT_NOTHROW) + .value("WORD_", E_Token::CT_WORD_); + + enum_<lang_flag_e>("Language") + .value("C", lang_flag_e::LANG_C) + .value("CPP", lang_flag_e::LANG_CPP) + .value("D", lang_flag_e::LANG_D) + .value("CS", lang_flag_e::LANG_CS) + .value("JAVA", lang_flag_e::LANG_JAVA) + .value("OC", lang_flag_e::LANG_OC) + .value("VALA", lang_flag_e::LANG_VALA) + .value("PAWN", lang_flag_e::LANG_PAWN) + .value("ECMA", lang_flag_e::LANG_ECMA); + + // endregion enum bindings + + register_vector<std::string>("strings"); + + class_<GenericOption>("GenericOption") + .function("type", &GenericOption::type) + .function("description", select_overload<std::string(const GenericOption &)>( + [](const GenericOption &o) + { + return((o.description() != nullptr) ? string(o.description()) : ""); + })) + .function("name", select_overload<std::string(const GenericOption &)>( + [](const GenericOption &o) + { + return((o.name() != nullptr) ? string(o.name()) : ""); + })) + .function("possible_values", select_overload<std::vector<std::string>(const GenericOption &)>( + [](const GenericOption &o) + { + std::vector<std::string> strings; + + auto ptr = o.possibleValues(); + + for (auto c = *ptr; c; c = *++ptr) + { + strings.push_back(std::string{ c }); + } + + return(strings); + })) + .function("default", &GenericOption::defaultStr) + .function("min", &GenericOption::minStr) + .function("max", &GenericOption::maxStr) + .function("is_default", &GenericOption::isDefault) + .function("reset", &GenericOption::reset) + .function("set", select_overload<bool(GenericOption &o, const std::string &s)>( + [](GenericOption &o, const std::string &s) + { + return(o.read(s.c_str())); + })) + .function("value", &GenericOption::str); + + register_vector<GenericOption *>("options"); + + class_<Option<iarf_e>, base<GenericOption> >("OptionIARF") + .function("value", &Option<iarf_e>::operator()); + + class_<Option<line_end_e>, base<GenericOption> >("OptionLineEnd") + .function("value", &Option<line_end_e>::operator()); + + class_<Option<token_pos_e>, base<GenericOption> >("OptionTokenPos") + .function("value", &Option<token_pos_e>::operator()); + + class_<Option<unsigned>, base<GenericOption> >("OptionUnsigned") + .function("value", &Option<unsigned>::operator()); + + class_<Option<signed>, base<GenericOption> >("OptionSigned") + .function("value", &Option<signed>::operator()); + + class_<Option<std::string>, base<GenericOption> >("OptionString") + .function("value", &Option<std::string>::operator()); + + class_<OptionGroup>("OptionGroup") + .property("description", select_overload<std::string(const OptionGroup &)>( + [](const OptionGroup &g) + { + return(std::string(g.description)); + })) + .property("options", &OptionGroup::options); + + register_vector<OptionGroup *>("groups"); + + emscripten::function("get_options", &get_options); + emscripten::function("get_groups", &get_groups); + + emscripten::function("_initialize", &_initialize); + emscripten::function("destruct", &destruct); + + emscripten::function("get_version", &get_version); + + emscripten::function("add_keyword", &_add_keyword); + emscripten::function("clear_keywords", &clear_keywords); + + emscripten::function("reset_options", &reset_options); + emscripten::function("option_reset_value", &reset_option); + emscripten::function("option_set_value", &set_option); + emscripten::function("option_get_value", &get_option); + + emscripten::function("_load_config", &_loadConfig); + emscripten::function("show_config", select_overload<string(bool, bool)>(&show_config)); + emscripten::function("show_config", select_overload<string(bool)>(&show_config)); + emscripten::function("show_config", select_overload<string()>(&show_config)); + + emscripten::function("log_type_enable", &log_set_sev); + emscripten::function("log_type_show_name", &show_log_type); + emscripten::function("quiet", &set_quiet); + + emscripten::function("_uncrustify", select_overload<intptr_t(intptr_t, lang_flag_e, bool, bool)>(&_uncrustify)); + emscripten::function("_uncrustify", select_overload<intptr_t(intptr_t, lang_flag_e, bool)>(&_uncrustify)); + emscripten::function("_uncrustify", select_overload<intptr_t(intptr_t, lang_flag_e)>(&_uncrustify)); + + emscripten::function("_debug", select_overload<intptr_t(intptr_t, lang_flag_e, bool)>(&_debug)); + emscripten::function("_debug", select_overload<intptr_t(intptr_t, lang_flag_e)>(&_debug)); +}; + +#endif diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify_limits.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify_limits.h new file mode 100644 index 00000000..9f226870 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify_limits.h @@ -0,0 +1,19 @@ +#pragma once + +namespace uncrustify +{ + +namespace limits +{ + +static constexpr int MAX_OPTION_NAME_LEN = 32; +static constexpr int AL_SIZE = 8000; +static constexpr int MAX_KEYWORDS = 300; + +// uncrustify doesn't support more than one variable definition per line/ type, +// the maximum level of pointer indirection is 3 (i.e., ***p). +// TODO add some more limitations + +} // namespace limits + +} // namespace uncrustify diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify_types.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify_types.cpp new file mode 100644 index 00000000..bd57f2d5 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify_types.cpp @@ -0,0 +1,88 @@ +/** + * @file uncrustify_types.cpp + * Defines some types for the uncrustify program + * + * @author Guy Maurel + * @license GPL v2+ + */ + +#include "uncrustify_types.h" + + +const char *get_brace_stage_name(brace_stage_e brace_stage) +{ + switch (brace_stage) + { + case brace_stage_e::NONE: + return("NONE"); + + case brace_stage_e::PAREN1: + return("PAREN1"); + + case brace_stage_e::OP_PAREN1: + return("OP_PAREN1"); + + case brace_stage_e::WOD_PAREN: + return("WOD_PAREN"); + + case brace_stage_e::WOD_SEMI: + return("WOD_SEMI"); + + case brace_stage_e::BRACE_DO: + return("BRACE_DO"); + + case brace_stage_e::BRACE2: + return("BRACE2"); + + case brace_stage_e::ELSE: + return("ELSE"); + + case brace_stage_e::ELSEIF: + return("ELSEIF"); + + case brace_stage_e::WHILE: + return("WHILE"); + + case brace_stage_e::CATCH: + return("CATCH"); + + case brace_stage_e::CATCH_WHEN: + return("CATCH_WHEN"); + } + return("?????"); +} // get_brace_stage_name + + +const char *get_unc_stage_name(unc_stage_e unc_stage) +{ + switch (unc_stage) + { + case unc_stage_e::TOKENIZE: + return("TOKENIZE"); + + case unc_stage_e::HEADER: + return("HEADER"); + + case unc_stage_e::TOKENIZE_CLEANUP: + return("TOKENIZE_CLEANUP"); + + case unc_stage_e::BRACE_CLEANUP: + return("BRACE_CLEANUP"); + + case unc_stage_e::FIX_SYMBOLS: + return("FIX_SYMBOLS"); + + case unc_stage_e::MARK_COMMENTS: + return("MARK_COMMENTS"); + + case unc_stage_e::COMBINE_LABELS: + return("COMBINE_LABELS"); + + case unc_stage_e::OTHER: + return("OTHER"); + + case unc_stage_e::CLEANUP: + return("CLEANUP"); + } + return("?????"); +} // get_unc_stage_name diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify_types.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify_types.h new file mode 100644 index 00000000..402c7922 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify_types.h @@ -0,0 +1,281 @@ +/** + * @file uncrustify_types.h + * + * Defines some types for the uncrustify program + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef UNCRUSTIFY_TYPES_H_INCLUDED +#define UNCRUSTIFY_TYPES_H_INCLUDED + +#include "options.h" +#include "pcf_flags.h" +#include "token_enum.h" // E_Token +#include "unc_text.h" +#include "uncrustify_limits.h" + +#include <assert.h> +#include <cstddef> // do get the definition of size_t + +#ifdef HAVE_UTIME_H +#include <utime.h> +#endif + + +class ParseFrame; + + +/** + * abbreviations used: + * SS = star style + */ + +/** + * special strings to mark a part of the input file where + * uncrustify shall not change anything + */ +#define UNCRUSTIFY_OFF_TEXT " *INDENT-OFF*" +#define UNCRUSTIFY_ON_TEXT " *INDENT-ON*" + +/** + * @brief Macro to inform the compiler that a variable is intentionally + * not in use. + * + * @param [in] variableName: The unused variable. + */ +#define UNUSED(variableName) ((void)variableName) + + +//! Brace stage enum used in brace_cleanup +enum class brace_stage_e : unsigned int +{ + NONE, + PAREN1, //! expected paren after if/catch (C++)/for/switch/synchronized/while + OP_PAREN1, //! optional paren after catch (C#) + WOD_PAREN, //! while of do parens + WOD_SEMI, //! semicolon after while of do + BRACE_DO, //! do + BRACE2, //! if/catch/else/finally/for/switch/synchronized/while + ELSE, //! expecting 'else' after 'if' + ELSEIF, //! expecting 'if' after 'else' + WHILE, //! expecting 'while' after 'do' + CATCH, //! expecting 'catch' or 'finally' after 'try' + CATCH_WHEN, //! optional 'when' after 'catch' +}; + + +enum class char_encoding_e : unsigned int +{ + e_ASCII, //! 0-127 + e_BYTE, //! 0-255, not UTF-8 + e_UTF8, //! utf 8 bit wide + e_UTF16_LE, //! utf 16 bit wide, little endian + e_UTF16_BE //! utf 16 bit wide, big endian +}; + +enum class tracking_type_e : unsigned int +{ + TT_NONE, + TT_SPACE, + TT_NEWLINE +}; + + +class Chunk; //forward declaration + + +/** + * Sort of like the aligning stuff, but the token indent is relative to the + * indent of another chunk. This is needed, as that chunk may be aligned and + * so the indent cannot be determined in the indent code. + */ +struct T_IndentData +{ + Chunk *ref; + int delta; +}; + + +struct T_AlignData +{ + Chunk *next; //! nullptr or the chunk that should be under this one + bool right_align; //! AlignStack.m_right_align + size_t star_style; //! AlignStack.m_star_style + size_t amp_style; //! AlignStack.m_amp_style + int gap; //! AlignStack.m_gap + + /* + * col_adj is the amount to alter the column for the token. + * For example, a dangling '*' would be set to -1. + * A right-aligned word would be a positive value. + */ + int col_adj; + Chunk *ref; + Chunk *start; +}; + + +// for debugging purpose only +typedef std::pair<size_t, char *> Track_nr; // track for "trackNumber" and "rule" +typedef std::vector<Track_nr> track_list; // liste for many tracks + +//! list of all programming languages Uncrustify supports +enum lang_flag_e +{ + LANG_C = 0x0001, + LANG_CPP = 0x0002, + LANG_D = 0x0004, + LANG_CS = 0x0008, //! C# (C-Sharp) + LANG_JAVA = 0x0010, + LANG_OC = 0x0020, //! Objective-C + LANG_VALA = 0x0040, + LANG_PAWN = 0x0080, + LANG_ECMA = 0x0100, //! ECMA Script (JavaScript) + + LANG_ALLC = 0x017f, /** LANG_C | LANG_CPP | LANG_D | LANG_CS | + * LANG_JAVA | LANG_OC | LANG_VALA | LANG_ECMA */ + LANG_ALL = 0x0fff, //! applies to all languages + + FLAG_HDR = 0x2000, /*<< Header file for C family languages */ + FLAG_DIG = 0x4000, //! digraph/trigraph + FLAG_PP = 0x8000, //! only appears in a preprocessor +}; + +//! Pattern classes for special keywords +enum class pattern_class_e : unsigned int +{ + NONE, + BRACED, /** keyword + braced statement: + * do, try, finally, body, unittest, unsafe, volatile + * add, get, remove, set */ + PBRACED, /** keyword + parens + braced statement: + * if, elseif, switch, for, while, synchronized, + * using, lock, with, version, CT_D_SCOPE_IF */ + OPBRACED, /** keyword + optional parens + braced statement: + * catch, version, debug */ + VBRACED, /** keyword + value + braced statement: + * namespace */ + PAREN, /** keyword + parens: + * while-of-do */ + OPPAREN, /** keyword + optional parens: + * invariant (D lang) */ + ELSE, /** Special case of pattern_class_e::BRACED for handling CT_IF + * else */ +}; + +//! used to link language keywords with some addition information +struct chunk_tag_t +{ + const char *tag; //! name of the keyword e.g. "bool" + E_Token type; //! uncrustify type assigned to that keyword + size_t lang_flags; //! programming language that uses this keyword +}; + + +struct align_t +{ + size_t col; + E_Token type; + size_t len; //! length of the token + space + Chunk *ref; // Issue #3786 +}; + +//! holds information and data of a file +struct file_mem +{ + std::vector<UINT8> raw; //! raw content of file + std::deque<int> data; //! processed content of file + bool bom; + char_encoding_e enc; //! character encoding of file ASCII, utf, etc. +#ifdef HAVE_UTIME_H + struct utimbuf utb; +#endif +}; + +enum class unc_stage_e : unsigned int +{ + TOKENIZE, + HEADER, + TOKENIZE_CLEANUP, + BRACE_CLEANUP, + FIX_SYMBOLS, + MARK_COMMENTS, + COMBINE_LABELS, + OTHER, + CLEANUP +}; + +struct cp_data_t +{ + std::deque<UINT8> *bout; + FILE *fout; + int last_char; + bool do_check; + unc_stage_e unc_stage; + int check_fail_cnt; //! total failure count + bool if_changed; + + std::string filename; + + file_mem file_hdr; // for cmt_insert_file_header + file_mem file_ftr; // for cmt_insert_file_footer + file_mem func_hdr; // for cmt_insert_func_header + file_mem oc_msg_hdr; // for cmt_insert_oc_msg_header + file_mem class_hdr; // for cmt_insert_class_header + file_mem reflow_fold_regex; // for cmt_reflow_fold_regex_file + + size_t lang_flags; //! defines the language of the source input + bool lang_forced; //! overwrites automatic language detection + + bool unc_off; + bool unc_off_used; //! true if the `disable_processing_cmt` option was actively used in the processed file + UINT32 line_number; + size_t column; //! column for parsing + UINT16 spaces; //! space count on output + + int ifdef_over_whole_file; + + bool frag; //! activates code fragment option + UINT32 frag_cols; + + // stuff to auto-detect line endings + UINT32 le_counts[uncrustify::line_end_styles]; + unc_text newline; + + bool did_newline; //! flag indicates if a newline was added or converted + E_Token in_preproc; + int preproc_ncnl_count; + bool output_trailspace; + bool output_tab_as_space; + + bool bom; + char_encoding_e enc; + + // bumped up when a line is split or indented + int changes; + int pass_count; //! indicates how often the chunk list shall be processed + + align_t al[uncrustify::limits::AL_SIZE]; + size_t al_cnt; + bool al_c99_array; + + bool warned_unable_string_replace_tab_chars; + + int pp_level; // TODO: can this ever be -1? + + const char *phase_name; + const char *dumped_file; + // for debugging purpose only + tracking_type_e html_type = tracking_type_e::TT_NONE; + const char *html_file = nullptr; +}; + +extern cp_data_t cpd; // TODO: can we avoid this external variable? + +const char *get_brace_stage_name(brace_stage_e brace_stage); + +const char *get_unc_stage_name(unc_stage_e unc_stage); + +#endif /* UNCRUSTIFY_TYPES_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify_version.h.in b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify_version.h.in new file mode 100644 index 00000000..079e0fa6 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/uncrustify_version.h.in @@ -0,0 +1,18 @@ +/** + * @file uncrustify_version.h + * Simply defines UNCRUSTIFY_VERSION. + * I don't particularly like how autoconf and friends handle the version... + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef UNCRUSTIFY_VERSION_H_INCLUDED +#define UNCRUSTIFY_VERSION_H_INCLUDED + +#ifdef DEBUG +#define UNCRUSTIFY_VERSION "Uncrustify_d-@UNCRUSTIFY_VERSION@" +#else +#define UNCRUSTIFY_VERSION "Uncrustify-@UNCRUSTIFY_VERSION@" +#endif + +#endif /* UNCRUSTIFY_VERSION_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unicode.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unicode.cpp new file mode 100644 index 00000000..0acd4ddb --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unicode.cpp @@ -0,0 +1,580 @@ +/** + * @file unicode.cpp + * Detects, read and writes characters in the proper format. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "unicode.h" + + +using namespace std; + + +//! See if all characters are ASCII (0-127) +static bool is_ascii(const vector<UINT8> &data, size_t &non_ascii_cnt, size_t &zero_cnt); + + +//! Convert the array of bytes into an array of ints +static bool decode_bytes(const vector<UINT8> &in_data, deque<int> &out_data); + + +/** + * Decode UTF-8 sequences from in_data and put the chars in out_data. + * If there are any decoding errors, then return false. + */ +static bool decode_utf8(const vector<UINT8> &in_data, deque<int> &out_data); + + +/** + * Extract 2 bytes from the stream and increment idx by 2 + * + * @param in byte vector with input data + * @param idx index points to working position in vector + */ +static int get_word(const vector<UINT8> &in_data, size_t &idx, bool be); + + +/** + * Decode a UTF-16 sequence. + * Sets enc based on the BOM. + * Must have the BOM as the first two bytes. + */ +static bool decode_utf16(const vector<UINT8> &in_data, deque<int> &out_data, char_encoding_e &enc); + + +/** + * Looks for the BOM of UTF-16 BE/LE and UTF-8. + * If found, set enc and return true. + * Sets enc to char_encoding_e::e_ASCII and returns false if not found. + */ +static bool decode_bom(const vector<UINT8> &in_data, char_encoding_e &enc); + + +//! Write for ASCII and BYTE encoding +static void write_byte(int ch); + + +//! Writes a single character to a file using UTF-8 encoding +static void write_utf8(int ch); + + +static void write_utf16(int ch, bool be); + + +static bool is_ascii(const vector<UINT8> &data, size_t &non_ascii_cnt, size_t &zero_cnt) +{ + non_ascii_cnt = 0; + zero_cnt = 0; + + for (unsigned char value : data) + { + if (value & 0x80) + { + non_ascii_cnt++; + } + + if (!value) + { + zero_cnt++; + } + } + + return((non_ascii_cnt + zero_cnt) == 0); +} + + +static bool decode_bytes(const vector<UINT8> &in_data, deque<int> &out_data) +{ + out_data.resize(in_data.size()); + + for (size_t idx = 0; idx < in_data.size(); idx++) + { + out_data[idx] = in_data[idx]; + } + + return(true); +} + + +void encode_utf8(int ch, vector<UINT8> &res) +{ + if (ch < 0) + { + // illegal code - do not store + } + else if (ch < 0x80) + { + // 0xxxxxxx + res.push_back(ch); + } + else if (ch < 0x0800) + { + // 110xxxxx 10xxxxxx + res.push_back(0xC0 | (ch >> 6)); + res.push_back(0x80 | (ch & 0x3f)); + } + else if (ch < 0x10000) + { + // 1110xxxx 10xxxxxx 10xxxxxx + res.push_back(0xE0 | (ch >> 12)); + res.push_back(0x80 | ((ch >> 6) & 0x3f)); + res.push_back(0x80 | (ch & 0x3f)); + } + else if (ch < 0x200000) + { + // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + res.push_back(0xF0 | (ch >> 18)); + res.push_back(0x80 | ((ch >> 12) & 0x3f)); + res.push_back(0x80 | ((ch >> 6) & 0x3f)); + res.push_back(0x80 | (ch & 0x3f)); + } + else if (ch < 0x4000000) + { + // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + res.push_back(0xF8 | (ch >> 24)); + res.push_back(0x80 | ((ch >> 18) & 0x3f)); + res.push_back(0x80 | ((ch >> 12) & 0x3f)); + res.push_back(0x80 | ((ch >> 6) & 0x3f)); + res.push_back(0x80 | (ch & 0x3f)); + } + else // (ch <= 0x7fffffff) + { + // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + res.push_back(0xFC | (ch >> 30)); + res.push_back(0x80 | ((ch >> 24) & 0x3f)); + res.push_back(0x80 | ((ch >> 18) & 0x3f)); + res.push_back(0x80 | ((ch >> 12) & 0x3f)); + res.push_back(0x80 | ((ch >> 6) & 0x3f)); + res.push_back(0x80 | (ch & 0x3f)); + } +} // encode_utf8 + + +static bool decode_utf8(const vector<UINT8> &in_data, deque<int> &out_data) +{ + size_t idx = 0; + int cnt; + + out_data.clear(); + + // check for UTF-8 BOM silliness and skip + if (in_data.size() >= 3) + { + if ( (in_data[0] == 0xef) + && (in_data[1] == 0xbb) + && (in_data[2] == 0xbf)) + { + idx = 3; // skip it + } + } + + while (idx < in_data.size()) + { + int ch = in_data[idx++]; + + if (ch < 0x80) // 1-byte sequence + { + out_data.push_back(ch); + continue; + } + else if ((ch & 0xE0) == 0xC0) // 2-byte sequence + { + ch &= 0x1F; + cnt = 1; + } + else if ((ch & 0xF0) == 0xE0) // 3-byte sequence + { + ch &= 0x0F; + cnt = 2; + } + else if ((ch & 0xF8) == 0xF0) // 4-byte sequence + { + ch &= 0x07; + cnt = 3; + } + else if ((ch & 0xFC) == 0xF8) // 5-byte sequence + { + ch &= 0x03; + cnt = 4; + } + else if ((ch & 0xFE) == 0xFC) // 6-byte sequence + { + ch &= 0x01; + cnt = 5; + } + else + { + // invalid UTF-8 sequence + return(false); + } + + while ( cnt-- > 0 + && idx < in_data.size()) + { + int tmp = in_data[idx++]; + + if ((tmp & 0xC0) != 0x80) + { + // invalid UTF-8 sequence + return(false); + } + ch = (ch << 6) | (tmp & 0x3f); + } + + if (cnt >= 0) + { + // short UTF-8 sequence + return(false); + } + out_data.push_back(ch); + } + return(true); +} // decode_utf8 + + +static int get_word(const vector<UINT8> &in_data, size_t &idx, bool be) +{ + int ch; + + if ((idx + 2) > in_data.size()) + { + ch = -1; + } + else if (be) + { + ch = (in_data[idx] << 8) | in_data[idx + 1]; + } + else + { + ch = in_data[idx] | (in_data[idx + 1] << 8); + } + idx += 2; + return(ch); +} + + +static bool decode_utf16(const vector<UINT8> &in_data, deque<int> &out_data, char_encoding_e &enc) +{ + out_data.clear(); + + if (in_data.size() & 1) + { + // can't have and odd length + return(false); + } + + if (in_data.size() < 2) + { + // we require the BOM or at least 1 char + return(false); + } + size_t idx = 2; + + if ( (in_data[0] == 0xfe) + && (in_data[1] == 0xff)) + { + enc = char_encoding_e::e_UTF16_BE; + } + else if ( (in_data[0] == 0xff) + && (in_data[1] == 0xfe)) + { + enc = char_encoding_e::e_UTF16_LE; + } + else + { + /* + * If we have a few words, we can take a guess, assuming the first few + * chars are ASCII + */ + enc = char_encoding_e::e_ASCII; + idx = 0; + + if (in_data.size() >= 6) + { + if ( (in_data[0] == 0) + && (in_data[2] == 0) + && (in_data[4] == 0)) + { + enc = char_encoding_e::e_UTF16_BE; + } + else if ( (in_data[1] == 0) + && (in_data[3] == 0) + && (in_data[5] == 0)) + { + enc = char_encoding_e::e_UTF16_LE; + } + } + + if (enc == char_encoding_e::e_ASCII) + { + return(false); + } + } + bool be = (enc == char_encoding_e::e_UTF16_BE); + + while (idx < in_data.size()) + { + int ch = get_word(in_data, idx, be); + + if ((ch & 0xfc00) == 0xd800) + { + ch &= 0x3ff; + ch <<= 10; + int tmp = get_word(in_data, idx, be); + + if ((tmp & 0xfc00) != 0xdc00) + { + return(false); + } + ch |= (tmp & 0x3ff); + ch += 0x10000; + out_data.push_back(ch); + } + else if ( ( ch >= 0 + && ch < 0xD800) + || ch >= 0xE000) + { + out_data.push_back(ch); + } + else + { + // invalid character + return(false); + } + } + return(true); +} // decode_utf16 + + +static bool decode_bom(const vector<UINT8> &in_data, char_encoding_e &enc) +{ + enc = char_encoding_e::e_ASCII; + + if (in_data.size() >= 2) + { + if ( (in_data[0] == 0xfe) + && (in_data[1] == 0xff)) + { + enc = char_encoding_e::e_UTF16_BE; + return(true); + } + + if ( (in_data[0] == 0xff) + && (in_data[1] == 0xfe)) + { + enc = char_encoding_e::e_UTF16_LE; + return(true); + } + + if ( (in_data.size() >= 3) + && (in_data[0] == 0xef) + && (in_data[1] == 0xbb) + && (in_data[2] == 0xbf)) + { + enc = char_encoding_e::e_UTF8; + return(true); + } + } + return(false); +} + + +bool decode_unicode(const vector<UINT8> &in_data, deque<int> &out_data, char_encoding_e &enc, bool &has_bom) +{ + // check for a BOM + if (decode_bom(in_data, enc)) + { + has_bom = true; + + if (enc == char_encoding_e::e_UTF8) + { + return(decode_utf8(in_data, out_data)); + } + return(decode_utf16(in_data, out_data, enc)); + } + has_bom = false; + + // Check for simple ASCII + size_t non_ascii_cnt; + size_t zero_cnt; + + if (is_ascii(in_data, non_ascii_cnt, zero_cnt)) + { + enc = char_encoding_e::e_ASCII; + return(decode_bytes(in_data, out_data)); + } + + // There are a lot of 0's in UTF-16 (~50%) + if ( (zero_cnt > (in_data.size() / 4)) + && (zero_cnt <= (in_data.size() / 2))) + { + // likely is UTF-16 + if (decode_utf16(in_data, out_data, enc)) + { + return(true); + } + } + + if (decode_utf8(in_data, out_data)) + { + enc = char_encoding_e::e_UTF8; + return(true); + } + // it is an unrecognized byte sequence + enc = char_encoding_e::e_BYTE; + return(decode_bytes(in_data, out_data)); +} // decode_unicode + + +static void write_byte(int ch) +{ + if ((ch & 0xff) == ch) + { + if (cpd.fout) + { + fputc(ch, cpd.fout); + } + + if (cpd.bout) + { + cpd.bout->push_back(static_cast<UINT8>(ch)); + } + } + else + { + // illegal code - do not store + } +} + + +static void write_utf8(int ch) +{ + vector<UINT8> vv; + + vv.reserve(6); + + encode_utf8(ch, vv); + + for (unsigned char char_val : vv) + { + write_byte(char_val); + } +} + + +static void write_utf16(int ch, bool be) +{ + // U+0000 to U+D7FF and U+E000 to U+FFFF + if ( ( ch >= 0 + && ch < 0xD800) + || ( ch >= 0xE000 + && ch < 0x10000)) + { + if (be) + { + write_byte(ch >> 8); + write_byte(ch & 0xff); + } + else + { + write_byte(ch & 0xff); + write_byte(ch >> 8); + } + } + else if ( ch >= 0x10000 + && ch < 0x110000) + { + int v1 = ch - 0x10000; + int w1 = 0xD800 + (v1 >> 10); + int w2 = 0xDC00 + (v1 & 0x3ff); + + if (be) + { + write_byte(w1 >> 8); + write_byte(w1 & 0xff); + write_byte(w2 >> 8); + write_byte(w2 & 0xff); + } + else + { + write_byte(w1 & 0xff); + write_byte(w1 >> 8); + write_byte(w2 & 0xff); + write_byte(w2 >> 8); + } + } + else + { + // illegal code - do not store + } +} // write_utf16 + + +void write_bom() +{ + switch (cpd.enc) + { + case char_encoding_e::e_UTF8: + write_byte(0xef); + write_byte(0xbb); + write_byte(0xbf); + break; + + case char_encoding_e::e_UTF16_LE: + write_utf16(0xfeff, false); + break; + + case char_encoding_e::e_UTF16_BE: + write_utf16(0xfeff, true); + break; + + default: + // char_encoding_e::e_ASCII + // char_encoding_e::e_BYTE + // do nothing + // Coveralls will complain + break; + } +} + + +void write_char(int ch) +{ + if (ch >= 0) + { + switch (cpd.enc) + { + case char_encoding_e::e_BYTE: + write_byte(ch & 0xff); + break; + + case char_encoding_e::e_ASCII: + default: + write_byte(ch); + break; + + case char_encoding_e::e_UTF8: + write_utf8(ch); + break; + + case char_encoding_e::e_UTF16_LE: + write_utf16(ch, false); + break; + + case char_encoding_e::e_UTF16_BE: + write_utf16(ch, true); + break; + } + } +} + + +void write_string(const unc_text &text) +{ + for (size_t idx = 0; idx < text.size(); idx++) + { + write_char(text[idx]); + } +} diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unicode.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unicode.h new file mode 100644 index 00000000..7217778b --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/unicode.h @@ -0,0 +1,34 @@ +/** + * @file unicode.h + * prototypes for unicode.c + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef UNICODE_H_INCLUDED +#define UNICODE_H_INCLUDED + +#include "uncrustify_types.h" + + +void write_bom(); + + +/** + * @param ch the 31-bit char value + */ +void write_char(int ch); + + +void write_string(const unc_text &text); + + +//! Figure out the encoding and convert to an int sequence +bool decode_unicode(const std::vector<UINT8> &in_data, std::deque<int> &out_data, char_encoding_e &enc, bool &has_bom); + + +void encode_utf8(int ch, std::vector<UINT8> &res); + + +#endif /* UNICODE_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/universalindentgui.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/universalindentgui.cpp new file mode 100644 index 00000000..12c66b5c --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/universalindentgui.cpp @@ -0,0 +1,372 @@ +/** + * @file universalindentgui.cpp + * Exports the config file for UniversalIndentGUI + * + * @author Ben Gardner + * @author Guy Maurel since version 0.62 for uncrustify4Qt + * October 2015, 2016 + * @license GPL v2+ + */ +#include "universalindentgui.h" + +#include "error_types.h" +#include "log_rules.h" +#include "prototypes.h" +#include "unc_ctype.h" +#include "uncrustify.h" +#include "uncrustify_version.h" + +#include <cstdio> +#include <vector> + + +constexpr static auto LCURRENT = LOTHER; + +using namespace std; + + +std::vector<uncrustify::OptionGroup *> get_option_groups() +{ + std::vector<uncrustify::OptionGroup *> groups; + size_t i = 0; + + while (auto *const g = uncrustify::get_option_group(i)) + { + groups.push_back(g); + ++i; + } + return(groups); +} + + +void print_option_choices(FILE *pfile, uncrustify::GenericOption *option, + char const *key = "Choices") +{ + fprintf(pfile, "%s=", key); + + for (auto c = option->possibleValues(); *c; ++c) + { + fprintf(pfile, "%s=%s%c", option->name(), *c, c[1] ? '|' : '\n'); + } +} + + +void print_universal_indent_cfg(FILE *pfile) +{ + const char *p_name; + char ch = '='; + const auto &groups = get_option_groups(); + size_t idx; + +#if defined (DEBUG) && !defined (WIN32) + vector<size_t> allGroups; + allGroups.reserve(16); + // first run to get the first option number of each group/category + size_t optionNumber = 0; + bool firstOptionNumberSet = false; + + for (idx = 0; idx < groups.size(); ++idx) + { + const auto *p_grp = groups[idx]; + + for (auto *const option : p_grp->options) + { + UNUSED(option); + + if (!firstOptionNumberSet) + { + allGroups[idx] = optionNumber; + firstOptionNumberSet = true; + } + optionNumber++; + } // for (auto *const option : p_grp->options) + + firstOptionNumberSet = false; + } // end of first run + +//#else +// UNUSED(allGroups); +#endif // DEBUG + + // second run + // Dump the header and the categories + fprintf(pfile, "[header]\n"); + + // Add all the categories + //const auto &groups = get_option_groups(); + ch = '='; + + fprintf(pfile, "categories"); + idx = 0; +#if defined (DEBUG) && !defined (WIN32) + optionNumber = 0; +#endif // DEBUG + + for (auto *const g : groups) + { + fputc(ch, pfile); + ch = '|'; + +#if defined (DEBUG) && !defined (WIN32) + fprintf(pfile, "(%zu)", allGroups[idx]); +#endif // DEBUG + + // Write description, stripping leading and trailing newlines + for (auto dc = g->description + 1; *(dc + 1); ++dc) + { + fputc(*dc, pfile); + } + + idx++; + } + + fprintf(pfile, "\n"); + + fprintf(pfile, + "cfgFileParameterEnding=cr\n" + "configFilename=uncrustify.cfg\n"); + + + // Add all the recognized file extensions + ch = '='; + int fileIdx = 0; + fprintf(pfile, "fileTypes"); + + while ((p_name = get_file_extension(fileIdx)) != nullptr) + { + fprintf(pfile, "%c*%s", ch, p_name); + ch = '|'; + } + fprintf(pfile, "\n"); + + // Add the rest of the constant file header + fprintf(pfile, + "indenterFileName=uncrustify\n" + "indenterName=Uncrustify (C, C++, C#, ObjectiveC, D, Java, Pawn, VALA)\n" + "inputFileName=indentinput\n" + "inputFileParameter=\"-f \"\n" + "manual=http://uncrustify.sourceforge.net/config.txt\n" + "outputFileName=indentoutput\n" + "outputFileParameter=\"-o \"\n" + "stringparaminquotes=false\n" + "parameterOrder=ipo\n" + "showHelpParameter=-h\n" + "stringparaminquotes=false\n" + "useCfgFileParameter=\"-c \"\n"); + + fprintf(pfile, "version=%s\n", UNCRUSTIFY_VERSION); + + ch = '='; + + // Now add each option + for (idx = 0; idx < groups.size(); ++idx) + { + const auto *p_grp = groups[idx]; + + for (auto *const option : p_grp->options) + { + /* + * Create a better readable name from the options name + * by replacing '_' by a space and use some upper case characters. + */ + char *optionNameReadable = new char[strlen(option->name()) + 1]; + strcpy(optionNameReadable, option->name()); + + bool was_space = true; + + for (char *character = optionNameReadable; *character != 0; character++) + { + if (*character == '_') + { + *character = ' '; + was_space = true; + } + else if (was_space) + { + *character = unc_toupper(*character); + was_space = false; + } + } + + fprintf(pfile, "\n[%s]\n", optionNameReadable); + fprintf(pfile, "Category=%zu\n", idx); +#if defined (DEBUG) && !defined (WIN32) + fprintf(pfile, "Description=\"<html>(%zu)", optionNumber); +#else // DEBUG + fprintf(pfile, "Description=\"<html>"); +#endif // DEBUG + + // Skip first character, which is always a newline + const char *tmp = option->description() + 1; + ch = 0; + + // Output the description which may contain forbidden chars, skipping + // the last character which is always an extra newline + while ( *tmp != 0 + && *(tmp + 1) != 0) + { + switch (*tmp) + { + case '<': + fputs("<", pfile); + break; + + case '>': + fputs(">", pfile); + break; + + case '&': + fputs("&", pfile); + break; + + case '\n': + fputs("<br/>", pfile); + break; + + default: + fputc(*tmp, pfile); + } + tmp++; + } + const auto ds = option->defaultStr(); + + if (!ds.empty()) + { + fprintf(pfile, "<br/><br/>Default: %s", ds.c_str()); + } + fprintf(pfile, "</html>\"\n"); + + // Handle some options independent of their type and most by their type. + log_rule_B("indent_with_tabs"); + + if (option == &uncrustify::options::indent_with_tabs) + { + // Indenting with tabs selector becomes a multiple selector and not + // only a number. Also it is by default enabled. + fprintf(pfile, "Enabled=true\n"); + fprintf(pfile, "EditorType=multiple\n"); + fprintf(pfile, "Choices=\"%s=0|%s=1|%s=2\"\n", + option->name(), option->name(), option->name()); +#if defined (DEBUG) && !defined (WIN32) + fprintf(pfile, "ChoicesReadable=\"(%zu)Spaces only|(%zu)Indent with tabs, align with spaces|(%zu)Indent and align with tabs\"\n", + optionNumber, optionNumber, optionNumber); +#else // DEBUG + fprintf(pfile, "ChoicesReadable=\"Spaces only|Indent with tabs, align with spaces|Indent and align with tabs\"\n"); +#endif // DEBUG + fprintf(pfile, "ValueDefault=%s\n", option->str().c_str()); + } + else + { + // All not specially handled options are created only dependent by + // their type. + fprintf(pfile, "Enabled=false\n"); + + switch (option->type()) + { + case uncrustify::OT_BOOL: + fprintf(pfile, "EditorType=boolean\n"); + print_option_choices(pfile, option, "TrueFalse"); + fprintf(pfile, "ValueDefault=%s\n", option->str().c_str()); + break; + + case uncrustify::OT_IARF: + fprintf(pfile, "EditorType=multiple\n"); + print_option_choices(pfile, option); +#if defined (DEBUG) && !defined (WIN32) + fprintf(pfile, "ChoicesReadable=\"(%zu)Ignore %s|(%zu)Add %s|(%zu)Remove %s|(%zu)Force %s\"\n", + optionNumber, optionNameReadable, + optionNumber, optionNameReadable, + optionNumber, optionNameReadable, + optionNumber, optionNameReadable); +#else // DEBUG + // 0 1 2 3 + fprintf(pfile, "ChoicesReadable=\"Ignore %s|Add %s|Remove %s|Force %s\"\n", + optionNameReadable, optionNameReadable, optionNameReadable, optionNameReadable); +#endif // DEBUG + fprintf(pfile, "ValueDefault=%s\n", option->str().c_str()); + break; + + case uncrustify::OT_NUM: + fprintf(pfile, "EditorType=numeric\n"); + fprintf(pfile, "CallName=\"%s=\"\n", option->name()); + fprintf(pfile, "MinVal=%s\n", option->minStr().c_str()); + fprintf(pfile, "MaxVal=%s\n", option->maxStr().c_str()); + fprintf(pfile, "ValueDefault=%s\n", option->str().c_str()); + break; + + case uncrustify::OT_UNUM: + fprintf(pfile, "EditorType=numeric\n"); + fprintf(pfile, "CallName=\"%s=\"\n", option->name()); + fprintf(pfile, "MinVal=%s\n", option->minStr().c_str()); + fprintf(pfile, "MaxVal=%s\n", option->maxStr().c_str()); + fprintf(pfile, "ValueDefault=%s\n", option->str().c_str()); + break; + + case uncrustify::OT_LINEEND: + fprintf(pfile, "EditorType=multiple\n"); + print_option_choices(pfile, option); +#if defined (DEBUG) && !defined (WIN32) + fprintf(pfile, "ChoicesReadable=\"(%zu)Newlines Unix|(%zu)Newlines Win|(%zu)Newlines Mac|(%zu)Newlines Auto\"\n", + optionNumber, optionNumber, optionNumber, optionNumber); +#else // DEBUG + fprintf(pfile, "ChoicesReadable=\"Newlines Unix|Newlines Win|Newlines Mac|Newlines Auto\"\n"); +#endif // DEBUG + fprintf(pfile, "ValueDefault=%s\n", option->str().c_str()); + break; + + case uncrustify::OT_TOKENPOS: + fprintf(pfile, "EditorType=multiple\n"); + // Issue #2300-a + print_option_choices(pfile, option); +#if defined (DEBUG) && !defined (WIN32) + fprintf(pfile, "ChoicesReadable=\"(%zu)Ignore %s|(%zu)Break %s|(%zu)Force %s|(%zu)Lead %s|(%zu)Trail %s|", + optionNumber, optionNameReadable, + optionNumber, optionNameReadable, + optionNumber, optionNameReadable, + optionNumber, optionNameReadable, + optionNumber, optionNameReadable); +#else // DEBUG + // 0 1 2 4 8 + fprintf(pfile, "ChoicesReadable=\"Ignore %s|Break %s|Force %s|Lead %s|Trail %s|", + optionNameReadable, optionNameReadable, optionNameReadable, + optionNameReadable, optionNameReadable); +#endif // DEBUG + // 16 5 6 9 10 +#if defined (DEBUG) && !defined (WIN32) + fprintf(pfile, "(%zu)Join %s|(%zu)Lead Break %s|(%zu)Lead Force %s|(%zu)Trail Break %s|(%zu)Trail Force %s\"\n", + optionNumber, optionNameReadable, + optionNumber, optionNameReadable, + optionNumber, optionNameReadable, + optionNumber, optionNameReadable, + optionNumber, optionNameReadable); +#else // DEBUG + fprintf(pfile, "Join %s|Lead Break %s|Lead Force %s|Trail Break %s|Trail Force %s\"\n", + optionNameReadable, optionNameReadable, optionNameReadable, + optionNameReadable, optionNameReadable); +#endif // DEBUG + fprintf(pfile, "ValueDefault=%s\n", option->str().c_str()); + break; + + case uncrustify::OT_STRING: + { + fprintf(pfile, "CallName=%s=\n", option->name()); + fprintf(pfile, "EditorType=string\n"); + fprintf(pfile, "ValueDefault=%s\n", option->str().c_str()); + break; + } + + default: + fprintf(stderr, "FATAL: Illegal option type %d for '%s'\n", + static_cast<int>(option->type()), option->name()); + log_flush(true); + exit(EX_SOFTWARE); + break; + } // switch + } +#if defined (DEBUG) && !defined (WIN32) + optionNumber++; +#endif // DEBUG + delete[] optionNameReadable; + } // for (auto *const option : p_grp->options) + } +} // print_universal_indent_cfg diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/universalindentgui.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/universalindentgui.h new file mode 100644 index 00000000..35a65167 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/universalindentgui.h @@ -0,0 +1,17 @@ +/** + * @file universalindentgui.h + * prototypes for universalindentgui.c + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef UNIVERSALINDENTGUI_H_INCLUDED +#define UNIVERSALINDENTGUI_H_INCLUDED + +#include "uncrustify_types.h" + + +void print_universal_indent_cfg(FILE *pfile); + + +#endif /* UNIVERSALINDENTGUI_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/width.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/width.cpp new file mode 100644 index 00000000..7734c90e --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/width.cpp @@ -0,0 +1,917 @@ +/** + * @file width.cpp + * Limits line width. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "width.h" + +#include "indent.h" +#include "newlines.h" +#include "prototypes.h" + + +constexpr static auto LCURRENT = LSPLIT; + +using namespace uncrustify; + + +/** + * abbreviations used: + * - fparen = function parenthesis + */ + +struct cw_entry +{ + Chunk *pc; + size_t pri; +}; + + +struct token_pri +{ + E_Token tok; + size_t pri; +}; + + +static inline bool is_past_width(Chunk *pc); + + +//! Split right after the chunk +static void split_before_chunk(Chunk *pc); + + +static size_t get_split_pri(E_Token tok); + + +/** + * Checks to see if pc is a better spot to split. + * This should only be called going BACKWARDS (ie prev) + * A lower level wins + * + * Splitting Preference: + * - semicolon + * - comma + * - boolean op + * - comparison + * - arithmetic op + * - assignment + * - concatenated strings + * - ? : + * - function open paren not followed by close paren + */ +static void try_split_here(cw_entry &ent, Chunk *pc); + + +/** + * Scan backwards to find the most appropriate spot to split the line + * and insert a newline. + * + * See if this needs special function handling. + * Scan backwards and find the best token for the split. + * + * @param start The first chunk that exceeded the limit + */ +static bool split_line(Chunk *pc); + + +/** + * Figures out where to split a function def/proto/call + * + * For function prototypes and definition. Also function calls where + * level == m_braceLevel: + * - find the open function parenthesis + * + if it doesn't have a newline right after it + * * see if all parameters will fit individually after the paren + * * if not, throw a newline after the open paren & return + * - scan backwards to the open fparen or comma + * + if there isn't a newline after that item, add one & return + * + otherwise, add a newline before the start token + * + * @param start the offending token + * @return the token that should have a newline + * inserted before it + */ +static void split_fcn_params(Chunk *start); + + +/** + * Figures out where to split a template + * + * + * @param start the offending token + */ +static void split_template(Chunk *start); + + +/** + * Splits the parameters at every comma that is at the fparen level. + * + * @param start the offending token + */ +static void split_fcn_params_full(Chunk *start); + + +/** + * A for statement is too long. + * Step backwards and forwards to find the semicolons + * Try splitting at the semicolons first. + * If that doesn't work, then look for a comma at paren level. + * If that doesn't work, then look for an assignment at paren level. + * If that doesn't work, then give up. + */ +static void split_for_stmt(Chunk *start); + + +static inline bool is_past_width(Chunk *pc) +{ + // allow char to sit at last column by subtracting 1 + LOG_FMT(LSPLIT, "%s(%d): orig line is %zu, orig col is %zu, for %s\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + log_rule_B("code_width"); + return((pc->GetColumn() + pc->Len() - 1) > options::code_width()); +} + + +static void split_before_chunk(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LSPLIT, "%s(%d): Text() '%s'\n", __func__, __LINE__, pc->Text()); + + if ( !pc->IsNewline() + && !pc->GetPrev()->IsNewline()) + { + newline_add_before(pc); + // reindent needs to include the indent_continue value and was off by one + log_rule_B("indent_columns"); + log_rule_B("indent_continue"); + reindent_line(pc, pc->GetBraceLevel() * options::indent_columns() + + abs(options::indent_continue()) + 1); + cpd.changes++; + } +} + + +void do_code_width() +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LSPLIT, "%s(%d)\n", __func__, __LINE__); + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if ( !pc->IsCommentOrNewline() + && pc->IsNot(CT_SPACE) + && is_past_width(pc)) + { + if ( pc->Is(CT_VBRACE_CLOSE) // don't break if a vbrace close + && pc->IsLastChunkOnLine()) // is the last chunk on its line + { + continue; + } + bool split_OK = split_line(pc); + + if (split_OK) + { + LOG_FMT(LSPLIT, "%s(%d): orig line is %zu, orig col is %zu, Text() '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + } + else + { + LOG_FMT(LSPLIT, "%s(%d): Bailed! orig line is %zu, orig col is %zu, Text() '%s'\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text()); + break; + } + } + } +} + + +static const token_pri pri_table[] = +{ + { CT_SEMICOLON, 1 }, + { CT_COMMA, 2 }, + { CT_BOOL, 3 }, + { CT_COMPARE, 4 }, + { CT_SHIFT, 5 }, + { CT_ARITH, 6 }, + { CT_CARET, 7 }, + { CT_ASSIGN, 8 }, + { CT_STRING, 9 }, + { CT_FOR_COLON, 10 }, + //{ CT_DC_MEMBER, 11 }, + //{ CT_MEMBER, 11 }, + { CT_QUESTION, 20 }, // allow break in ? : for ls_code_width + { CT_COND_COLON, 20 }, + { CT_FPAREN_OPEN, 21 }, // break after function open paren not followed by close paren + { CT_QUALIFIER, 25 }, + { CT_CLASS, 25 }, + { CT_STRUCT, 25 }, + { CT_TYPE, 25 }, + { CT_TYPENAME, 25 }, + { CT_VOLATILE, 25 }, +}; + + +static size_t get_split_pri(E_Token tok) +{ + for (auto token : pri_table) + { + if (token.tok == tok) + { + return(token.pri); + } + } + + return(0); +} + + +static void try_split_here(cw_entry &ent, Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + LOG_FMT(LSPLIT, "%s(%d): at %s, orig col=%zu\n", __func__, __LINE__, pc->Text(), pc->GetOrigCol()); + size_t pc_pri = get_split_pri(pc->GetType()); + + LOG_FMT(LSPLIT, "%s(%d): pc_pri is %zu\n", __func__, __LINE__, pc_pri); + + if (pc_pri == 0) + { + LOG_FMT(LSPLIT, "%s(%d): pc_pri is 0, return\n", __func__, __LINE__); + return; + } + LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__); + // Can't split after a newline + Chunk *prev = pc->GetPrev(); + + if ( prev->IsNullChunk() + || ( prev->IsNewline() + && pc->IsNot(CT_STRING))) + { + if (prev->IsNotNullChunk()) + { + LOG_FMT(LSPLIT, "%s(%d): Can't split after a newline, orig line is %zu, return\n", + __func__, __LINE__, prev->GetOrigLine()); + } + return; + } + LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__); + + // Can't split a function without arguments + if (pc->Is(CT_FPAREN_OPEN)) + { + Chunk *next = pc->GetNext(); + + if (next->Is(CT_FPAREN_CLOSE)) + { + LOG_FMT(LSPLIT, "%s(%d): Can't split a function without arguments, return\n", __func__, __LINE__); + return; + } + } + LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__); + + // Only split concatenated strings + if (pc->Is(CT_STRING)) + { + Chunk *next = pc->GetNext(); + + if (next->IsNot(CT_STRING)) + { + LOG_FMT(LSPLIT, "%s(%d): Only split concatenated strings, return\n", __func__, __LINE__); + return; + } + } + LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__); + + // keep common groupings unless ls_code_width + log_rule_B("ls_code_width"); + + if ( !options::ls_code_width() + && pc_pri >= 20) + { + LOG_FMT(LSPLIT, "%s(%d): keep common groupings unless ls_code_width, return\n", __func__, __LINE__); + return; + } + LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__); + + // don't break after last term of a qualified type + if (pc_pri == 25) + { + Chunk *next = pc->GetNext(); + + if ( next->IsNot(CT_WORD) + && (get_split_pri(next->GetType()) != 25)) + { + LOG_FMT(LSPLIT, "%s(%d): don't break after last term of a qualified type, return\n", __func__, __LINE__); + return; + } + } + LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__); + // Check levels first + bool change = false; + + if ( ent.pc == nullptr + || pc->GetLevel() < ent.pc->GetLevel()) + { + LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__); + change = true; + } + else + { + if (pc_pri < ent.pri) + { + LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__); + change = true; + } + } + LOG_FMT(LSPLIT, "%s(%d): change is %s\n", __func__, __LINE__, change ? "TRUE" : "FALSE"); + + if (change) + { + LOG_FMT(LSPLIT, "%s(%d): do the change\n", __func__, __LINE__); + ent.pc = pc; + ent.pri = pc_pri; + } +} // try_split_here + + +static bool split_line(Chunk *start) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LSPLIT, "%s(%d): start->Text() '%s', orig line is %zu, orig col is %zu, type is %s\n", + __func__, __LINE__, start->Text(), start->GetOrigLine(), start->GetOrigCol(), get_token_name(start->GetType())); + LOG_FMT(LSPLIT, " start->GetFlags() "); + log_pcf_flags(LSPLIT, start->GetFlags()); + LOG_FMT(LSPLIT, " start->GetParentType() %s, (PCF_IN_FCN_DEF is %s), (PCF_IN_FCN_CALL is %s)\n", + get_token_name(start->GetParentType()), + start->TestFlags((PCF_IN_FCN_DEF)) ? "TRUE" : "FALSE", + start->TestFlags((PCF_IN_FCN_CALL)) ? "TRUE" : "FALSE"); + + // break at maximum line length if ls_code_width is true + // Issue #2432 + if (start->TestFlags(PCF_ONE_LINER)) + { + LOG_FMT(LSPLIT, "%s(%d): ** ONCE LINER SPLIT **\n", __func__, __LINE__); + undo_one_liner(start); + newlines_cleanup_braces(false); + // Issue #1352 + cpd.changes++; + return(false); + } + LOG_FMT(LSPLIT, "%s(%d): before ls_code_width\n", __func__, __LINE__); + + log_rule_B("ls_code_width"); + + if (options::ls_code_width()) + { + } + // Check to see if we are in a for statement + else if (start->TestFlags(PCF_IN_FOR)) + { + LOG_FMT(LSPLIT, " ** FOR SPLIT **\n"); + split_for_stmt(start); + + if (!is_past_width(start)) + { + return(true); + } + LOG_FMT(LSPLIT, "%s(%d): for split didn't work\n", __func__, __LINE__); + } + + /* + * If this is in a function call or prototype, split on commas or right + * after the open parenthesis + */ + else if ( start->TestFlags(PCF_IN_FCN_DEF) + || start->GetParentType() == CT_FUNC_PROTO // Issue #1169 + || ( (start->GetLevel() == (start->GetBraceLevel() + 1)) + && start->TestFlags(PCF_IN_FCN_CALL))) + { + LOG_FMT(LSPLIT, " ** FUNC SPLIT **\n"); + + log_rule_B("ls_func_split_full"); + + if (options::ls_func_split_full()) + { + split_fcn_params_full(start); + + if (!is_past_width(start)) + { + return(true); + } + } + split_fcn_params(start); + return(true); + } + + /* + * If this is in a template, split on commas, Issue #1170 + */ + else if (start->TestFlags(PCF_IN_TEMPLATE)) + { + LOG_FMT(LSPLIT, " ** TEMPLATE SPLIT **\n"); + split_template(start); + return(true); + } + LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__); + // Try to find the best spot to split the line + cw_entry ent; + + memset(&ent, 0, sizeof(ent)); + Chunk *pc = start; + Chunk *prev; + + while ( ((pc = pc->GetPrev()) != nullptr) + && pc->IsNotNullChunk() + && !pc->IsNewline()) + { + LOG_FMT(LSPLIT, "%s(%d): at %s, orig line is %zu, orig col is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigLine(), pc->GetOrigCol()); + + if (pc->IsNot(CT_SPACE)) + { + try_split_here(ent, pc); + + // break at maximum line length + log_rule_B("ls_code_width"); + + if ( ent.pc != nullptr + && (options::ls_code_width())) + { + break; + } + } + } + + if (ent.pc == nullptr) + { + LOG_FMT(LSPLIT, "%s(%d): TRY_SPLIT yielded NO SOLUTION for orig line %zu at '%s' [%s]\n", + __func__, __LINE__, start->GetOrigLine(), start->Text(), get_token_name(start->GetType())); + } + else + { + LOG_FMT(LSPLIT, "%s(%d): TRY_SPLIT yielded '%s' [%s] on orig line %zu\n", + __func__, __LINE__, ent.pc->Text(), get_token_name(ent.pc->GetType()), ent.pc->GetOrigLine()); + LOG_FMT(LSPLIT, "%s(%d): ent at '%s', orig col is %zu\n", + __func__, __LINE__, ent.pc->Text(), ent.pc->GetOrigCol()); + } + + // Break before the token instead of after it according to the pos_xxx rules + if (ent.pc == nullptr) + { + pc = nullptr; + } + else + { + log_rule_B("pos_arith"); + log_rule_B("pos_assign"); + log_rule_B("pos_compare"); + log_rule_B("pos_conditional"); + log_rule_B("pos_shift"); + log_rule_B("pos_bool"); + + if ( ( ent.pc->Is(CT_SHIFT) + && (options::pos_shift() & TP_LEAD)) + || ( ( ent.pc->Is(CT_ARITH) + || ent.pc->Is(CT_CARET)) + && (options::pos_arith() & TP_LEAD)) + || ( ent.pc->Is(CT_ASSIGN) + && (options::pos_assign() & TP_LEAD)) + || ( ent.pc->Is(CT_COMPARE) + && (options::pos_compare() & TP_LEAD)) + || ( ( ent.pc->Is(CT_COND_COLON) + || ent.pc->Is(CT_QUESTION)) + && (options::pos_conditional() & TP_LEAD)) + || ( ent.pc->Is(CT_BOOL) + && (options::pos_bool() & TP_LEAD))) + { + pc = ent.pc; + } + else + { + pc = ent.pc->GetNext(); + } + LOG_FMT(LSPLIT, "%s(%d): at '%s', orig col is %zu\n", + __func__, __LINE__, pc->Text(), pc->GetOrigCol()); + } + + if ( pc == nullptr + || pc->IsNullChunk()) + { + pc = start; + + // Don't break before a close, comma, or colon + if ( start->Is(CT_PAREN_CLOSE) + || start->Is(CT_PAREN_OPEN) + || start->Is(CT_FPAREN_CLOSE) + || start->Is(CT_FPAREN_OPEN) + || start->Is(CT_SPAREN_CLOSE) + || start->Is(CT_SPAREN_OPEN) + || start->Is(CT_ANGLE_CLOSE) + || start->Is(CT_BRACE_CLOSE) + || start->Is(CT_COMMA) + || start->IsSemicolon() + || start->Len() == 0) + { + LOG_FMT(LSPLIT, " ** NO GO **\n"); + + // TODO: Add in logic to handle 'hard' limits by backing up a token + return(true); + } + } + // add a newline before pc + prev = pc->GetPrev(); + + if ( prev->IsNotNullChunk() + && !pc->IsNewline() + && !prev->IsNewline()) + { + //int plen = (pc->Len() < 5) ? pc->Len() : 5; + //int slen = (start->Len() < 5) ? start->Len() : 5; + //LOG_FMT(LSPLIT, " '%.*s' [%s], started on token '%.*s' [%s]\n", + // plen, pc->Text(), get_token_name(pc->GetType()), + // slen, start->Text(), get_token_name(start->GetType())); + LOG_FMT(LSPLIT, "%s(%d): Text() '%s', type %s, started on token '%s', type %s\n", + __func__, __LINE__, pc->Text(), get_token_name(pc->GetType()), + start->Text(), get_token_name(start->GetType())); + + split_before_chunk(pc); + } + return(true); +} // split_line + + +/* + * The for statement split algorithm works as follows: + * 1. Step backwards and forwards to find the semicolons + * 2. Try splitting at the semicolons first. + * 3. If that doesn't work, then look for a comma at paren level. + * 4. If that doesn't work, then look for an assignment at paren level. + * 5. If that doesn't work, then give up. + */ +static void split_for_stmt(Chunk *start) +{ + LOG_FUNC_ENTRY(); + // how many semicolons (1 or 2) do we need to find + log_rule_B("ls_for_split_full"); + size_t max_cnt = options::ls_for_split_full() ? 2 : 1; + Chunk *open_paren = nullptr; + size_t nl_cnt = 0; + + LOG_FMT(LSPLIT, "%s: starting on %s, line %zu\n", + __func__, start->Text(), start->GetOrigLine()); + + // Find the open paren so we know the level and count newlines + Chunk *pc = start; + + while ((pc = pc->GetPrev())->IsNotNullChunk()) + { + if (pc->Is(CT_SPAREN_OPEN)) + { + open_paren = pc; + break; + } + + if (pc->GetNlCount() > 0) + { + nl_cnt += pc->GetNlCount(); + } + } + + if (open_paren == nullptr) + { + LOG_FMT(LSPLIT, "No open paren\n"); + return; + } + // see if we started on the semicolon + int count = 0; + Chunk *st[2]; + + pc = start; + + if ( pc->Is(CT_SEMICOLON) + && pc->GetParentType() == CT_FOR) + { + st[count++] = pc; + } + + // first scan backwards for the semicolons + while ( (count < static_cast<int>(max_cnt)) + && ((pc = pc->GetPrev())->IsNotNullChunk()) + && pc->IsNotNullChunk() + && pc->TestFlags(PCF_IN_SPAREN)) + { + if ( pc->Is(CT_SEMICOLON) + && pc->GetParentType() == CT_FOR) + { + st[count++] = pc; + } + } + // And now scan forward + pc = start; + + while ( (count < static_cast<int>(max_cnt)) + && ((pc = pc->GetNext())->IsNotNullChunk()) + && pc->TestFlags(PCF_IN_SPAREN)) + { + if ( pc->Is(CT_SEMICOLON) + && pc->GetParentType() == CT_FOR) + { + st[count++] = pc; + } + } + + while (--count >= 0) + { + // TODO: st[0] may be uninitialized here + LOG_FMT(LSPLIT, "%s(%d): split before %s\n", __func__, __LINE__, st[count]->Text()); + split_before_chunk(st[count]->GetNext()); + } + + if ( !is_past_width(start) + || nl_cnt > 0) + { + return; + } + // Still past width, check for commas at parentheses level + pc = open_paren; + + while ((pc = pc->GetNext()) != start) + { + if ( pc->Is(CT_COMMA) + && (pc->GetLevel() == (open_paren->GetLevel() + 1))) + { + split_before_chunk(pc->GetNext()); + + if (!is_past_width(pc)) + { + return; + } + } + } + // Still past width, check for a assignments at parentheses level + pc = open_paren; + + while ((pc = pc->GetNext()) != start) + { + if ( pc->Is(CT_ASSIGN) + && (pc->GetLevel() == (open_paren->GetLevel() + 1))) + { + split_before_chunk(pc->GetNext()); + + if (!is_past_width(pc)) + { + return; + } + } + } + // Oh, well. We tried. +} // split_for_stmt + + +static void split_fcn_params_full(Chunk *start) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LSPLIT, "%s(%d): %s\n", __func__, __LINE__, start->Text()); + + // Find the opening function parenthesis + Chunk *fpo = start; + + LOG_FMT(LSPLIT, " %s(%d): Find the opening function parenthesis\n", __func__, __LINE__); + + while ((fpo = fpo->GetPrev())->IsNotNullChunk()) + { + LOG_FMT(LSPLIT, "%s(%d): %s, orig col is %zu, level is %zu\n", + __func__, __LINE__, fpo->Text(), fpo->GetOrigCol(), fpo->GetLevel()); + + if ( fpo->Is(CT_FPAREN_OPEN) + && (fpo->GetLevel() == start->GetLevel() - 1)) + { + break; // opening parenthesis found. Issue #1020 + } + } + // Now break after every comma + Chunk *pc = fpo->GetNextNcNnl(); + + while (pc->IsNotNullChunk()) + { + if (pc->GetLevel() <= fpo->GetLevel()) + { + break; + } + + if ( (pc->GetLevel() == (fpo->GetLevel() + 1)) + && pc->Is(CT_COMMA)) + { + split_before_chunk(pc->GetNext()); + } + pc = pc->GetNextNcNnl(); + } +} + + +static void split_fcn_params(Chunk *start) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LSPLIT, "%s(%d): start->Text() is '%s', orig line is %zu, orig col is %zu\n", + __func__, __LINE__, start->Text(), start->GetOrigLine(), start->GetOrigCol()); + Chunk *fpo = start; + + if (!start->Is(CT_FPAREN_OPEN)) + { + // Find the opening function parenthesis + LOG_FMT(LSPLIT, "%s(%d): Find the opening function parenthesis\n", __func__, __LINE__); + + while ( ((fpo = fpo->GetPrev()) != nullptr) + && fpo->IsNotNullChunk() + && fpo->IsNot(CT_FPAREN_OPEN)) + { + // do nothing + LOG_FMT(LSPLIT, "%s(%d): '%s', orig col is %zu, level is %zu\n", + __func__, __LINE__, fpo->Text(), fpo->GetOrigCol(), fpo->GetLevel()); + } + } + Chunk *pc = fpo->GetNextNcNnl(); + size_t min_col = pc->GetColumn(); + + log_rule_B("code_width"); + LOG_FMT(LSPLIT, " mincol is %zu, max_width is %zu\n", + min_col, options::code_width() - min_col); + + int cur_width = 0; + int last_col = -1; + + LOG_FMT(LSPLIT, "%s(%d):look forward until CT_COMMA or CT_FPAREN_CLOSE\n", __func__, __LINE__); + + while (pc->IsNotNullChunk()) + { + LOG_CHUNK(LTOK, pc); + + if (pc->IsNewline()) + { + cur_width = 0; + last_col = -1; + } + else + { + if (last_col < 0) + { + last_col = pc->GetColumn(); + LOG_FMT(LSPLIT, "%s(%d): last_col is %d\n", + __func__, __LINE__, last_col); + } + cur_width += (pc->GetColumn() - last_col) + pc->Len(); + last_col = pc->GetColumn() + pc->Len(); + + LOG_FMT(LSPLIT, "%s(%d): last_col is %d\n", + __func__, __LINE__, last_col); + + if ( pc->Is(CT_COMMA) + || pc->Is(CT_FPAREN_CLOSE)) + { + if (cur_width == 0) + { + fprintf(stderr, "%s(%d): cur_width is ZERO, cannot be decremented, at line %zu, column %zu\n", + __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol()); + log_flush(true); + exit(EX_SOFTWARE); + } + cur_width--; + LOG_FMT(LSPLIT, "%s(%d): cur_width is %d\n", + __func__, __LINE__, cur_width); + + log_rule_B("code_width"); + + if ( ((last_col - 1) > static_cast<int>(options::code_width())) + || pc->Is(CT_FPAREN_CLOSE)) + { + break; + } + } + } + pc = pc->GetNext(); + } + // back up until the prev is a comma + Chunk *prev = pc; + + LOG_FMT(LSPLIT, "%s(%d): back up until the prev is a comma, begin is '%s', level is %zu\n", + __func__, __LINE__, prev->Text(), prev->GetLevel()); + + while ((prev = prev->GetPrev())->IsNotNullChunk()) + { + LOG_FMT(LSPLIT, "%s(%d): prev->Text() is '%s', orig line is %zu, orig col is %zu\n", + __func__, __LINE__, prev->Text(), prev->GetOrigLine(), prev->GetOrigCol()); + LOG_FMT(LSPLIT, "%s(%d): prev->GetLevel() is %zu, prev '%s', prev->GetType() is %s\n", + __func__, __LINE__, prev->GetLevel(), prev->Text(), get_token_name(prev->GetType())); + + if ( prev->IsNewline() + || prev->Is(CT_COMMA)) + { + LOG_FMT(LSPLIT, "%s(%d): found at %zu\n", + __func__, __LINE__, prev->GetOrigCol()); + break; + } + LOG_FMT(LSPLIT, "%s(%d): last_col is %d, prev->Len() is %zu\n", + __func__, __LINE__, last_col, prev->Len()); + last_col -= prev->Len(); + LOG_FMT(LSPLIT, "%s(%d): last_col is %d\n", + __func__, __LINE__, last_col); + + if (prev->Is(CT_FPAREN_OPEN)) + { + pc = prev->GetNext(); + + log_rule_B("indent_paren_nl"); + + if (!options::indent_paren_nl()) + { + log_rule_B("indent_columns"); + min_col = pc->GetBraceLevel() * options::indent_columns() + 1; + LOG_FMT(LSPLIT, "%s(%d): min_col is %zu\n", + __func__, __LINE__, min_col); + + log_rule_B("indent_continue"); + + if (options::indent_continue() == 0) + { + log_rule_B("indent_columns"); + min_col += options::indent_columns(); + } + else + { + min_col += abs(options::indent_continue()); + } + LOG_FMT(LSPLIT, "%s(%d): min_col is %zu\n", + __func__, __LINE__, min_col); + } + + // Don't split "()" + if (pc->GetType() != E_Token(prev->GetType() + 1)) + { + break; + } + } + } + + if ( prev->IsNotNullChunk() + && !prev->IsNewline()) + { + LOG_FMT(LSPLIT, "%s(%d): -- ended on %s --\n", + __func__, __LINE__, get_token_name(prev->GetType())); + LOG_FMT(LSPLIT, "%s(%d): min_col is %zu\n", + __func__, __LINE__, min_col); + pc = prev->GetNext(); + newline_add_before(pc); + reindent_line(pc, min_col); + cpd.changes++; + } +} // split_fcn_params + + +static void split_template(Chunk *start) +{ + LOG_FUNC_ENTRY(); + LOG_FMT(LSPLIT, " %s(%d): start %s\n", __func__, __LINE__, start->Text()); + LOG_FMT(LSPLIT, " %s(%d): back up until the prev is a comma\n", __func__, __LINE__); + + // back up until the prev is a comma + Chunk *prev = start; + + while ((prev = prev->GetPrev())->IsNotNullChunk()) + { + LOG_FMT(LSPLIT, " %s(%d): prev '%s'\n", __func__, __LINE__, prev->Text()); + + if ( prev->IsNewline() + || prev->Is(CT_COMMA)) + { + break; + } + } + + if ( prev->IsNotNullChunk() + && !prev->IsNewline()) + { + LOG_FMT(LSPLIT, " %s(%d):", __func__, __LINE__); + LOG_FMT(LSPLIT, " -- ended on %s --\n", get_token_name(prev->GetType())); + Chunk *pc = prev->GetNext(); + newline_add_before(pc); + size_t min_col = 1; + + log_rule_B("indent_continue"); + + if (options::indent_continue() == 0) + { + log_rule_B("indent_columns"); + min_col += options::indent_columns(); + } + else + { + min_col += abs(options::indent_continue()); + } + reindent_line(pc, min_col); + cpd.changes++; + } +} // split_templatefcn_params diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/width.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/width.h new file mode 100644 index 00000000..73df45e1 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/width.h @@ -0,0 +1,21 @@ +/** + * @file width.h + * prototypes for width.c + * + * @author Ben Gardner + * @license GPL v2+ + */ +#ifndef WIDTH_H_INCLUDED +#define WIDTH_H_INCLUDED + +#include "uncrustify_types.h" + + +/** + * Step forward until a token goes beyond the limit and then call split_line() + * to split the line at or before that point. + */ +void do_code_width(); + + +#endif /* WIDTH_H_INCLUDED */ diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/windows_compat.h b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/windows_compat.h new file mode 100644 index 00000000..619581b0 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/windows_compat.h @@ -0,0 +1,102 @@ +/** + * @file windows_compat.h + * Hacks to work with different versions of windows. + * This is only included if WIN32 is set. + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#ifndef WINDOWS_COMPAT_H_INCLUDED +#define WINDOWS_COMPAT_H_INCLUDED + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef WIN32 +#include "windows.h" +#endif + +#define HAVE_SYS_STAT_H + +#define NO_MACRO_VARARG + +typedef char CHAR; + +typedef signed char INT8; +typedef short INT16; +typedef int INT32; + +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef unsigned int UINT32; +typedef unsigned long long UINT64; + +#ifndef PRIx64 +#define PRIx64 "llx" +#endif + +#ifndef PRIu64 +#define PRIu64 "llu" +#endif + +// Make sure to keep GNU style attributes if they are supported; other +// included headers may have chosen to rely on them. This is essential +// if building with libc++ headers, where attributes are relied upon +// if they are supported (see _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION). +#ifndef __GNUC__ +// eliminate GNU's attribute +#define __attribute__(x) +#endif + +/* + * MSVC compilers before VC7 don't have __func__ at all; later ones call it + * __FUNCTION__. + */ +#ifdef _MSC_VER +#if _MSC_VER < 1300 +#define __func__ "???" +#else +#define __func__ __FUNCTION__ +#endif +#else // _MSC_VER +#ifndef __GNUC__ +#define __func__ "???" +#endif // __GNUC__ +#endif // _MSC_VER + +#include "stdio.h" +#include "string.h" + +#undef snprintf +#define snprintf _snprintf + +#undef vsnprintf +#define vsnprintf _vsnprintf + +#undef strcasecmp +#define strcasecmp _strcmpi + +#undef strncasecmp +#define strncasecmp _strnicmp + +#undef strdup +#define strdup _strdup + +#undef fileno +#define fileno _fileno + +// includes for _setmode() +#ifdef WIN32 +#include <direct.h> +#include <io.h> +#endif +#include <fcntl.h> + +// on windows the file permissions have no meaning thus neglect them +#define mkdir(x, y) _mkdir(x) + +#define PATH_SEP '\\' + +#endif /* WINDOWS_COMPAT_H_INCLUDED */ |