diff options
Diffstat (limited to 'debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/rewrite_infinite_loops.cpp')
-rw-r--r-- | debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/rewrite_infinite_loops.cpp | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/rewrite_infinite_loops.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/rewrite_infinite_loops.cpp new file mode 100644 index 00000000..6b97ea7d --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/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 |