summaryrefslogtreecommitdiffstats
path: root/debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine.cpp')
-rw-r--r--debian/uncrustify-trinity/uncrustify-trinity-0.76.0/src/combine.cpp4088
1 files changed, 4088 insertions, 0 deletions
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