summaryrefslogtreecommitdiffstats
path: root/debian/uncrustify-trinity/uncrustify-trinity-0.75.0/src/combine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'debian/uncrustify-trinity/uncrustify-trinity-0.75.0/src/combine.cpp')
-rw-r--r--debian/uncrustify-trinity/uncrustify-trinity-0.75.0/src/combine.cpp4018
1 files changed, 4018 insertions, 0 deletions
diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.75.0/src/combine.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.75.0/src/combine.cpp
new file mode 100644
index 00000000..f21d106c
--- /dev/null
+++ b/debian/uncrustify-trinity/uncrustify-trinity-0.75.0/src/combine.cpp
@@ -0,0 +1,4018 @@
+/**
+ * @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 "newlines.h"
+#include "prototypes.h"
+#include "tokenize_cleanup.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);
+
+
+/**
+ * Skips the list of class/struct parent types.
+ */
+Chunk *skip_parent_types(Chunk *colon);
+
+
+/**
+ * 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(void);
+
+
+/**
+ * Processes a return statement, labeling the parens and marking the parent.
+ * May remove or add parens around the return statement
+ *
+ * @param pc Pointer to the return chunk
+ */
+static Chunk *process_return(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, pcf_flags_t 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 (chunk_is_not_token(tmp, CT_QUALIFIER))
+ {
+ return;
+ }
+ Chunk *po = tmp->GetNextNcNnl(E_Scope::PREPROC);
+
+ if (!chunk_is_paren_open(po))
+ {
+ return;
+ }
+ Chunk *end = chunk_skip_to_match(po, E_Scope::PREPROC);
+
+ if (end == nullptr)
+ {
+ return;
+ }
+ set_chunk_parent(po, CT_ASM);
+ set_chunk_parent(end, CT_ASM);
+
+ for ( tmp = po->GetNextNcNnl(E_Scope::PREPROC);
+ tmp->IsNotNullChunk()
+ && tmp != end;
+ tmp = tmp->GetNextNcNnl(E_Scope::PREPROC))
+ {
+ if (chunk_is_token(tmp, CT_COLON))
+ {
+ set_chunk_type(tmp, CT_ASM_COLON);
+ }
+ else if (chunk_is_token(tmp, CT_DC_MEMBER))
+ {
+ // if there is a string on both sides, then this is two ASM_COLONs
+ if ( chunk_is_token(tmp->GetNextNcNnl(E_Scope::PREPROC), CT_STRING)
+ && chunk_is_token(tmp->GetPrevNcNnlNi(E_Scope::PREPROC), CT_STRING)) // Issue #2279
+ {
+ Chunk nc;
+
+ nc = *tmp;
+
+ tmp->str.resize(1);
+ tmp->orig_col_end = tmp->orig_col + 1;
+ set_chunk_type(tmp, CT_ASM_COLON);
+
+ set_chunk_type(&nc, tmp->type);
+ nc.str.pop_front();
+ nc.orig_col++;
+ nc.column++;
+ chunk_add_after(&nc, tmp);
+ }
+ }
+ }
+
+ tmp = end->GetNextNcNnl(E_Scope::PREPROC);
+
+ if (tmp->IsNullChunk())
+ {
+ return;
+ }
+
+ if (chunk_is_token(tmp, CT_SEMICOLON))
+ {
+ set_chunk_parent(tmp, 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->type));
+ log_pcf_flags(LFCNR, prev->flags);
+ LOG_FMT(LFCNR, "%s(%d): pc is '%s' %s\n",
+ __func__, __LINE__,
+ pc->Text(), get_token_name(pc->type));
+ log_pcf_flags(LFCNR, pc->flags);
+ LOG_FMT(LFCNR, "%s(%d): next is '%s' %s\n",
+ __func__, __LINE__,
+ next->Text(), get_token_name(next->type));
+ log_pcf_flags(LFCNR, next->flags);
+
+ if ( chunk_is_token(pc, CT_NOEXCEPT) // Issue #3284
+ && chunk_is_token(next, CT_ASSIGN)) // skip over noexcept
+ {
+ LOG_FMT(LFCNR, "%s(%d): orig_line is %zu, orig_col is %zu, Text() '%s'\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->Text());
+ pc = next;
+ next = pc->GetNext();
+ }
+
+ // separate the uses of CT_ASSIGN sign '='
+ // into CT_ASSIGN_DEFAULT_ARG, CT_ASSIGN_FUNC_PROTO
+ if ( chunk_is_token(pc, CT_ASSIGN)
+ && get_chunk_parent_type(pc) == CT_FUNC_PROTO
+ && ( pc->flags.test(PCF_IN_FCN_DEF) // Issue #2236
+ || pc->flags.test(PCF_IN_CONST_ARGS)))
+ {
+ LOG_FMT(LFCNR, "%s(%d): orig_line is %zu, orig_col is %zu, Text() '%s'\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col, pc->Text());
+ log_pcf_flags(LFCNR, pc->flags);
+ set_chunk_type(pc, CT_ASSIGN_DEFAULT_ARG);
+ return;
+ }
+
+ if ( ( chunk_is_token(prev, CT_FPAREN_CLOSE)
+ || ( ( chunk_is_str(prev, "const")
+ || chunk_is_str(prev, "override"))
+ && chunk_is_token(prev->prev, CT_FPAREN_CLOSE)))
+ && chunk_is_token(pc, CT_ASSIGN)
+ && ( chunk_is_token(next, CT_DEFAULT)
+ || chunk_is_token(next, CT_DELETE)
+ || chunk_is_str(next, "0")))
+ {
+ set_chunk_type(pc, CT_ASSIGN_FUNC_PROTO);
+ return; // cpp 30031
+ }
+
+ if (chunk_is_token(pc, CT_OC_AT))
+ {
+ if ( chunk_is_token(next, CT_PAREN_OPEN)
+ || chunk_is_token(next, CT_BRACE_OPEN)
+ || chunk_is_token(next, CT_SQUARE_OPEN))
+ {
+ flag_parens(next, PCF_OC_BOXED, next->type, CT_OC_AT, false);
+ }
+ else
+ {
+ set_chunk_parent(next, CT_OC_AT);
+ return; // objective-c_50095
+ }
+ }
+
+ // D stuff
+ if ( language_is_set(LANG_D)
+ && chunk_is_token(pc, CT_QUALIFIER)
+ && chunk_is_str(pc, "const")
+ && chunk_is_token(next, CT_PAREN_OPEN))
+ {
+ set_chunk_type(pc, CT_D_CAST);
+ set_paren_parent(next, pc->type);
+ return; // d_40061
+ }
+
+ if ( chunk_is_token(next, CT_PAREN_OPEN)
+ && ( chunk_is_token(pc, CT_D_CAST)
+ || chunk_is_token(pc, CT_DELEGATE)
+ || chunk_is_token(pc, CT_ALIGN)))
+ {
+ // mark the parenthesis parent
+ Chunk *tmp = set_paren_parent(next, pc->type);
+
+ // For a D cast - convert the next item
+ if ( chunk_is_token(pc, CT_D_CAST)
+ && tmp != nullptr)
+ {
+ if (chunk_is_token(tmp, CT_STAR))
+ {
+ set_chunk_type(tmp, CT_DEREF);
+ return; // d_40006
+ }
+ else if (chunk_is_token(tmp, CT_AMP))
+ {
+ set_chunk_type(tmp, CT_ADDR);
+ return; // d_40060
+ }
+ else if (chunk_is_token(tmp, CT_MINUS))
+ {
+ set_chunk_type(tmp, CT_NEG);
+ return; // d_40060
+ }
+ else if (chunk_is_token(tmp, CT_PLUS))
+ {
+ set_chunk_type(tmp, 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 (chunk_is_token(pc, CT_DELEGATE))
+ {
+ if (tmp != nullptr)
+ {
+ set_chunk_parent(tmp, CT_DELEGATE);
+
+ if (tmp->level == tmp->brace_level)
+ {
+ chunk_flags_set(tmp, PCF_VAR_1ST_DEF);
+ }
+ }
+
+ for (tmp = pc->GetPrevNcNnlNi(); tmp->IsNotNullChunk(); tmp = tmp->GetPrevNcNnlNi()) // Issue #2279
+ {
+ if ( chunk_is_semicolon(tmp)
+ || chunk_is_token(tmp, CT_BRACE_OPEN)
+ || chunk_is_token(tmp, CT_VBRACE_OPEN))
+ {
+ break;
+ }
+ make_type(tmp);
+ }
+
+ return; // c-sharp_10160
+ }
+
+ if ( chunk_is_token(pc, CT_ALIGN)
+ && tmp != nullptr)
+ {
+ if (chunk_is_token(tmp, CT_BRACE_OPEN))
+ {
+ set_paren_parent(tmp, pc->type);
+ return; // d_40024
+ }
+ else if (chunk_is_token(tmp, CT_COLON))
+ {
+ set_chunk_parent(tmp, pc->type);
+ return; // d_40024
+ }
+ }
+ } // paren open + cast/align/delegate
+
+ if (chunk_is_token(pc, CT_INVARIANT))
+ {
+ if (chunk_is_token(next, CT_PAREN_OPEN))
+ {
+ set_chunk_parent(next, pc->type);
+ Chunk *tmp = next->GetNext();
+
+ if (tmp == nullptr)
+ {
+ tmp = Chunk::NullChunkPtr;
+ }
+
+ while (tmp->IsNotNullChunk())
+ {
+ if (chunk_is_token(tmp, CT_PAREN_CLOSE))
+ {
+ set_chunk_parent(tmp, pc->type);
+ break;
+ }
+ make_type(tmp);
+ tmp = tmp->GetNext();
+ }
+ return; // d_40100
+ }
+ else
+ {
+ set_chunk_type(pc, CT_QUALIFIER);
+ return;
+ }
+ }
+
+ if ( chunk_is_token(prev, CT_BRACE_OPEN)
+ && get_chunk_parent_type(prev) != CT_CS_PROPERTY
+ && ( chunk_is_token(pc, CT_GETSET)
+ || chunk_is_token(pc, CT_GETSET_EMPTY)))
+ {
+ flag_parens(prev, PCF_NONE, CT_NONE, CT_GETSET, false);
+ return;
+ }
+
+ if (chunk_is_token(pc, 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 (chunk_is_token(pc, CT_CARET))
+ {
+ if ( pc->flags.test(PCF_EXPR_START)
+ || pc->flags.test(PCF_IN_PREPROC))
+ {
+ handle_oc_block_literal(pc);
+ return;
+ }
+ }
+ }
+
+ // Objective C stuff
+ if (language_is_set(LANG_OC))
+ {
+ // Check for message declarations
+ if (pc->flags.test(PCF_STMT_START))
+ {
+ if ( ( chunk_is_str(pc, "-")
+ || chunk_is_str(pc, "+"))
+ && chunk_is_str(next, "("))
+ {
+ handle_oc_message_decl(pc);
+ return;
+ }
+ }
+
+ if ( pc->flags.test(PCF_EXPR_START)
+ || pc->flags.test(PCF_IN_PREPROC))
+ {
+ if (chunk_is_token(pc, CT_SQUARE_OPEN))
+ {
+ handle_oc_message_send(pc);
+ return; // objective-c_50003
+ }
+ }
+
+ if (chunk_is_token(pc, CT_OC_PROPERTY))
+ {
+ handle_oc_property_decl(pc);
+ return;
+ }
+
+ if (chunk_is_token(pc, CT_OC_AVAILABLE))
+ {
+ handle_oc_available(pc);
+ return;
+ }
+ }
+
+ // C# stuff
+ if (language_is_set(LANG_CS))
+ {
+ // '[assembly: xxx]' stuff
+ if ( pc->flags.test(PCF_EXPR_START)
+ && chunk_is_token(pc, CT_SQUARE_OPEN))
+ {
+ handle_cs_square_stmt(pc);
+ return;
+ }
+
+ if ( chunk_is_token(next, CT_BRACE_OPEN)
+ && get_chunk_parent_type(next) == CT_NONE
+ && ( chunk_is_token(pc, CT_SQUARE_CLOSE)
+ || chunk_is_token(pc, CT_ANGLE_CLOSE)
+ || chunk_is_token(pc, CT_WORD)))
+ {
+ handle_cs_property(next);
+ return;
+ }
+
+ if ( chunk_is_token(pc, CT_SQUARE_CLOSE)
+ && chunk_is_token(next, CT_WORD))
+ {
+ handle_cs_array_type(pc);
+ return;
+ }
+
+ if ( ( chunk_is_token(pc, CT_LAMBDA)
+ || chunk_is_token(pc, CT_DELEGATE))
+ && chunk_is_token(next, CT_BRACE_OPEN))
+ {
+ set_paren_parent(next, pc->type);
+ return;
+ }
+
+ if ( chunk_is_token(pc, CT_WHEN)
+ && pc->GetNext()->IsNotNullChunk()
+ && pc->GetNext()->type != CT_SPAREN_OPEN)
+ {
+ set_chunk_type(pc, CT_WORD);
+ return;
+ }
+ }
+
+ if ( language_is_set(LANG_JAVA)
+ && chunk_is_token(pc, CT_LAMBDA)
+ && chunk_is_token(next, CT_BRACE_OPEN))
+ {
+ set_paren_parent(next, pc->type);
+ return;
+ }
+
+ if (chunk_is_token(pc, CT_NEW))
+ {
+ Chunk *ts = nullptr;
+ Chunk *tmp = next;
+
+ if (chunk_is_token(tmp, CT_TSQUARE))
+ {
+ ts = tmp;
+ tmp = tmp->GetNextNcNnl();
+ }
+
+ if ( chunk_is_token(tmp, CT_BRACE_OPEN)
+ || chunk_is_token(tmp, CT_PAREN_OPEN))
+ {
+ set_paren_parent(tmp, pc->type);
+
+ if (ts != nullptr)
+ {
+ set_chunk_parent(ts, pc->type);
+ }
+ }
+ return;
+ }
+
+ // C++11 Lambda stuff
+ if ( language_is_set(LANG_CPP)
+ && ( chunk_is_token(pc, CT_SQUARE_OPEN)
+ || chunk_is_token(pc, CT_TSQUARE)))
+ {
+ handle_cpp_lambda(pc);
+ }
+
+ // FIXME: which language does this apply to?
+ // Issue #2432
+ if (!language_is_set(LANG_OC))
+ {
+ if ( chunk_is_token(pc, CT_ASSIGN)
+ && chunk_is_token(next, CT_SQUARE_OPEN))
+ {
+ set_paren_parent(next, CT_ASSIGN);
+
+ // Mark one-liner assignment
+ Chunk *tmp = next;
+
+ while ((tmp = tmp->GetNextNc())->IsNotNullChunk())
+ {
+ if (chunk_is_newline(tmp))
+ {
+ break;
+ }
+
+ if ( chunk_is_token(tmp, CT_SQUARE_CLOSE)
+ && next->level == tmp->level)
+ {
+ chunk_flags_set(tmp, PCF_ONE_LINER);
+ chunk_flags_set(next, PCF_ONE_LINER);
+ break;
+ }
+ }
+ return;
+ }
+ }
+
+ if (chunk_is_token(pc, CT_ASSERT))
+ {
+ handle_java_assert(pc);
+ return;
+ }
+
+ if (chunk_is_token(pc, CT_ANNOTATION))
+ {
+ Chunk *tmp = pc->GetNextNcNnl();
+
+ if (chunk_is_paren_open(tmp))
+ {
+ set_paren_parent(tmp, CT_ANNOTATION);
+ }
+ return;
+ }
+
+ if ( chunk_is_token(pc, CT_SIZEOF)
+ && language_is_set(LANG_ALLC))
+ {
+ Chunk *tmp = pc->GetNextNcNnl();
+
+ if (chunk_is_token(tmp, CT_ELLIPSIS))
+ {
+ set_chunk_parent(tmp, CT_SIZEOF);
+ }
+ return;
+ }
+
+ if ( chunk_is_token(pc, CT_DECLTYPE)
+ && pc->parent_type != CT_FUNC_DEF)
+ {
+ Chunk *tmp = pc->GetNextNcNnl();
+
+ if (chunk_is_paren_open(tmp))
+ {
+ // decltype may be followed by a braced-init-list
+ tmp = set_paren_parent(tmp, CT_DECLTYPE);
+
+ if (chunk_is_opening_brace(tmp) && !pc->flags.test(PCF_IN_LAMBDA))
+ {
+ tmp = set_paren_parent(tmp, CT_BRACED_INIT_LIST);
+
+ if (tmp)
+ {
+ chunk_flags_clr(tmp, PCF_EXPR_START | PCF_STMT_START);
+ }
+ }
+ else
+ {
+ if (chunk_is_token(tmp, CT_WORD))
+ {
+ chunk_flags_set(tmp, PCF_VAR_1ST_DEF);
+ }
+ }
+ }
+ return;
+ }
+
+ // A [] in C# and D only follows a type
+ if ( chunk_is_token(pc, CT_TSQUARE)
+ && language_is_set(LANG_D | LANG_CS | LANG_VALA))
+ {
+ if (chunk_is_token(prev, CT_WORD))
+ {
+ set_chunk_type(prev, CT_TYPE);
+ }
+
+ if (chunk_is_token(next, CT_WORD))
+ {
+ chunk_flags_set(next, PCF_VAR_1ST_DEF);
+ }
+ return;
+ }
+
+ if ( chunk_is_token(pc, CT_SQL_EXEC)
+ || chunk_is_token(pc, CT_SQL_BEGIN)
+ || chunk_is_token(pc, CT_SQL_END))
+ {
+ mark_exec_sql(pc);
+ return;
+ }
+
+ if (chunk_is_token(pc, CT_PROTO_WRAP))
+ {
+ handle_proto_wrap(pc);
+ return;
+ }
+
+ // Handle the typedef
+ if (chunk_is_token(pc, CT_TYPEDEF))
+ {
+ fix_typedef(pc);
+ return;
+ }
+
+ if ( chunk_is_class_enum_struct_union(pc)
+ && chunk_is_not_token(prev, CT_TYPEDEF))
+ {
+ EnumStructUnionParser parser;
+ parser.parse(pc);
+ return;
+ }
+
+ if (chunk_is_token(pc, CT_EXTERN))
+ {
+ if (chunk_is_paren_open(next))
+ {
+ Chunk *tmp = flag_parens(next, PCF_NONE, CT_NONE, CT_EXTERN, true);
+
+ if (chunk_is_token(tmp, CT_BRACE_OPEN))
+ {
+ set_paren_parent(tmp, CT_EXTERN);
+ }
+ }
+ else
+ {
+ // next likely is a string (see tokenize_cleanup.cpp)
+ set_chunk_parent(next, CT_EXTERN);
+ Chunk *tmp = next->GetNextNcNnl();
+
+ if (chunk_is_token(tmp, CT_BRACE_OPEN))
+ {
+ set_paren_parent(tmp, CT_EXTERN);
+ }
+ }
+ return;
+ }
+
+ if (chunk_is_token(pc, CT_TEMPLATE))
+ {
+ if (language_is_set(LANG_D))
+ {
+ handle_d_template(pc);
+ }
+ else
+ {
+ handle_cpp_template(pc);
+ }
+ return;
+ }
+
+ if ( chunk_is_token(pc, CT_WORD)
+ && chunk_is_token(next, CT_ANGLE_OPEN)
+ && get_chunk_parent_type(next) == CT_TEMPLATE)
+ {
+ mark_template_func(pc, next);
+ return;
+ }
+
+ if ( chunk_is_token(pc, CT_SQUARE_CLOSE)
+ && chunk_is_token(next, CT_PAREN_OPEN))
+ {
+ flag_parens(next, PCF_NONE, CT_FPAREN_OPEN, CT_NONE, false);
+ return;
+ }
+
+ if (chunk_is_token(pc, CT_TYPE_CAST))
+ {
+ fix_type_cast(pc);
+ return;
+ }
+
+ if ( get_chunk_parent_type(pc) == CT_ASSIGN
+ && ( chunk_is_token(pc, CT_BRACE_OPEN)
+ || chunk_is_token(pc, CT_SQUARE_OPEN)))
+ {
+ // Mark everything in here as in assign
+ flag_parens(pc, PCF_IN_ARRAY_ASSIGN, pc->type, CT_NONE, false);
+ return;
+ }
+
+ if (chunk_is_token(pc, CT_D_TEMPLATE))
+ {
+ set_paren_parent(next, pc->type);
+ return;
+ }
+
+ /*
+ * A word before an open paren is a function call or definition.
+ * CT_WORD => CT_FUNC_CALL or CT_FUNC_DEF
+ */
+ if (chunk_is_token(next, CT_PAREN_OPEN))
+ {
+ Chunk *tmp = next->GetNextNcNnl();
+
+ if ( language_is_set(LANG_C | LANG_CPP | LANG_OC)
+ && chunk_is_token(tmp, 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 ( ( chunk_is_token(tmp, CT_OC_BLOCK_CARET)
+ || chunk_is_token(tmp, CT_CARET))
+ && chunk_is_token(pc, 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->orig_line, pc->orig_col, pc->Text());
+ set_chunk_type(pc, CT_FUNC_CALL);
+ }
+ }
+ else if ( chunk_is_token(pc, CT_WORD)
+ || chunk_is_token(pc, CT_OPERATOR_VAL))
+ {
+ set_chunk_type(pc, CT_FUNCTION);
+ }
+ else if (chunk_is_token(pc, CT_FIXED))
+ {
+ set_chunk_type(pc, CT_FUNCTION);
+ set_chunk_parent(pc, CT_FIXED);
+ }
+ else if (chunk_is_token(pc, 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->orig_line, pc->orig_col, 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 (chunk_is_token(tmp, CT_AMP))
+ {
+ auto tmp2 = tmp->GetNextNcNnl();
+
+ if (chunk_is_token(tmp2, CT_WORD))
+ {
+ tmp2 = tmp2->GetNextNcNnl();
+ }
+
+ if (chunk_is_token(tmp2, CT_PAREN_CLOSE))
+ {
+ tmp2 = tmp2->GetNextNcNnl();
+
+ if (chunk_is_token(tmp2, CT_SQUARE_OPEN))
+ {
+ is_byref_array = true;
+ set_chunk_type(tmp, CT_BYREF);
+ }
+ }
+ }
+ }
+
+ if (!is_byref_array)
+ {
+ tmp = next->GetNextType(CT_PAREN_CLOSE, next->level);
+
+ if (tmp->IsNotNullChunk())
+ {
+ tmp = tmp->GetNext();
+
+ if (chunk_is_token(tmp, CT_PAREN_OPEN))
+ {
+ set_chunk_type(pc, CT_FUNCTION);
+ }
+ else
+ {
+ if ( get_chunk_parent_type(pc) == CT_NONE
+ && !pc->flags.test(PCF_IN_TYPEDEF))
+ {
+ tmp = next->GetNextNcNnl();
+
+ if (chunk_is_token(tmp, CT_PAREN_CLOSE))
+ {
+ // we have TYPE()
+ set_chunk_type(pc, CT_FUNCTION);
+ }
+ else
+ {
+ // we have TYPE(...)
+ set_chunk_type(pc, CT_CPP_CAST);
+ set_paren_parent(next, CT_CPP_CAST);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (language_is_set(LANG_PAWN))
+ {
+ if ( chunk_is_token(pc, CT_FUNCTION)
+ && pc->brace_level > 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->orig_line, pc->orig_col, pc->Text());
+ set_chunk_type(pc, CT_FUNC_CALL);
+ }
+
+ if ( chunk_is_token(pc, CT_STATE)
+ && chunk_is_token(next, CT_PAREN_OPEN))
+ {
+ set_paren_parent(next, pc->type);
+ }
+ }
+ else
+ {
+ if ( ( chunk_is_token(pc, CT_FUNCTION)
+ || chunk_is_token(pc, CT_FUNC_DEF))
+ && ( (get_chunk_parent_type(pc) == CT_OC_BLOCK_EXPR)
+ || !is_oc_block(pc)))
+ {
+ mark_function(pc);
+ }
+ }
+
+ // Detect C99 member stuff
+ if ( chunk_is_token(pc, CT_MEMBER)
+ && ( chunk_is_token(prev, CT_COMMA)
+ || chunk_is_token(prev, CT_BRACE_OPEN)))
+ {
+ set_chunk_type(pc, CT_C99_MEMBER);
+ set_chunk_parent(next, CT_C99_MEMBER);
+ return;
+ }
+
+ // Mark function parens and braces
+ if ( chunk_is_token(pc, CT_FUNC_DEF)
+ || chunk_is_token(pc, CT_FUNC_CALL)
+ || chunk_is_token(pc, CT_FUNC_CALL_USER)
+ || chunk_is_token(pc, CT_FUNC_PROTO))
+ {
+ Chunk *tmp = next;
+
+ if (chunk_is_token(tmp, CT_SQUARE_OPEN))
+ {
+ tmp = set_paren_parent(tmp, pc->type);
+ }
+ else if ( chunk_is_token(tmp, CT_TSQUARE)
+ || get_chunk_parent_type(tmp) == CT_OPERATOR)
+ {
+ tmp = tmp->GetNextNcNnl();
+ }
+
+ if ( tmp != nullptr
+ && tmp->IsNotNullChunk())
+ {
+ if (chunk_is_paren_open(tmp))
+ {
+ tmp = flag_parens(tmp, PCF_NONE, CT_FPAREN_OPEN, pc->type, false);
+
+ if ( tmp != nullptr
+ && tmp->IsNotNullChunk())
+ {
+ if (chunk_is_token(tmp, CT_BRACE_OPEN))
+ {
+ if ( get_chunk_parent_type(tmp) != CT_DOUBLE_BRACE
+ && !pc->flags.test(PCF_IN_CONST_ARGS))
+ {
+ set_paren_parent(tmp, pc->type);
+ }
+ }
+ else if ( chunk_is_semicolon(tmp)
+ && chunk_is_token(pc, CT_FUNC_PROTO))
+ {
+ set_chunk_parent(tmp, pc->type);
+ }
+ }
+ }
+ }
+ return;
+ }
+
+ // Mark the parameters in catch()
+ if ( chunk_is_token(pc, CT_CATCH)
+ && chunk_is_token(next, CT_SPAREN_OPEN))
+ {
+ fix_fcn_def_params(next);
+ return;
+ }
+
+ if ( chunk_is_token(pc, CT_THROW)
+ && chunk_is_token(prev, CT_FPAREN_CLOSE))
+ {
+ set_chunk_parent(pc, get_chunk_parent_type(prev));
+
+ if (chunk_is_token(next, CT_PAREN_OPEN))
+ {
+ set_paren_parent(next, CT_THROW);
+ }
+ return;
+ }
+
+ // Mark the braces in: "for_each_entry(xxx) { }"
+ if ( chunk_is_token(pc, CT_BRACE_OPEN)
+ && get_chunk_parent_type(pc) != CT_DOUBLE_BRACE
+ && chunk_is_token(prev, CT_FPAREN_CLOSE)
+ && ( get_chunk_parent_type(prev) == CT_FUNC_CALL
+ || get_chunk_parent_type(prev) == CT_FUNC_CALL_USER)
+ && !pc->flags.test(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->orig_line, pc->orig_col, 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->flags.test(PCF_IN_TEMPLATE) // Issue #3252
+ && get_chunk_parent_type(pc) != CT_CPP_CAST
+ && get_chunk_parent_type(pc) != CT_C_CAST
+ && !pc->flags.test(PCF_IN_PREPROC)
+ && !is_oc_block(pc)
+ && get_chunk_parent_type(pc) != CT_OC_MSG_DECL
+ && get_chunk_parent_type(pc) != CT_OC_MSG_SPEC
+ && chunk_is_str(pc, ")")
+ && chunk_is_str(next, "("))
+ {
+ 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 (chunk_is_token(pc, 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 ( chunk_is_token(pc, CT_PAREN_OPEN)
+ && ( get_chunk_parent_type(pc) == CT_NONE
+ || get_chunk_parent_type(pc) == CT_OC_MSG
+ || get_chunk_parent_type(pc) == CT_OC_BLOCK_EXPR
+ || get_chunk_parent_type(pc) == CT_CS_SQ_STMT) // Issue # 1256
+ && ( chunk_is_token(next, CT_WORD)
+ || chunk_is_token(next, CT_TYPE)
+ || chunk_is_token(next, CT_STRUCT)
+ || chunk_is_token(next, CT_QUALIFIER)
+ || chunk_is_token(next, CT_MEMBER)
+ || chunk_is_token(next, CT_DC_MEMBER)
+ || chunk_is_token(next, CT_ENUM)
+ || chunk_is_token(next, CT_UNION))
+ && chunk_is_not_token(prev, CT_DECLTYPE)
+ && chunk_is_not_token(prev, CT_SIZEOF)
+ && get_chunk_parent_type(prev) != CT_SIZEOF
+ && get_chunk_parent_type(prev) != CT_OPERATOR
+ && !pc->flags.test(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->flags.test_any(PCF_IN_STRUCT | PCF_IN_CLASS)
+ && chunk_is_token(pc, CT_ASSIGN)
+ && chunk_is_token(nnext, CT_SEMICOLON)
+ && ( chunk_is_token(next, CT_DEFAULT)
+ || chunk_is_token(next, CT_DELETE)
+ || ( chunk_is_token(next, CT_NUMBER)
+ && chunk_is_str(next, "0"))))
+ {
+ const size_t level = pc->level;
+ bool found_status = false;
+ Chunk *pprev = pc->GetPrev();
+
+ for ( ; ( pprev->IsNotNullChunk()
+ && pprev->level >= level
+ && chunk_is_not_token(pprev, CT_SEMICOLON)
+ && chunk_is_not_token(pprev, CT_ACCESS_COLON))
+ ; pprev = pprev->GetPrev())
+ {
+ if (pprev->level != level)
+ {
+ continue;
+ }
+
+ if (chunk_is_token(next, CT_NUMBER))
+ {
+ if ( chunk_is_token(pprev, CT_QUALIFIER)
+ && chunk_is_str(pprev, "virtual"))
+ {
+ found_status = true;
+ break;
+ }
+ }
+ else
+ {
+ if ( chunk_is_token(pprev, CT_FUNC_CLASS_PROTO) // ctor/dtor
+ || chunk_is_token(pprev, CT_FUNC_PROTO)) // normal function
+ {
+ found_status = true;
+ break;
+ }
+ }
+ }
+
+ if (found_status)
+ {
+ set_chunk_parent(pc, pprev->type);
+ }
+ }
+
+ 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->flags.test(PCF_EXPR_START)
+ || ( prev->flags.test(PCF_EXPR_START)
+ && get_chunk_parent_type(pc) == CT_OC_AT))
+ {
+ // Change STAR, MINUS, and PLUS in the easy cases
+ if (chunk_is_token(pc, CT_STAR))
+ {
+ // issue #596
+ // [0x100062020:IN_SPAREN,IN_FOR,STMT_START,EXPR_START,PUNCTUATOR]
+ // prev->type is CT_COLON ==> CT_DEREF
+ if (chunk_is_token(prev, CT_ANGLE_CLOSE))
+ {
+ set_chunk_type(pc, CT_PTR_TYPE);
+ }
+ else if (chunk_is_token(prev, CT_COLON))
+ {
+ set_chunk_type(pc, CT_DEREF);
+ }
+ else
+ {
+ set_chunk_type(pc, CT_DEREF);
+ }
+ }
+
+ if ( language_is_set(LANG_CPP)
+ && chunk_is_token(pc, CT_CARET)
+ && chunk_is_token(prev, CT_ANGLE_CLOSE))
+ {
+ set_chunk_type(pc, CT_PTR_TYPE);
+ }
+
+ if ( language_is_set(LANG_CS | LANG_VALA)
+ && chunk_is_token(pc, CT_QUESTION)
+ && chunk_is_token(prev, CT_ANGLE_CLOSE))
+ {
+ set_chunk_type(pc, CT_PTR_TYPE);
+ }
+
+ else if (chunk_is_token(pc, CT_MINUS))
+ {
+ set_chunk_type(pc, CT_NEG);
+ }
+
+ else if (chunk_is_token(pc, CT_PLUS))
+ {
+ set_chunk_type(pc, CT_POS);
+ }
+
+ else if (chunk_is_token(pc, CT_INCDEC_AFTER))
+ {
+ set_chunk_type(pc, CT_INCDEC_BEFORE);
+ }
+
+ else if (chunk_is_token(pc, CT_AMP))
+ {
+ if (chunk_is_token(prev, CT_ANGLE_CLOSE)) // Issue #2324
+ {
+ set_chunk_type(pc, CT_BYREF);
+ }
+ else
+ {
+ set_chunk_type(pc, CT_ADDR);
+ }
+ }
+
+ else if (chunk_is_token(pc, 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 (chunk_is_token(pc, CT_MACRO_FUNC))
+ {
+ flag_parens(next, PCF_IN_FCN_CALL, CT_FPAREN_OPEN, CT_MACRO_FUNC, false);
+ }
+
+ if ( chunk_is_token(pc, CT_MACRO_OPEN)
+ || chunk_is_token(pc, CT_MACRO_ELSE)
+ || chunk_is_token(pc, CT_MACRO_CLOSE))
+ {
+ if (chunk_is_token(next, CT_PAREN_OPEN))
+ {
+ flag_parens(next, PCF_NONE, CT_FPAREN_OPEN, pc->type, false);
+ }
+ }
+
+ if ( chunk_is_token(pc, CT_DELETE)
+ && chunk_is_token(next, CT_TSQUARE))
+ {
+ set_chunk_parent(next, CT_DELETE);
+ }
+
+ // Change CT_STAR to CT_PTR_TYPE or CT_ARITH or CT_DEREF
+ if ( chunk_is_token(pc, CT_STAR)
+ || ( language_is_set(LANG_CPP)
+ && chunk_is_token(pc, CT_CARET)))
+ {
+ if ( chunk_is_paren_close(next)
+ || chunk_is_token(next, CT_COMMA))
+ {
+ set_chunk_type(pc, CT_PTR_TYPE);
+ }
+ else if ( language_is_set(LANG_OC)
+ && chunk_is_token(next, CT_STAR))
+ {
+ /*
+ * Change pointer-to-pointer types in OC_MSG_DECLs
+ * from ARITH <===> DEREF to PTR_TYPE <===> PTR_TYPE
+ */
+ set_chunk_type(pc, CT_PTR_TYPE);
+ set_chunk_parent(pc, get_chunk_parent_type(prev));
+
+ set_chunk_type(next, CT_PTR_TYPE);
+ set_chunk_parent(next, get_chunk_parent_type(pc));
+ }
+ else if ( chunk_is_token(pc, CT_STAR)
+ && ( chunk_is_token(prev, CT_DECLTYPE)
+ || chunk_is_token(prev, CT_SIZEOF)
+ || chunk_is_token(prev, CT_DELETE)
+ || get_chunk_parent_type(pc) == CT_SIZEOF))
+ {
+ set_chunk_type(pc, CT_DEREF);
+ }
+ else if ( ( chunk_is_token(prev, CT_WORD)
+ && chunk_ends_type(prev)
+ && !prev->flags.test(PCF_IN_FCN_CTOR)
+ && !prev->flags.test(PCF_IN_ARRAY_ASSIGN)) // Issue #3345
+ || chunk_is_token(prev, CT_DC_MEMBER)
+ || chunk_is_token(prev, 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->orig_line, pc->orig_col, pc->Text(), get_token_name(pc->type));
+ log_pcf_flags(LFCNR, pc->flags);
+ set_chunk_type(pc, CT_PTR_TYPE);
+ }
+ else if ( chunk_is_token(next, CT_SQUARE_OPEN)
+ && !language_is_set(LANG_OC)) // Issue #408
+ {
+ set_chunk_type(pc, CT_PTR_TYPE);
+ }
+ else if (chunk_is_token(pc, 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, fuction call, return to distinguish between
+ // double result = Constants::PI * factor;
+ // and
+ // ::some::name * foo;
+ if ( chunk_is_token(prev, CT_WORD)
+ && chunk_is_token(prev->prev, CT_DC_MEMBER)
+ && language_is_set(LANG_CPP))
+ {
+ // Issue 1402
+ bool is_multiplication = false;
+ Chunk *tmp = pc;
+
+ while (tmp->IsNotNullChunk())
+ {
+ if ( chunk_is_token(tmp, CT_SEMICOLON)
+ || get_chunk_parent_type(tmp) == CT_CLASS)
+ {
+ break;
+ }
+ else if ( chunk_is_token(tmp, CT_ASSIGN)
+ || chunk_is_token(tmp, CT_FUNC_CALL)
+ || chunk_is_token(tmp, CT_RETURN))
+ {
+ is_multiplication = true;
+ break;
+ }
+ tmp = tmp->GetPrevNcNnlNi(); // Issue #2279
+ }
+
+ if (is_multiplication)
+ {
+ // double result = Constants::PI * factor;
+ set_chunk_type(pc, CT_ARITH);
+ }
+ else
+ {
+ // ::some::name * foo;
+ set_chunk_type(prev, CT_TYPE);
+ set_chunk_type(pc, 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 (chunk_is_token(prev, CT_TYPE))
+ {
+ set_chunk_type(pc, CT_PTR_TYPE);
+ }
+ else if ( chunk_is_token(pc->next, CT_SEMICOLON) // Issue #2319
+ || ( chunk_is_token(pc->next, CT_STAR)
+ && chunk_is_token(pc->next->next, CT_SEMICOLON)))
+ {
+ // example:
+ // using AbstractLinkPtr = AbstractLink*;
+ // using AbstractLinkPtrPtr = AbstractLink**;
+ set_chunk_type(pc, CT_PTR_TYPE);
+ }
+ else if ( ( get_chunk_parent_type(pc) == CT_FUNC_DEF
+ && ( chunk_is_opening_brace(next)
+ || pc->GetNext()->IsStar()))
+ || chunk_is_token(next, 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 }}
+ set_chunk_type(pc, CT_PTR_TYPE);
+ }
+ else if ( chunk_is_token(pc->next, CT_SEMICOLON) // Issue #2319
+ || ( chunk_is_token(pc->next, CT_STAR)
+ && chunk_is_token(pc->next->next, 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->orig_line, pc->orig_col);
+ fprintf(stderr, "Please make a report.\n");
+ log_flush(true);
+ exit(EX_SOFTWARE);
+ }
+ else
+ {
+ // Issue 1402
+ set_chunk_type(pc,
+ ( prev->flags.test(PCF_PUNCTUATOR)
+ && ( !chunk_is_paren_close(prev)
+ || chunk_is_token(prev, CT_SPAREN_CLOSE)
+ || get_chunk_parent_type(prev) == CT_MACRO_FUNC)
+ && chunk_is_not_token(prev, CT_SQUARE_CLOSE)
+ && chunk_is_not_token(prev, CT_DC_MEMBER)) ? CT_DEREF : CT_ARITH);
+ }
+
+ if (pc->flags.test(PCF_IN_TYPEDEF)) // Issue #1255/#633
+ {
+ Chunk *tmp = pc;
+
+ while (tmp->IsNotNullChunk())
+ {
+ if ( chunk_is_token(tmp, CT_SEMICOLON)
+ || chunk_is_token(tmp, CT_BRACE_OPEN)
+ || chunk_is_token(tmp, CT_SQUARE_OPEN)) // Issue #3342
+ {
+ break;
+ }
+ else if (chunk_is_token(tmp, CT_TYPEDEF))
+ {
+ set_chunk_type(pc, CT_PTR_TYPE);
+ }
+ tmp = tmp->GetPrevNcNnlNi(); // Issue #2279
+ }
+ }
+ }
+ }
+
+ if (chunk_is_token(pc, CT_AMP))
+ {
+ if (chunk_is_token(prev, CT_DELETE))
+ {
+ set_chunk_type(pc, CT_ADDR);
+ }
+ else if ( chunk_is_token(prev, CT_TYPE)
+ || chunk_is_token(prev, CT_QUALIFIER))
+ {
+ set_chunk_type(pc, CT_BYREF);
+ }
+ else if ( chunk_is_token(prev, CT_WORD) // Issue #3204
+ && chunk_is_token(next, CT_OPERATOR))
+ {
+ set_chunk_type(pc, CT_BYREF);
+ }
+ else if ( chunk_is_token(next, CT_FPAREN_CLOSE)
+ || chunk_is_token(next, CT_COMMA))
+ {
+ // fix the bug #654
+ // connect(&mapper, SIGNAL(mapped(QString &)), this, SLOT(onSomeEvent(QString &)));
+ set_chunk_type(pc, CT_BYREF);
+ }
+ else if (get_chunk_parent_type(pc) == CT_USING_ALIAS)
+ {
+ // fix the Issue # 1689
+ // using reference = value_type &;
+ set_chunk_type(pc->prev, CT_TYPE);
+ set_chunk_type(pc, CT_BYREF);
+ }
+ else
+ {
+ // Issue # 1398
+ if ( pc->flags.test(PCF_IN_FCN_DEF)
+ && chunk_is_token(prev, CT_WORD)
+ && chunk_is_token(pc, CT_AMP)
+ && chunk_is_token(next, CT_WORD))
+ {
+ /*
+ * Change CT_WORD before CT_AMP before CT_WORD to CT_TYPE
+ */
+ set_chunk_type(prev, CT_TYPE);
+ }
+ else
+ {
+ set_chunk_type(pc, CT_ARITH);
+
+ if ( chunk_is_token(prev, CT_WORD)
+ && !chunk_is_token(next, CT_NUMBER)) // Issue #3407
+ {
+ Chunk *tmp = prev->GetPrevNcNnlNi(); // Issue #2279
+
+ if (tmp->IsNotNullChunk())
+ {
+ if ( chunk_is_semicolon(tmp)
+ || chunk_is_token(tmp, CT_BRACE_OPEN)
+ || chunk_is_token(tmp, CT_QUALIFIER))
+ {
+ set_chunk_type(pc, CT_BYREF);
+ set_chunk_type(prev, CT_TYPE);
+
+ if (!( chunk_is_token(next, CT_OPERATOR)
+ || chunk_is_token(next, CT_TYPE)
+ || chunk_is_token(next, 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->orig_line, pc->orig_col, pc->Text());
+ chunk_flags_set(next, PCF_VAR_1ST);
+ }
+ }
+ else if (chunk_is_token(tmp, CT_DC_MEMBER))
+ {
+ set_chunk_type(prev, CT_TYPE);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( chunk_is_token(pc, CT_MINUS)
+ || chunk_is_token(pc, CT_PLUS))
+ {
+ if ( chunk_is_token(prev, CT_POS)
+ || chunk_is_token(prev, CT_NEG)
+ || chunk_is_token(prev, CT_ARITH)
+ || chunk_is_token(prev, CT_SHIFT))
+ {
+ set_chunk_type(pc, chunk_is_token(pc, CT_MINUS) ? CT_NEG : CT_POS);
+ }
+ else if (chunk_is_token(prev, CT_OC_CLASS))
+ {
+ set_chunk_type(pc, (chunk_is_token(pc, CT_MINUS)) ? CT_NEG : CT_POS);
+ }
+ else
+ {
+ set_chunk_type(pc, 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 (chunk_is_token(pc, CT_WORD)) // here NSString
+ {
+ if (pc->next != nullptr) // here *
+ {
+ if (pc->next->type == CT_STAR) // here *
+ {
+ // compare text with "C" to find extern "C" instructions
+ if (pc->prev != nullptr)
+ {
+ if (pc->prev->type == CT_STRING)
+ {
+ if (unc_text::compare(pc->prev->Text(), "\"C\"") == 0)
+ {
+ if (pc->prev->prev->type == CT_EXTERN)
+ {
+ set_chunk_type(pc, CT_TYPE); // change CT_WORD => CT_TYPE
+ set_chunk_type(pc->next, CT_PTR_TYPE); // change CT_STAR => CT_PTR_TYPE
+ }
+ }
+ }
+ }
+
+ // Issue #322 STDMETHOD(GetValues)(BSTR bsName, REFDATA** pData);
+ if ( (pc->next->next != nullptr)
+ && pc->next->next->type == CT_STAR
+ && pc->flags.test(PCF_IN_CONST_ARGS))
+ {
+ // change CT_STAR => CT_PTR_TYPE
+ set_chunk_type(pc->next, CT_PTR_TYPE);
+ set_chunk_type(pc->next->next, CT_PTR_TYPE);
+ }
+
+ // Issue #222 whatever3 *(func_ptr)( whatever4 *foo2, ...
+ if ( (pc->next->next != nullptr)
+ && pc->next->next->type == CT_WORD
+ && pc->flags.test(PCF_IN_FCN_DEF))
+ {
+ // look for the opening parenthesis
+ // Issue 1403
+ Chunk *tmp = pc->GetPrevType(CT_FPAREN_OPEN, pc->level - 1);
+
+ if ( tmp->IsNotNullChunk()
+ && get_chunk_parent_type(tmp) != CT_FUNC_CTOR_VAR)
+ {
+ set_chunk_type(pc->next, 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 (chunk_is_token(pc, CT_WORD)) // here NSString
+ {
+ if (pc->next != nullptr) // here *
+ {
+ if (pc->next->type == CT_STAR) // here *
+ {
+ Chunk *tmp = pc;
+
+ while ( tmp != nullptr
+ && tmp->IsNotNullChunk())
+ {
+ if (chunk_is_token(tmp, CT_ATTRIBUTE))
+ {
+ LOG_FMT(LFCNR, "%s(%d): ATTRIBUTE found, type is %s, Text() '%s'\n",
+ __func__, __LINE__, get_token_name(tmp->type), tmp->Text());
+ LOG_FMT(LFCNR, "for token, type is %s, Text() '%s'\n", get_token_name(pc->type), pc->Text());
+ // change CT_WORD => CT_TYPE
+ set_chunk_type(pc, CT_TYPE);
+ // change CT_STAR => CT_PTR_TYPE
+ set_chunk_type(pc->next, CT_PTR_TYPE);
+ }
+
+ if (tmp->flags.test(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 (chunk_is_token(pc, CT_USING))
+ {
+ // look for CT_ASSIGN before CT_SEMICOLON at the end of the statement
+
+ bool is_preproc = pc->flags.test(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->orig_line, temp->orig_col,
+ temp->Text(), get_token_name(temp->type));
+
+ if (chunk_is_token(temp, CT_ASSIGN))
+ {
+ return(true);
+ }
+
+ if ( chunk_is_token(temp, CT_SEMICOLON)
+ || ( is_preproc
+ && ( !temp->flags.test(PCF_IN_PREPROC)
+ || chunk_is_token(temp, 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 (get_chunk_parent_type(temp) == CT_NONE)
+ {
+ set_chunk_parent(temp, CT_USING_ALIAS);
+ }
+
+ if ( chunk_is_token(temp, CT_SEMICOLON)
+ || ( is_preproc
+ && ( !temp->flags.test(PCF_IN_PREPROC)
+ || chunk_is_token(temp, CT_PREPROC))))
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ // Issue #548: inline T && someFunc(foo * *p, bar && q) { }
+ if ( chunk_is_token(pc, CT_BOOL)
+ && !pc->flags.test(PCF_IN_PREPROC)
+ && chunk_is_str(pc, "&&")
+ && chunk_ends_type(pc->prev))
+ {
+ 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->orig_line, tmp->orig_col,
+ tmp->Text(), get_token_name(tmp->type));
+ log_pcf_flags(LFCNR, tmp->flags);
+ // look for a type
+
+ if (chunk_is_token(tmp, CT_TYPE))
+ {
+ LOG_FMT(LFCNR, "%s(%d): orig_line is %zu, orig_col is %zu, Text() '%s', type is %s\n",
+ __func__, __LINE__, pc->orig_line, pc->orig_col,
+ pc->Text(), get_token_name(pc->type));
+ log_pcf_flags(LFCNR, pc->flags);
+ set_chunk_type(pc, CT_BYREF);
+ }
+ // look next, is there a "assign" before the ";"
+ Chunk *semi = pc->GetNextType(CT_SEMICOLON, pc->level); // 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->orig_line, semi->orig_col,
+ semi->Text(), get_token_name(semi->type));
+
+ 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->orig_line, test_it->orig_col,
+ test_it->Text(), get_token_name(test_it->type));
+
+ if (chunk_is_token(test_it, CT_ASSIGN))
+ {
+ // the statement is an assigment
+ // && is before assign
+ set_chunk_type(pc, CT_BYREF);
+ break;
+ }
+ }
+ }
+ }
+
+ // Issue #1704
+ if ( chunk_is_token(pc, CT_INCDEC_AFTER)
+ && pc->flags.test(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->orig_line, pc->orig_col,
+ pc->Text(), get_token_name(pc->type));
+ log_pcf_flags(LFTYPE, pc->flags);
+
+ if (chunk_is_token(tmp_2, CT_WORD))
+ {
+ set_chunk_type(pc, 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->orig_line, bo1->orig_col);
+ Chunk *pc = bo1->GetPrevNcNnlNi(); // Issue #2279
+
+ if (pc->IsNullChunk())
+ {
+ return;
+ }
+
+ if (chunk_is_paren_close(pc))
+ {
+ Chunk *bo2 = bo1->GetNext();
+
+ if (bo2->IsNullChunk())
+ {
+ return;
+ }
+
+ if (chunk_is_token(bo2, CT_BRACE_OPEN))
+ {
+ // found a potential double brace
+ Chunk *bc2 = chunk_skip_to_match(bo2);
+
+ if (bc2 == nullptr)
+ {
+ return;
+ }
+ Chunk *bc1 = bc2->GetNext();
+
+ if (bc1->IsNullChunk())
+ {
+ return;
+ }
+
+ if (chunk_is_token(bc1, CT_BRACE_CLOSE))
+ {
+ LOG_FMT(LJDBI, " - end, orig_line is %zu, orig_col is %zu\n", bc2->orig_line, bc2->orig_col);
+ // delete bo2 and bc1
+ bo1->str += bo2->str;
+ bo1->orig_col_end = bo2->orig_col_end;
+ chunk_del(bo2);
+ set_chunk_parent(bo1, CT_DOUBLE_BRACE);
+
+ bc2->str += bc1->str;
+ bc2->orig_col_end = bc1->orig_col_end;
+ chunk_del(bc1);
+ set_chunk_parent(bc2, CT_DOUBLE_BRACE);
+ return;
+ }
+ }
+ }
+ LOG_FMT(LJDBI, " - no\n");
+} // check_double_brace_init
+
+
+void fix_symbols(void)
+{
+ LOG_FUNC_ENTRY();
+ Chunk *pc;
+ Chunk dummy;
+
+ 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())
+ {
+ if ( chunk_is_token(pc, CT_FUNC_WRAP)
+ || chunk_is_token(pc, CT_TYPE_WRAP))
+ {
+ handle_wrap(pc);
+ }
+
+ if (chunk_is_token(pc, 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
+ && chunk_is_token(pc, CT_BRACE_OPEN)
+ && ( chunk_is_token(prev, CT_WORD)
+ || chunk_is_token(prev, CT_TYPE)))
+ {
+ mark_lvalue(pc);
+ }
+
+ if ( is_java
+ && chunk_is_token(pc, CT_BRACE_OPEN))
+ {
+ check_double_brace_init(pc);
+ }
+
+ if (chunk_is_token(pc, CT_ATTRIBUTE))
+ {
+ Chunk *next = pc->GetNextNcNnl(E_Scope::PREPROC);
+
+ if ( next->IsNotNullChunk()
+ && chunk_is_token(next, 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 (chunk_is_token(pc, 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->orig_line, pc->orig_col, pc->Text(), get_token_name(pc->type));
+ Chunk *prev = pc->GetPrevNcNnlNi(E_Scope::PREPROC); // Issue #2279
+
+ if (chunk_is_token(prev, CT_QUALIFIER))
+ {
+ prev = prev->GetPrevNcNnlNi(E_Scope::PREPROC); // Issue #3513
+ }
+
+ if (prev->IsNullChunk())
+ {
+ prev = &dummy;
+ }
+ 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->orig_line, prev->orig_col, prev->Text(), get_token_name(prev->type));
+ }
+ Chunk *next = pc->GetNextNcNnl(E_Scope::PREPROC);
+
+ if (next->IsNullChunk())
+ {
+ next = &dummy;
+ }
+ 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->orig_line, next->orig_col, next->Text(), get_token_name(next->type));
+ }
+ 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();
+
+ /*
+ * 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->orig_line, pc->orig_col, pc->ElidedText(copy), get_token_name(pc->type), get_token_name(pc->parent_type));
+
+ // Can't have a variable definition inside [ ]
+ if (square_level < 0)
+ {
+ if (chunk_is_token(pc, CT_SQUARE_OPEN))
+ {
+ square_level = pc->level;
+ }
+ }
+ else
+ {
+ if (pc->level <= static_cast<size_t>(square_level))
+ {
+ square_level = -1;
+ }
+ }
+
+ if ( chunk_is_token(pc, CT_EXTERN)
+ && language_is_set(LANG_ALLC))
+ {
+ Chunk *next = pc->GetNextNcNnl();
+
+ if (chunk_is_token(next, CT_STRING))
+ {
+ Chunk *tmp = next->GetNextNcNnl();
+
+ while (tmp->IsNotNullChunk())
+ {
+ if ( chunk_is_token(tmp, CT_TYPE)
+ || chunk_is_token(tmp, CT_BRACE_OPEN)
+ || chunk_is_token(tmp, CT_ATTRIBUTE))
+ {
+ break;
+ }
+
+ if (chunk_is_token(tmp, CT_WORD))
+ {
+ chunk_flags_set(tmp, PCF_STMT_START | PCF_EXPR_START);
+ break;
+ }
+ tmp = tmp->GetNextNcNnl();
+ }
+ }
+ }
+
+ if ( chunk_is_token(pc, CT_ATTRIBUTE)
+ && language_is_set(LANG_ALLC))
+ {
+ Chunk *tmp = skip_attribute_next(pc);
+
+ if (chunk_is_token(tmp, CT_WORD))
+ {
+ chunk_flags_set(tmp, PCF_STMT_START | PCF_EXPR_START);
+ }
+ }
+
+ if ( chunk_is_token(pc, CT_BRACE_OPEN) // Issue #2332
+ && get_chunk_parent_type(pc) == 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->orig_line, pc->orig_col, pc->Text());
+ pc = pc->GetNextType(CT_BRACE_CLOSE, pc->level);
+ }
+ /*
+ * 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->orig_line, pc->orig_col, pc->ElidedText(copy), get_token_name(pc->type), get_token_name(pc->parent_type));
+ log_pcf_flags(LFCNR, pc->flags);
+
+ if ( (square_level < 0)
+ && pc->flags.test(PCF_STMT_START)
+ && ( chunk_is_token(pc, CT_QUALIFIER)
+ || chunk_is_token(pc, CT_TYPE)
+ || chunk_is_token(pc, CT_TYPENAME)
+ || chunk_is_token(pc, CT_DC_MEMBER) // Issue #2478
+ || chunk_is_token(pc, CT_WORD))
+ && get_chunk_parent_type(pc) != CT_BIT_COLON
+ && get_chunk_parent_type(pc) != CT_ENUM
+ && !pc->flags.test(PCF_IN_CLASS_BASE)
+ && !pc->flags.test(PCF_IN_ENUM))
+ {
+ pc = fix_variable_definition(pc);
+ }
+ else
+ {
+ pc = pc->GetNextNcNnl();
+ }
+ }
+} // fix_symbols
+
+
+static void process_returns(void)
+{
+ LOG_FUNC_ENTRY();
+ Chunk *pc;
+
+ pc = Chunk::GetHead();
+
+ while (pc->IsNotNullChunk())
+ {
+ if (chunk_is_not_token(pc, CT_RETURN))
+ {
+ pc = pc->GetNextType(CT_RETURN, -1);
+ continue;
+ }
+ pc = process_return(pc);
+ }
+}
+
+
+static Chunk *process_return(Chunk *pc)
+{
+ LOG_FUNC_ENTRY();
+ 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()
+ || chunk_is_semicolon(next)
+ || chunk_is_token(next, CT_NEWLINE))
+ {
+ return(next);
+ }
+ log_rule_B("nl_return_expr");
+
+ if ( options::nl_return_expr() != IARF_IGNORE
+ && !pc->flags.test(PCF_IN_PREPROC))
+ {
+ newline_iarf(pc, options::nl_return_expr());
+ }
+
+ if (chunk_is_token(next, CT_PAREN_OPEN))
+ {
+ // See if the return is fully paren'd
+ cpar = next->GetNextType(CT_PAREN_CLOSE, next->level);
+
+ if (cpar->IsNullChunk())
+ {
+ return(Chunk::NullChunkPtr);
+ }
+ semi = cpar->PpaGetNextNcNnl();
+
+ if (semi->IsNullChunk())
+ {
+ return(Chunk::NullChunkPtr);
+ }
+
+ if ( chunk_is_token(semi, CT_NEWLINE)
+ || chunk_is_semicolon(semi))
+ {
+ log_rule_B("mod_paren_on_return");
+
+ if (options::mod_paren_on_return() == IARF_REMOVE)
+ {
+ LOG_FMT(LRETURN, "%s(%d): removing parens on orig_line %zu\n",
+ __func__, __LINE__, pc->orig_line);
+
+ // lower the level of everything
+ for (temp = next; temp != cpar; temp = temp->GetNext())
+ {
+ if (temp->level == 0)
+ {
+ fprintf(stderr, "%s(%d): temp->level is ZERO, cannot be decremented, at line %zu, column %zu\n",
+ __func__, __LINE__, temp->orig_line, temp->orig_col);
+ log_flush(true);
+ exit(EX_SOFTWARE);
+ }
+ temp->level--;
+ }
+
+ // delete the parenthesis
+ chunk_del(next);
+ chunk_del(cpar);
+
+ // back up following chunks
+ temp = semi;
+
+ while ( temp->IsNotNullChunk()
+ && chunk_is_not_token(temp, CT_NEWLINE))
+ {
+ temp->column = temp->column - 2;
+ temp->orig_col = temp->orig_col - 2;
+ temp->orig_col_end = temp->orig_col_end - 2;
+ temp = temp->GetNext();
+ }
+ }
+ else
+ {
+ LOG_FMT(LRETURN, "%s(%d): keeping parens on orig_line %zu\n",
+ __func__, __LINE__, pc->orig_line);
+
+ // mark & keep them
+ set_chunk_parent(next, CT_RETURN);
+ set_chunk_parent(cpar, CT_RETURN);
+ }
+ return(semi);
+ }
+ }
+ // We don't have a fully paren'd return. Should we add some?
+ log_rule_B("mod_paren_on_return");
+
+ if (!(options::mod_paren_on_return() & 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)
+ && chunk_is_token(next, CT_BRACE_OPEN)
+ && get_chunk_parent_type(next) == CT_BRACED_INIT_LIST)
+ {
+ LOG_FMT(LRETURN, "%s(%d): not adding parens around braced initializer"
+ " on orig_line %zd\n",
+ __func__, __LINE__, pc->orig_line);
+ return(next);
+ }
+ // find the next semicolon on the same level
+ semi = next;
+
+ if (pc->flags.test(PCF_IN_PREPROC))
+ {
+ while ((semi = semi->GetNext())->IsNotNullChunk())
+ {
+ if (!semi->flags.test(PCF_IN_PREPROC))
+ {
+ break;
+ }
+
+ if (semi->level < pc->level)
+ {
+ return(semi);
+ }
+
+ if ( chunk_is_semicolon(semi)
+ && pc->level == semi->level)
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ while ((semi = semi->GetNext())->IsNotNullChunk())
+ {
+ if (semi->level < pc->level)
+ {
+ return(semi);
+ }
+
+ if ( chunk_is_semicolon(semi)
+ && pc->level == semi->level)
+ {
+ break;
+ }
+ }
+ }
+
+ if (semi)
+ {
+ // add the parenthesis
+ set_chunk_type(&chunk, CT_PAREN_OPEN);
+ set_chunk_parent(&chunk, CT_RETURN);
+ chunk.str = "(";
+ chunk.level = pc->level;
+ chunk.pp_level = pc->pp_level;
+ chunk.brace_level = pc->brace_level;
+ chunk.orig_line = pc->orig_line;
+ chunk.orig_col = next->orig_col - 1;
+ chunk.flags = pc->flags & PCF_COPY_FLAGS;
+ chunk_add_before(&chunk, next);
+
+ set_chunk_type(&chunk, CT_PAREN_CLOSE);
+ chunk.str = ")";
+ chunk.orig_line = semi->orig_line;
+ chunk.orig_col = semi->orig_col - 1;
+ cpar = chunk_add_before(&chunk, semi);
+
+ LOG_FMT(LRETURN, "%s(%d): added parens on orig_line %zu\n",
+ __func__, __LINE__, pc->orig_line);
+
+ for (temp = next; temp != cpar; temp = temp->GetNext())
+ {
+ temp->level++;
+ }
+ }
+ return(semi);
+} // process_return
+
+
+static bool is_oc_block(Chunk *pc)
+{
+ return( pc != nullptr
+ && ( get_chunk_parent_type(pc) == CT_OC_BLOCK_TYPE
+ || get_chunk_parent_type(pc) == CT_OC_BLOCK_EXPR
+ || get_chunk_parent_type(pc) == CT_OC_BLOCK_ARG
+ || get_chunk_parent_type(pc) == CT_OC_BLOCK
+ || chunk_is_token(pc, CT_OC_BLOCK_CARET)
+ || ( pc->next != nullptr
+ && pc->next->type == CT_OC_BLOCK_CARET)
+ || ( pc->prev != nullptr
+ && pc->prev->type == CT_OC_BLOCK_CARET)));
+}
+
+
+void mark_comments(void)
+{
+ 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() || chunk_is_newline(next);
+
+ if (cur->IsComment())
+ {
+ if ( next_nl
+ && prev_nl)
+ {
+ set_chunk_parent(cur, CT_COMMENT_WHOLE);
+ }
+ else if (next_nl)
+ {
+ set_chunk_parent(cur, CT_COMMENT_END);
+ }
+ else if (prev_nl)
+ {
+ set_chunk_parent(cur, CT_COMMENT_START);
+ }
+ else
+ {
+ set_chunk_parent(cur, CT_COMMENT_EMBED);
+ }
+ }
+ prev_nl = chunk_is_newline(cur);
+ cur = next;
+ }
+}
+
+
+static void handle_cpp_template(Chunk *pc)
+{
+ LOG_FUNC_ENTRY();
+
+ Chunk *tmp = pc->GetNextNcNnl();
+
+ if (chunk_is_not_token(tmp, CT_ANGLE_OPEN))
+ {
+ return;
+ }
+ set_chunk_parent(tmp, CT_TEMPLATE);
+
+ size_t level = tmp->level;
+
+ tmp = tmp->GetNext();
+
+ while (tmp->IsNotNullChunk())
+ {
+ if ( chunk_is_token(tmp, CT_CLASS)
+ || chunk_is_token(tmp, CT_STRUCT))
+ {
+ set_chunk_type(tmp, CT_TYPE);
+ }
+ else if ( chunk_is_token(tmp, CT_ANGLE_CLOSE)
+ && tmp->level == level)
+ {
+ set_chunk_parent(tmp, CT_TEMPLATE);
+ break;
+ }
+ tmp = tmp->GetNext();
+ }
+
+ if (tmp->IsNotNullChunk())
+ {
+ tmp = tmp->GetNextNcNnl();
+
+ if (chunk_is_token(tmp, CT_FRIEND))
+ {
+ // Account for a template friend declaration
+ set_chunk_parent(tmp, CT_TEMPLATE);
+
+ tmp = tmp->GetNextNcNnl();
+ }
+
+ if ( chunk_is_token(tmp, CT_CLASS)
+ || chunk_is_token(tmp, CT_STRUCT))
+ {
+ set_chunk_parent(tmp, CT_TEMPLATE);
+
+ // REVISIT: This may be a bit risky - might need to track the { };
+ tmp = tmp->GetNextType(CT_SEMICOLON, tmp->level);
+
+ if (tmp->IsNotNullChunk())
+ {
+ set_chunk_parent(tmp, 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()
+ || ( chunk_is_not_token(prev, CT_ASSIGN)
+ && chunk_is_not_token(prev, CT_COMMA)
+ && chunk_is_not_token(prev, CT_PAREN_OPEN) // allow Js like self invoking lambda syntax: ([](){})();
+ && chunk_is_not_token(prev, CT_FPAREN_OPEN)
+ && chunk_is_not_token(prev, CT_SQUARE_OPEN)
+ && chunk_is_not_token(prev, CT_BRACE_OPEN)
+ && chunk_is_not_token(prev, CT_SEMICOLON)
+ && chunk_is_not_token(prev, CT_RETURN)))
+ {
+ LOG_FMT(LFCNR, "%s(%d): return\n", __func__, __LINE__);
+ return;
+ }
+ Chunk *sq_c = sq_o; // assuming '[]'
+
+ if (chunk_is_token(sq_o, CT_SQUARE_OPEN))
+ {
+ // make sure there is a ']'
+ sq_c = chunk_skip_to_match(sq_o);
+
+ if (sq_c == nullptr)
+ {
+ 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 (chunk_is_token(pa_o, 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 (chunk_is_token(pa_o, CT_PAREN_OPEN))
+ {
+ // and now find the ')'
+ pa_c = chunk_skip_to_match(pa_o);
+
+ 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 (chunk_is_str(br_o, "mutable"))
+ {
+ br_o = br_o->GetNextNcNnl();
+ }
+ //TODO: also check for exception and attribute between [] ... {}
+
+ // skip possible arrow syntax: '-> ret'
+ if (chunk_is_str(br_o, "->"))
+ {
+ ret = br_o;
+ // REVISIT: really should check the stuff we are skipping
+ br_o = br_o->GetNextType(CT_BRACE_OPEN, br_o->level);
+ }
+
+ // skip possible CT_NOEXCEPT
+ if (chunk_is_token(br_o, 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->level);
+ }
+
+ if (br_o->IsNullChunk())
+ {
+ LOG_FMT(LFCNR, "%s(%d): br_o is null. Return\n", __func__, __LINE__);
+ return;
+ }
+
+ if (chunk_is_not_token(br_o, CT_BRACE_OPEN))
+ {
+ LOG_FMT(LFCNR, "%s(%d): br_o is '%s'/%s\n",
+ __func__, __LINE__,
+ br_o->Text(), get_token_name(br_o->type));
+ LOG_FMT(LFCNR, "%s(%d): return\n", __func__, __LINE__);
+ return;
+ }
+ // and now find the '}'
+ Chunk *br_c = chunk_skip_to_match(br_o);
+
+ if (br_c->IsNullChunk())
+ {
+ LOG_FMT(LFCNR, "%s(%d): return\n", __func__, __LINE__);
+ return;
+ }
+
+ // This looks like a lambda expression
+ if (chunk_is_token(sq_o, CT_TSQUARE))
+ {
+ // split into two chunks
+ Chunk nc;
+
+ nc = *sq_o;
+ set_chunk_type(sq_o, CT_SQUARE_OPEN);
+ sq_o->str.resize(1);
+ /*
+ * bug # 664
+ *
+ * The original orig_col of CT_SQUARE_CLOSE is stored at orig_col_end
+ * of CT_TSQUARE. CT_SQUARE_CLOSE orig_col and orig_col_end values
+ * are calculate from orig_col_end of CT_TSQUARE.
+ */
+ nc.orig_col = sq_o->orig_col_end - 1;
+ nc.column = static_cast<int>(nc.orig_col);
+ nc.orig_col_end = sq_o->orig_col_end;
+ sq_o->orig_col_end = sq_o->orig_col + 1;
+
+ set_chunk_type(&nc, CT_SQUARE_CLOSE);
+ nc.str.pop_front();
+ sq_c = chunk_add_after(&nc, sq_o);
+ }
+ set_chunk_parent(sq_o, CT_CPP_LAMBDA);
+ set_chunk_parent(sq_c, CT_CPP_LAMBDA);
+
+ if (pa_c->IsNotNullChunk())
+ {
+ set_chunk_type(pa_o, CT_LPAREN_OPEN); // Issue #3054
+ set_chunk_parent(pa_o, CT_CPP_LAMBDA);
+ chunk_set_parent(pa_o, sq_o);
+ chunk_set_parent(br_o, sq_o);
+ set_chunk_type(pa_c, CT_LPAREN_CLOSE);
+ set_chunk_parent(pa_c, CT_CPP_LAMBDA);
+ chunk_set_parent(pa_c, sq_o);
+ chunk_set_parent(br_c, sq_o);
+ }
+ set_chunk_parent(br_o, CT_CPP_LAMBDA);
+ set_chunk_parent(br_c, CT_CPP_LAMBDA);
+
+ if (ret->IsNotNullChunk())
+ {
+ set_chunk_type(ret, 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 (chunk_is_token(call_pa_o, CT_PAREN_OPEN))
+ {
+ Chunk *call_pa_c = chunk_skip_to_match(call_pa_o);
+
+ if (call_pa_c->IsNotNullChunk())
+ {
+ set_chunk_type(call_pa_o, CT_FPAREN_OPEN);
+ set_chunk_parent(call_pa_o, CT_FUNC_CALL);
+ set_chunk_type(call_pa_c, CT_FPAREN_CLOSE);
+ set_chunk_parent(call_pa_c, 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 || (name->type != CT_WORD && name->type != CT_WORD)) Coverity CID 76000 Same on both sides, 2016-03-16
+ if ( name->IsNullChunk()
+ || chunk_is_not_token(name, CT_WORD))
+ {
+ // TODO: log an error, expected NAME
+ return;
+ }
+
+ if ( po->IsNullChunk()
+ || chunk_is_not_token(po, CT_PAREN_OPEN))
+ {
+ // TODO: log an error, expected '('
+ return;
+ }
+ set_chunk_type(name, CT_TYPE);
+ set_chunk_parent(name, CT_TEMPLATE);
+ set_chunk_parent(po, CT_TEMPLATE);
+
+ ChunkStack cs;
+ Chunk *tmp = get_d_template_types(cs, po);
+
+ if ( tmp == nullptr
+ || chunk_is_not_token(tmp, CT_PAREN_CLOSE))
+ {
+ // TODO: log an error, expected ')'
+ return;
+ }
+ set_chunk_parent(tmp, CT_TEMPLATE);
+
+ tmp = tmp->GetNextNcNnl();
+
+ if (chunk_is_not_token(tmp, CT_BRACE_OPEN))
+ {
+ // TODO: log an error, expected '{'
+ return;
+ }
+ set_chunk_parent(tmp, CT_TEMPLATE);
+ po = tmp;
+ tmp = tmp->GetNextNcNnl();
+
+ while ( tmp->IsNotNullChunk()
+ && tmp->level > po->level)
+ {
+ if ( chunk_is_token(tmp, CT_WORD)
+ && chunkstack_match(cs, tmp))
+ {
+ set_chunk_type(tmp, CT_TYPE);
+ }
+ tmp = tmp->GetNextNcNnl();
+ }
+// if (!chunk_is_token(tmp, CT_BRACE_CLOSE))
+// {
+// // TODO: log an error, expected '}'
+// }
+ set_chunk_parent(tmp, CT_TEMPLATE);
+} // handle_d_template
+
+
+Chunk *skip_template_next(Chunk *ang_open)
+{
+ if (ang_open == nullptr)
+ {
+ return(Chunk::NullChunkPtr);
+ }
+
+ if (chunk_is_token(ang_open, CT_ANGLE_OPEN))
+ {
+ Chunk *pc = ang_open->GetNextType(CT_ANGLE_CLOSE, ang_open->level);
+
+ 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(get_chunk_parent_type(pc)), pc->orig_line);
+
+ if (get_chunk_parent_type(pc) == CT_OC_PROTOCOL)
+ {
+ tmp = pc->GetNextNcNnl();
+
+ if (chunk_is_semicolon(tmp))
+ {
+ set_chunk_parent(tmp, get_chunk_parent_type(pc));
+ 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->orig_line, tmp->Text());
+
+ if (chunk_is_token(tmp, CT_OC_END))
+ {
+ break;
+ }
+
+ if (chunk_is_token(tmp, CT_PAREN_OPEN))
+ {
+ passed_name = true;
+ }
+
+ if (chunk_is_str(tmp, "<"))
+ {
+ set_chunk_type(tmp, CT_ANGLE_OPEN);
+
+ if (passed_name)
+ {
+ set_chunk_parent(tmp, CT_OC_PROTO_LIST);
+ }
+ else
+ {
+ set_chunk_parent(tmp, CT_OC_GENERIC_SPEC);
+ generic_level++;
+ }
+ as = angle_state_e::OPEN;
+ }
+
+ if (chunk_is_str(tmp, ">"))
+ {
+ set_chunk_type(tmp, CT_ANGLE_CLOSE);
+
+ if (passed_name)
+ {
+ set_chunk_parent(tmp, CT_OC_PROTO_LIST);
+ as = angle_state_e::CLOSE;
+ }
+ else
+ {
+ set_chunk_parent(tmp, 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->orig_line, tmp->orig_col);
+ log_flush(true);
+ exit(EX_SOFTWARE);
+ }
+ generic_level--;
+
+ if (generic_level == 0)
+ {
+ as = angle_state_e::CLOSE;
+ }
+ }
+ }
+
+ if (chunk_is_str(tmp, ">>"))
+ {
+ set_chunk_type(tmp, CT_ANGLE_CLOSE);
+ set_chunk_parent(tmp, CT_OC_GENERIC_SPEC);
+ split_off_angle_close(tmp);
+ generic_level -= 1;
+
+ if (generic_level == 0)
+ {
+ as = angle_state_e::CLOSE;
+ }
+ }
+
+ if ( chunk_is_token(tmp, CT_BRACE_OPEN)
+ && get_chunk_parent_type(tmp) != CT_ASSIGN)
+ {
+ as = angle_state_e::CLOSE;
+ set_chunk_parent(tmp, CT_OC_CLASS);
+ tmp = tmp->GetNextType(CT_BRACE_CLOSE, tmp->level);
+
+ if ( tmp->IsNotNullChunk()
+ && get_chunk_parent_type(tmp) != CT_ASSIGN)
+ {
+ set_chunk_parent(tmp, CT_OC_CLASS);
+ }
+ }
+ else if (chunk_is_token(tmp, CT_COLON))
+ {
+ if (as != angle_state_e::OPEN)
+ {
+ passed_name = true;
+ }
+ set_chunk_type(tmp, hit_scope ? CT_OC_COLON : CT_CLASS_COLON);
+
+ if (chunk_is_token(tmp, CT_CLASS_COLON))
+ {
+ set_chunk_parent(tmp, CT_OC_CLASS);
+ }
+ }
+ else if ( chunk_is_str(tmp, "-")
+ || chunk_is_str(tmp, "+"))
+ {
+ as = angle_state_e::CLOSE;
+
+ if (chunk_is_newline(tmp->GetPrev()))
+ {
+ set_chunk_type(tmp, CT_OC_SCOPE);
+ chunk_flags_set(tmp, PCF_STMT_START);
+ hit_scope = true;
+ }
+ }
+
+ if (as == angle_state_e::OPEN)
+ {
+ if (passed_name)
+ {
+ set_chunk_parent(tmp, CT_OC_PROTO_LIST);
+ }
+ else
+ {
+ set_chunk_parent(tmp, CT_OC_GENERIC_SPEC);
+ }
+ }
+ }
+
+ if (chunk_is_token(tmp, CT_BRACE_OPEN))
+ {
+ tmp = tmp->GetNextType(CT_BRACE_CLOSE, tmp->level);
+
+ if (tmp->IsNotNullChunk())
+ {
+ set_chunk_parent(tmp, 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->orig_line, pc->orig_col);
+
+ 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 (chunk_is_str(tmp, "<"))
+ {
+ Chunk *ao = tmp;
+ Chunk *ac = ao->GetNextString(">", 1, ao->level);
+
+ if (ac->IsNotNullChunk())
+ {
+ set_chunk_type(ao, CT_ANGLE_OPEN);
+ set_chunk_parent(ao, CT_OC_PROTO_LIST);
+ set_chunk_type(ac, CT_ANGLE_CLOSE);
+ set_chunk_parent(ac, CT_OC_PROTO_LIST);
+
+ for (tmp = ao->GetNext(); tmp != ac; tmp = tmp->GetNext())
+ {
+ tmp->level += 1;
+ set_chunk_parent(tmp, CT_OC_PROTO_LIST);
+ }
+
+ tmp = ac->GetNextNcNnl();
+ }
+ else
+ {
+ tmp = Chunk::NullChunkPtr;
+ }
+ }
+ LOG_FMT(LOCBLK, " '%s'", tmp->Text());
+
+ if ( tmp->level < pc->level
+ || chunk_is_token(tmp, CT_SEMICOLON))
+ {
+ LOG_FMT(LOCBLK, "[DONE]");
+ break;
+ }
+
+ if (tmp->level == pc->level)
+ {
+ if (chunk_is_paren_open(tmp))
+ {
+ apo = tmp;
+ LOG_FMT(LOCBLK, "[PAREN]");
+ }
+
+ if (chunk_is_token(tmp, CT_BRACE_OPEN))
+ {
+ LOG_FMT(LOCBLK, "[BRACE]");
+ bbo = tmp;
+ break;
+ }
+ }
+ }
+
+ // make sure we have braces
+ bbc = chunk_skip_to_match(bbo);
+
+ if ( bbo->IsNullChunk()
+ || bbc == nullptr
+ || bbc->IsNullChunk())
+ {
+ LOG_FMT(LOCBLK, " -- no braces found\n");
+ return;
+ }
+ LOG_FMT(LOCBLK, "\n");
+
+ // we are on a block literal for sure
+ set_chunk_type(pc, CT_OC_BLOCK_CARET);
+ set_chunk_parent(pc, CT_OC_BLOCK_EXPR);
+
+ // handle the optional args
+ Chunk *lbp; // last before paren - end of return type, if any
+
+ if (apo->IsNotNullChunk())
+ {
+ Chunk *apc = chunk_skip_to_match(apo); // arg parenthesis close
+
+ if (chunk_is_paren_close(apc))
+ {
+ LOG_FMT(LOCBLK, " -- marking parens @ apo->orig_line is %zu, apo->orig_col is %zu and apc->orig_line is %zu, apc->orig_col is %zu\n",
+ apo->orig_line, apo->orig_col, apc->orig_line, apc->orig_col);
+ 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->type));
+ make_type(lbp);
+ chunk_flags_set(lbp, PCF_OC_RTYPE);
+ set_chunk_parent(lbp, CT_OC_BLOCK_EXPR);
+ lbp = lbp->GetPrevNcNnlNi(); // Issue #2279
+ }
+ // mark the braces
+ set_chunk_parent(bbo, CT_OC_BLOCK_EXPR);
+ set_chunk_parent(bbc, CT_OC_BLOCK_EXPR);
+} // handle_oc_block_literal
+
+
+static void handle_oc_block_type(Chunk *pc)
+{
+ LOG_FUNC_ENTRY();
+
+ if (pc == nullptr)
+ {
+ return;
+ }
+
+ if (pc->flags.test(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->orig_line, pc->orig_col);
+ return;
+ }
+ // make sure we have '( ^'
+ Chunk *tpo = pc->GetPrevNcNnlNi(); // type paren open Issue #2279
+
+ if (chunk_is_paren_open(tpo))
+ {
+ /*
+ * block type: 'RTYPE (^LABEL)(ARGS)'
+ * LABEL is optional.
+ */
+ Chunk *tpc = chunk_skip_to_match(tpo); // type close paren (after '^')
+ Chunk *nam = tpc->GetPrevNcNnlNi(); // name (if any) or '^' Issue #2279
+ Chunk *apo = tpc->GetNextNcNnl(); // arg open paren
+ Chunk *apc = chunk_skip_to_match(apo); // 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 (chunk_is_closing_brace(nam))
+ {
+ return(handle_oc_block_literal(pc));
+ }
+
+ // Check apo is '(' or else this might be a block literal. Issue 2643.
+ if (!chunk_is_paren_open(apo))
+ {
+ return(handle_oc_block_literal(pc));
+ }
+
+ if (chunk_is_paren_close(apc))
+ {
+ Chunk *aft = apc->GetNextNcNnl();
+ E_Token pt;
+
+ if (chunk_is_str(nam, "^"))
+ {
+ set_chunk_type(nam, CT_PTR_TYPE);
+ pt = CT_FUNC_TYPE;
+ }
+ else if ( chunk_is_token(aft, CT_ASSIGN)
+ || chunk_is_token(aft, CT_SEMICOLON))
+ {
+ set_chunk_type(nam, CT_FUNC_VAR);
+ pt = CT_FUNC_VAR;
+ }
+ else
+ {
+ set_chunk_type(nam, 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->orig_line, pc->orig_col, nam->Text(), get_token_name(nam->type));
+ set_chunk_type(pc, CT_PTR_TYPE);
+ set_chunk_parent(pc, pt); //CT_OC_BLOCK_TYPE;
+ set_chunk_type(tpo, CT_TPAREN_OPEN);
+ set_chunk_parent(tpo, pt); //CT_OC_BLOCK_TYPE;
+ set_chunk_type(tpc, CT_TPAREN_CLOSE);
+ set_chunk_parent(tpc, pt); //CT_OC_BLOCK_TYPE;
+ set_chunk_type(apo, CT_FPAREN_OPEN);
+ set_chunk_parent(apo, CT_FUNC_PROTO);
+ set_chunk_type(apc, CT_FPAREN_CLOSE);
+ set_chunk_parent(apc, 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, pcf_flags_t flags, bool &did_it)
+{
+ Chunk *paren_close;
+
+ if ( !chunk_is_paren_open(paren_open)
+ || ((paren_close = chunk_skip_to_match(paren_open)) == nullptr))
+ {
+ did_it = false;
+ return(paren_open);
+ }
+ did_it = true;
+
+ set_chunk_parent(paren_open, ptype);
+ chunk_flags_set(paren_open, flags);
+ set_chunk_parent(paren_close, ptype);
+ chunk_flags_set(paren_close, flags);
+
+ for (Chunk *cur = paren_open->GetNextNcNnl();
+ cur != paren_close;
+ cur = cur->GetNextNcNnl())
+ {
+ LOG_FMT(LOCMSGD, " <%s|%s>", cur->Text(), get_token_name(cur->type));
+ chunk_flags_set(cur, 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->level < pc->level)
+ {
+ // should not happen
+ return;
+ }
+
+ if ( chunk_is_token(tmp, CT_SEMICOLON)
+ || chunk_is_token(tmp, CT_BRACE_OPEN))
+ {
+ break;
+ }
+ }
+
+ if (tmp == nullptr)
+ {
+ return;
+ }
+ E_Token pt = chunk_is_token(tmp, CT_SEMICOLON) ? CT_OC_MSG_SPEC : CT_OC_MSG_DECL;
+
+ set_chunk_type(pc, CT_OC_SCOPE);
+ set_chunk_parent(pc, pt);
+
+ LOG_FMT(LOCMSGD, "%s(%d): %s @ orig_line is %zu, orig_col is %zu -",
+ __func__, __LINE__, get_token_name(pt), pc->orig_line, pc->orig_col);
+
+ // 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 (chunk_is_not_token(tmp, CT_WORD))
+ {
+ LOG_FMT(LOCMSGD, " -- missing method name\n");
+ return;
+ } // expect the method name/label
+
+ Chunk *label = tmp;
+
+ set_chunk_type(tmp, pt);
+ set_chunk_parent(tmp, pt);
+ pc = tmp->GetNextNcNnl();
+
+ LOG_FMT(LOCMSGD, " [%s]%s", pc->Text(), get_token_name(pc->type));
+
+ // if we have a colon next, we have args
+ if ( chunk_is_token(pc, CT_COLON)
+ || chunk_is_token(pc, CT_OC_COLON))
+ {
+ pc = label;
+
+ while (true)
+ {
+ // skip optional label
+ if ( chunk_is_token(pc, CT_WORD)
+ || chunk_is_token(pc, pt))
+ {
+ set_chunk_parent(pc, pt);
+ pc = pc->GetNextNcNnl();
+ }
+
+ // a colon must be next
+ if (!chunk_is_str(pc, ":"))
+ {
+ break;
+ }
+ set_chunk_type(pc, CT_OC_COLON);
+ set_chunk_parent(pc, 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->orig_line, pc->orig_col);
+ 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
+ chunk_flags_set(pc, PCF_VAR_DEF);
+ LOG_FMT(LOCMSGD, " arg[%s]", pc->Text());
+ pc = pc->GetNextNcNnl();
+ }
+ }
+ LOG_FMT(LOCMSGD, " end[%s]", pc->Text());
+
+ if (chunk_is_token(pc, CT_BRACE_OPEN))
+ {
+ set_chunk_parent(pc, pt);
+ pc = chunk_skip_to_match(pc);
+
+ if (pc != nullptr)
+ {
+ set_chunk_parent(pc, pt);
+ }
+ }
+ else if (chunk_is_token(pc, CT_SEMICOLON))
+ {
+ set_chunk_parent(pc, 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->level > os->level)
+ {
+ cs = cs->GetNext();
+ }
+
+ if ( cs->IsNullChunk()
+ || chunk_is_not_token(cs, CT_SQUARE_CLOSE))
+ {
+ return;
+ }
+ LOG_FMT(LOCMSG, "%s(%d): orig_line is %zu, orig_col is %zu\n",
+ __func__, __LINE__, os->orig_line, os->orig_col);
+
+ Chunk *tmp = cs->GetNextNcNnl();
+
+ if (chunk_is_semicolon(tmp))
+ {
+ set_chunk_parent(tmp, CT_OC_MSG);
+ }
+ // expect a word first thing or [...]
+ tmp = Chunk::NullChunkPtr;
+
+ if (os != nullptr)
+ {
+ tmp = os->GetNextNcNnl();
+ }
+
+ if ( chunk_is_token(tmp, CT_SQUARE_OPEN)
+ || chunk_is_token(tmp, CT_PAREN_OPEN)
+ || chunk_is_token(tmp, CT_OC_AT))
+ {
+ Chunk *tt = tmp->GetNextNcNnl();
+
+ if ( chunk_is_token(tmp, CT_OC_AT)
+ && tt->IsNotNullChunk())
+ {
+ if ( chunk_is_token(tt, CT_PAREN_OPEN)
+ || chunk_is_token(tt, CT_BRACE_OPEN)
+ || chunk_is_token(tt, CT_SQUARE_OPEN))
+ {
+ tmp = tt;
+ }
+ else
+ {
+ LOG_FMT(LOCMSG, "%s(%d): tmp->orig_line is %zu, tmp->orig_col is %zu, expected identifier, not '%s' [%s]\n",
+ __func__, __LINE__, tmp->orig_line, tmp->orig_col,
+ tmp->Text(), get_token_name(tmp->type));
+ return;
+ }
+ }
+ tmp = chunk_skip_to_match(tmp);
+ }
+ else if ( chunk_is_not_token(tmp, CT_WORD)
+ && chunk_is_not_token(tmp, CT_TYPE)
+ && chunk_is_not_token(tmp, CT_THIS)
+ && chunk_is_not_token(tmp, CT_STAR)
+ && chunk_is_not_token(tmp, CT_STRING))
+ {
+ LOG_FMT(LOCMSG, "%s(%d): orig_line is %zu, orig_col is %zu, expected identifier, not '%s' [%s]\n",
+ __func__, __LINE__, tmp->orig_line, tmp->orig_col,
+ tmp->Text(), get_token_name(tmp->type));
+ return;
+ }
+ else
+ {
+ if (tmp->IsStar()) // Issue #2722
+ {
+ set_chunk_type(tmp, CT_PTR_TYPE);
+ tmp = tmp->GetNextNcNnl();
+ }
+ Chunk *tt = tmp->GetNextNcNnl();
+
+ if (chunk_is_paren_open(tt))
+ {
+ 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->orig_line, tmp->orig_col, tmp->Text());
+ set_chunk_type(tmp, CT_FUNC_CALL);
+ tmp = set_paren_parent(tt, CT_FUNC_CALL)->GetPrevNcNnlNi(); // Issue #2279
+ }
+ else
+ {
+ set_chunk_type(tmp, CT_OC_MSG_CLASS);
+ }
+ }
+ set_chunk_parent(os, CT_OC_MSG);
+ chunk_flags_set(os, PCF_IN_OC_MSG);
+ set_chunk_parent(cs, CT_OC_MSG);
+ chunk_flags_set(cs, PCF_IN_OC_MSG);
+
+ // handle '< protocol >'
+ tmp = tmp->GetNextNcNnl();
+
+ if (chunk_is_str(tmp, "<"))
+ {
+ Chunk *ao = tmp;
+ Chunk *ac = ao->GetNextString(">", 1, ao->level);
+
+ if (ac->IsNotNullChunk())
+ {
+ set_chunk_type(ao, CT_ANGLE_OPEN);
+ set_chunk_parent(ao, CT_OC_PROTO_LIST);
+ set_chunk_type(ac, CT_ANGLE_CLOSE);
+ set_chunk_parent(ac, CT_OC_PROTO_LIST);
+
+ for (tmp = ao->GetNext(); tmp != ac; tmp = tmp->GetNext())
+ {
+ tmp->level += 1;
+ set_chunk_parent(tmp, CT_OC_PROTO_LIST);
+ }
+
+ tmp = ac->GetNextNcNnl();
+ }
+ else
+ {
+ tmp = Chunk::NullChunkPtr;
+ }
+ }
+ // handle 'object.property' and 'collection[index]'
+ else
+ {
+ while (tmp->IsNotNullChunk())
+ {
+ if (chunk_is_token(tmp, CT_MEMBER)) // move past [object.prop1.prop2
+ {
+ Chunk *typ = tmp->GetNextNcNnl();
+
+ if ( chunk_is_token(typ, CT_WORD)
+ || chunk_is_token(typ, CT_TYPE))
+ {
+ tmp = typ->GetNextNcNnl();
+ }
+ else
+ {
+ break;
+ }
+ }
+ else if (chunk_is_token(tmp, CT_SQUARE_OPEN)) // move past [collection[index]
+ {
+ Chunk *tcs = tmp->GetNextNcNnl();
+
+ while ( tcs->IsNotNullChunk()
+ && tcs->level > tmp->level)
+ {
+ tcs = tcs->GetNextNcNnl();
+ }
+
+ if (chunk_is_token(tcs, CT_SQUARE_CLOSE))
+ {
+ tmp = tcs->GetNextNcNnl();
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ // [(self.foo.bar) method]
+ if (chunk_is_paren_open(tmp))
+ {
+ tmp = chunk_skip_to_match(tmp)->GetNextNcNnl();
+ }
+
+ if ( chunk_is_token(tmp, CT_WORD)
+ || chunk_is_token(tmp, CT_TYPE))
+ {
+ set_chunk_type(tmp, CT_OC_MSG_FUNC);
+ }
+ Chunk *prev = Chunk::NullChunkPtr;
+
+ for (tmp = os->GetNext(); tmp != cs; tmp = tmp->GetNext())
+ {
+ chunk_flags_set(tmp, PCF_IN_OC_MSG);
+
+ if (tmp->level == cs->level + 1)
+ {
+ if (chunk_is_token(tmp, CT_COLON))
+ {
+ set_chunk_type(tmp, CT_OC_COLON);
+
+ if ( chunk_is_token(prev, CT_WORD)
+ || chunk_is_token(prev, CT_TYPE))
+ {
+ // Might be a named param, check previous block
+ Chunk *pp = prev->GetPrev();
+
+ if ( pp->IsNotNullChunk()
+ && chunk_is_not_token(pp, CT_OC_COLON)
+ && chunk_is_not_token(pp, CT_ARITH)
+ && chunk_is_not_token(pp, CT_SHIFT)
+ && chunk_is_not_token(pp, CT_CARET))
+ {
+ set_chunk_type(prev, CT_OC_MSG_NAME);
+ set_chunk_parent(tmp, 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->type;
+ set_chunk_type(os, 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 (chunk_is_token(next, 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()
+ && chunk_is_not_token(next, CT_PAREN_CLOSE))
+ {
+ if (chunk_is_token(next, CT_OC_PROPERTY_ATTR))
+ {
+ if ( chunk_is_str(next, "atomic")
+ || chunk_is_str(next, "nonatomic"))
+ {
+ ChunkGroup chunkGroup;
+ chunkGroup.push_back(next);
+ thread_chunks.push_back(chunkGroup);
+ }
+ else if ( chunk_is_str(next, "readonly")
+ || chunk_is_str(next, "readwrite"))
+ {
+ ChunkGroup chunkGroup;
+ chunkGroup.push_back(next);
+ readwrite_chunks.push_back(chunkGroup);
+ }
+ else if ( chunk_is_str(next, "assign")
+ || chunk_is_str(next, "retain")
+ || chunk_is_str(next, "copy")
+ || chunk_is_str(next, "strong")
+ || chunk_is_str(next, "weak")
+ || chunk_is_str(next, "unsafe_unretained"))
+ {
+ ChunkGroup chunkGroup;
+ chunkGroup.push_back(next);
+ ref_chunks.push_back(chunkGroup);
+ }
+ else if (chunk_is_str(next, "getter"))
+ {
+ ChunkGroup chunkGroup;
+
+ do
+ {
+ chunkGroup.push_back(next);
+ next = next->GetNext();
+ } while ( next->IsNotNullChunk()
+ && chunk_is_not_token(next, CT_COMMA)
+ && chunk_is_not_token(next, CT_PAREN_CLOSE));
+
+ next = next->GetPrev();
+
+ // coverity CID 160946
+ if (next->IsNullChunk())
+ {
+ break;
+ }
+ getter_chunks.push_back(chunkGroup);
+ }
+ else if (chunk_is_str(next, "setter"))
+ {
+ ChunkGroup chunkGroup;
+
+ do
+ {
+ chunkGroup.push_back(next);
+ next = next->GetNext();
+ } while ( next->IsNotNullChunk()
+ && chunk_is_not_token(next, CT_COMMA)
+ && chunk_is_not_token(next, CT_PAREN_CLOSE));
+
+ if (next->IsNotNullChunk())
+ {
+ next = next->GetPrev();
+ }
+
+ if (next->IsNullChunk())
+ {
+ break;
+ }
+ setter_chunks.push_back(chunkGroup);
+ }
+ else if ( chunk_is_str(next, "nullable")
+ || chunk_is_str(next, "nonnull")
+ || chunk_is_str(next, "null_resettable")
+ || chunk_is_str(next, "null_unspecified"))
+ {
+ ChunkGroup chunkGroup;
+ chunkGroup.push_back(next);
+ nullability_chunks.push_back(chunkGroup);
+ }
+ else if (chunk_is_str(next, "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 (chunk_is_word(next))
+ {
+ if (chunk_is_str(next, "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->orig_prev_sp = 0;
+
+ if (chunk != curr_chunk)
+ {
+ chunk_move_after(chunk, curr_chunk);
+ curr_chunk = chunk;
+ }
+ else
+ {
+ curr_chunk = curr_chunk->GetNext();
+ }
+ }
+
+ // add the parenthesis
+ Chunk endchunk;
+ set_chunk_type(&endchunk, CT_COMMA);
+ set_chunk_parent(&endchunk, get_chunk_parent_type(curr_chunk));
+ endchunk.str = ",";
+ endchunk.level = curr_chunk->level;
+ endchunk.pp_level = curr_chunk->pp_level;
+ endchunk.brace_level = curr_chunk->brace_level;
+ endchunk.orig_line = curr_chunk->orig_line;
+ endchunk.orig_col = curr_chunk->orig_col;
+ endchunk.column = curr_chunk->orig_col_end + 1;
+ endchunk.flags = curr_chunk->flags & PCF_COPY_FLAGS;
+ chunk_add_after(&endchunk, curr_chunk);
+ curr_chunk = curr_chunk->GetNext();
+ }
+ }
+
+ // Remove the extra comma's that we did not move
+ while ( curr_chunk != nullptr
+ && curr_chunk->IsNotNullChunk()
+ && chunk_is_not_token(curr_chunk, CT_PAREN_CLOSE))
+ {
+ Chunk *rm_chunk = curr_chunk;
+ curr_chunk = curr_chunk->GetNext();
+ chunk_del(rm_chunk);
+ }
+ }
+ }
+ Chunk *tmp = Chunk::NullChunkPtr;
+
+ if (os != nullptr)
+ {
+ tmp = os->GetNextNcNnl();
+ }
+
+ if (chunk_is_paren_open(tmp))
+ {
+ tmp = chunk_skip_to_match(tmp)->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->level > os->level)
+ {
+ cs = cs->GetNext();
+ }
+
+ if ( cs->IsNullChunk()
+ || chunk_is_not_token(cs, CT_SQUARE_CLOSE))
+ {
+ return;
+ }
+ set_chunk_parent(os, CT_CS_SQ_STMT);
+ set_chunk_parent(cs, CT_CS_SQ_STMT);
+
+ Chunk *tmp;
+
+ for (tmp = os->GetNext(); tmp != cs; tmp = tmp->GetNext())
+ {
+ set_chunk_parent(tmp, CT_CS_SQ_STMT);
+
+ if (chunk_is_token(tmp, CT_COLON))
+ {
+ set_chunk_type(tmp, CT_CS_SQ_COLON);
+ }
+ }
+
+ tmp = cs->GetNextNcNnl();
+
+ if (tmp->IsNotNullChunk())
+ {
+ chunk_flags_set(tmp, 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->level == bro->level)
+ {
+ //prevent scanning back past 'new' in expressions like new List<int> {1,2,3}
+ // Issue # 1620, UNI-24090.cs
+ if (chunk_is_token(pc, CT_NEW))
+ {
+ break;
+ }
+
+ if ( !did_prop
+ && ( chunk_is_token(pc, CT_WORD)
+ || chunk_is_token(pc, CT_THIS)))
+ {
+ set_chunk_type(pc, CT_CS_PROPERTY);
+ did_prop = true;
+ }
+ else
+ {
+ set_chunk_parent(pc, CT_CS_PROPERTY);
+ make_type(pc);
+ }
+
+ if (pc->flags.test(PCF_STMT_START))
+ {
+ break;
+ }
+ }
+ }
+}
+
+
+static void handle_cs_array_type(Chunk *pc)
+{
+ if ( pc == nullptr
+ || pc->IsNullChunk())
+ {
+ return;
+ }
+ Chunk *prev = pc->GetPrev();
+
+ for ( ;
+ chunk_is_token(prev, CT_COMMA);
+ prev = prev->GetPrev())
+ {
+ // empty
+ }
+
+ if (chunk_is_token(prev, CT_SQUARE_OPEN))
+ {
+ while (pc != prev)
+ {
+ set_chunk_parent(pc, CT_TYPE);
+ pc = pc->GetPrev();
+ }
+ set_chunk_parent(prev, 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 = chunk_is_token(pc, 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 = chunk_is_token(pc, CT_FUNC_WRAP) ?
+ options::sp_inside_fparen() :
+ options::sp_inside_paren_cast();
+
+ if ( chunk_is_token(clp, CT_PAREN_CLOSE)
+ && chunk_is_token(opp, CT_PAREN_OPEN)
+ && ( chunk_is_token(name, CT_WORD)
+ || chunk_is_token(name, 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->str);
+ pc->str.append(fsp);
+ pc->str.append(")");
+
+ set_chunk_type(pc, chunk_is_token(pc, CT_FUNC_WRAP) ? CT_FUNCTION : CT_TYPE);
+
+ pc->orig_col_end = pc->orig_col + pc->Len();
+
+ chunk_del(opp);
+ chunk_del(name);
+ chunk_del(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 = chunk_skip_to_match(opp);
+ Chunk *cma = clp->GetNextNcNnl();
+
+ if ( opp->IsNullChunk()
+ || name->IsNullChunk()
+ || tmp->IsNullChunk()
+ || clp == nullptr
+ || cma->IsNullChunk()
+ || ( chunk_is_not_token(name, CT_WORD)
+ && chunk_is_not_token(name, CT_TYPE))
+ || chunk_is_not_token(opp, CT_PAREN_OPEN))
+ {
+ return;
+ }
+
+ if (chunk_is_token(cma, CT_SEMICOLON))
+ {
+ set_chunk_type(pc, CT_FUNC_PROTO);
+ }
+ else if (chunk_is_token(cma, 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->orig_line, pc->orig_col, pc->Text());
+ set_chunk_type(pc, CT_FUNC_DEF);
+ }
+ else
+ {
+ return;
+ }
+ set_chunk_parent(opp, pc->type);
+ set_chunk_parent(clp, pc->type);
+
+ set_chunk_parent(tmp, CT_PROTO_WRAP);
+
+ if (chunk_is_token(tmp, CT_PAREN_OPEN))
+ {
+ fix_fcn_def_params(tmp);
+ }
+ else
+ {
+ fix_fcn_def_params(opp);
+ set_chunk_type(name, CT_WORD);
+ }
+ tmp = chunk_skip_to_match(tmp);
+
+ if (tmp)
+ {
+ set_chunk_parent(tmp, CT_PROTO_WRAP);
+ }
+ // Mark return type (TODO: move to own function)
+ tmp = pc;
+
+ while ((tmp = tmp->GetPrevNcNnlNi())->IsNotNullChunk()) // Issue #2279
+ {
+ if ( !chunk_is_type(tmp)
+ && chunk_is_not_token(tmp, CT_OPERATOR)
+ && chunk_is_not_token(tmp, CT_WORD)
+ && chunk_is_not_token(tmp, CT_ADDR))
+ {
+ break;
+ }
+ set_chunk_parent(tmp, pc->type);
+ 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->level == pc->level)
+ {
+ if ( !did_colon
+ && chunk_is_token(tmp, CT_COLON))
+ {
+ did_colon = true;
+ set_chunk_parent(tmp, pc->type);
+ }
+
+ if (chunk_is_token(tmp, CT_SEMICOLON))
+ {
+ set_chunk_parent(tmp, pc->type);
+ break;
+ }
+ }
+ }
+}