summaryrefslogtreecommitdiffstats
path: root/debian/uncrustify-trinity/uncrustify-trinity-0.78.0/src/tokenize_cleanup.cpp
diff options
context:
space:
mode:
authorMichele Calgaro <michele.calgaro@yahoo.it>2023-11-18 17:53:35 +0900
committerMichele Calgaro <michele.calgaro@yahoo.it>2023-11-19 19:27:29 +0900
commitc0a6f1b84c84749908961579b84513fd9f9d9eac (patch)
treeace7ba60cb031acd3a1f4ff10f7bbc5668fa801f /debian/uncrustify-trinity/uncrustify-trinity-0.78.0/src/tokenize_cleanup.cpp
parent52e5ffe140f0f4402e97936447bc9a606045d2b5 (diff)
downloadextra-dependencies-c0a6f1b84c84749908961579b84513fd9f9d9eac.tar.gz
extra-dependencies-c0a6f1b84c84749908961579b84513fd9f9d9eac.zip
uncrustify-trinity: updated based on upstream version 0.78.0
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
Diffstat (limited to 'debian/uncrustify-trinity/uncrustify-trinity-0.78.0/src/tokenize_cleanup.cpp')
-rw-r--r--debian/uncrustify-trinity/uncrustify-trinity-0.78.0/src/tokenize_cleanup.cpp1223
1 files changed, 1223 insertions, 0 deletions
diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.78.0/src/tokenize_cleanup.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.78.0/src/tokenize_cleanup.cpp
new file mode 100644
index 00000000..831e1aae
--- /dev/null
+++ b/debian/uncrustify-trinity/uncrustify-trinity-0.78.0/src/tokenize_cleanup.cpp
@@ -0,0 +1,1223 @@
+/**
+ * @file tokenize_cleanup.cpp
+ * Looks at simple sequences to refine the chunk types.
+ * Examples:
+ * - change '[' + ']' into '[]'/
+ * - detect "version = 10;" vs "version (xxx) {"
+ *
+ * @author Ben Gardner
+ * @author Guy Maurel 2015, 2022
+ * @license GPL v2+
+ */
+
+#include "tokenize_cleanup.h"
+
+#include "check_template.h"
+#include "combine.h"
+#include "combine_skip.h"
+#include "flag_braced_init_list.h"
+#include "flag_decltype.h"
+#include "keywords.h"
+#include "prototypes.h"
+#include "punctuators.h"
+#include "space.h"
+#include "unc_ctype.h"
+
+
+using namespace uncrustify;
+
+
+/**
+ * Marks ObjC specific chunks in property declaration, by setting
+ * parent types and chunk types.
+ */
+static void cleanup_objc_property(Chunk *start);
+
+
+/**
+ * Marks ObjC specific chunks in property declaration (getter/setter attribute)
+ * Will mark 'test4Setter'and ':' in '@property (setter=test4Setter:, strong) int test4;' as CT_OC_SEL_NAME
+ */
+static void mark_selectors_in_property_with_open_paren(Chunk *open_paren);
+
+
+/**
+ * Marks ObjC specific chunks in property declaration ( attributes)
+ * Changes all the CT_WORD and CT_TYPE to CT_OC_PROPERTY_ATTR
+ */
+static void mark_attributes_in_property_with_open_paren(Chunk *open_paren);
+
+
+void split_off_angle_close(Chunk *pc)
+{
+ const chunk_tag_t *ct = find_punctuator(pc->Text() + 1, cpd.lang_flags);
+
+ if (ct == nullptr)
+ {
+ return;
+ }
+ Chunk nc = *pc;
+
+ pc->Str().resize(1);
+ pc->SetOrigColEnd(pc->GetOrigCol() + 1);
+ pc->SetType(CT_ANGLE_CLOSE);
+
+ nc.SetType(ct->type);
+ nc.Str().pop_front();
+ nc.SetOrigCol(nc.GetOrigCol() + 1);
+ nc.SetColumn(nc.GetColumn() + 1);
+ nc.CopyAndAddAfter(pc);
+}
+
+
+void tokenize_trailing_return_types()
+{
+ // Issue #2330
+ // auto max(int a, int b) -> int;
+ // Issue #2460
+ // auto f01() -> bool;
+ // auto f02() noexcept -> bool;
+ // auto f03() noexcept(true) -> bool;
+ // auto f04() noexcept(false) -> bool;
+ // auto f05() noexcept -> bool = delete;
+ // auto f06() noexcept(true) -> bool = delete;
+ // auto f07() noexcept(false) -> bool = delete;
+ // auto f11() const -> bool;
+ // auto f12() const noexcept -> bool;
+ // auto f13() const noexcept(true) -> bool;
+ // auto f14() const noexcept(false) -> bool;
+ // auto f15() const noexcept -> bool = delete;
+ // auto f16() const noexcept(true) -> bool = delete;
+ // auto f17() const noexcept(false) -> bool = delete;
+ // auto f21() throw() -> bool;
+ // auto f22() throw() -> bool = delete;
+ // auto f23() const throw() -> bool;
+ // auto f24() const throw() -> bool = delete;
+
+ for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl())
+ {
+ char copy[1000];
+ LOG_FMT(LNOTE, "%s(%d): orig line is %zu, orig col is %zu, Text() is '%s'\n",
+ __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->ElidedText(copy));
+
+ if ( pc->Is(CT_MEMBER)
+ && (strcmp(pc->Text(), "->") == 0))
+ {
+ Chunk *tmp = pc->GetPrevNcNnl();
+ Chunk *tmp_2;
+ Chunk *open_paren;
+
+ if (tmp->Is(CT_QUALIFIER))
+ {
+ // auto max(int a, int b) const -> int;
+ // auto f11() const -> bool;
+ tmp = tmp->GetPrevNcNnl();
+ }
+ else if (tmp->Is(CT_NOEXCEPT))
+ {
+ // noexcept is present
+ tmp_2 = tmp->GetPrevNcNnl();
+
+ if (tmp_2->Is(CT_QUALIFIER))
+ {
+ // auto f12() const noexcept -> bool;
+ // auto f15() const noexcept -> bool = delete;
+ tmp = tmp_2->GetPrevNcNnl();
+ }
+ else
+ {
+ // auto f02() noexcept -> bool;
+ // auto f05() noexcept -> bool = delete;
+ tmp = tmp_2;
+ }
+ }
+ else if (tmp->Is(CT_PAREN_CLOSE))
+ {
+ open_paren = tmp->GetPrevType(CT_PAREN_OPEN, tmp->GetLevel());
+ tmp = open_paren->GetPrevNcNnl();
+
+ if (tmp->Is(CT_NOEXCEPT))
+ {
+ // noexcept is present
+ tmp_2 = tmp->GetPrevNcNnl();
+
+ if (tmp_2->Is(CT_QUALIFIER))
+ {
+ // auto f13() const noexcept(true) -> bool;
+ // auto f14() const noexcept(false) -> bool;
+ // auto f16() const noexcept(true) -> bool = delete;
+ // auto f17() const noexcept(false) -> bool = delete;
+ tmp = tmp_2->GetPrevNcNnl();
+ }
+ else
+ {
+ // auto f03() noexcept(true) -> bool;
+ // auto f04() noexcept(false) -> bool;
+ // auto f06() noexcept(true) -> bool = delete;
+ // auto f07() noexcept(false) -> bool = delete;
+ tmp = tmp_2;
+ }
+ }
+ else if (tmp->Is(CT_THROW))
+ {
+ // throw is present
+ tmp_2 = tmp->GetPrevNcNnl();
+
+ if (tmp_2->Is(CT_QUALIFIER))
+ {
+ // auto f23() const throw() -> bool;
+ // auto f24() const throw() -> bool = delete;
+ tmp = tmp_2->GetPrevNcNnl();
+ }
+ else
+ {
+ // auto f21() throw() -> bool;
+ // auto f22() throw() -> bool = delete;
+ tmp = tmp_2;
+ }
+ }
+ else
+ {
+ LOG_FMT(LNOTE, "%s(%d): NOT COVERED\n", __func__, __LINE__);
+ }
+ }
+ else
+ {
+ LOG_FMT(LNOTE, "%s(%d): NOT COVERED\n", __func__, __LINE__);
+ }
+
+ if ( tmp->Is(CT_FPAREN_CLOSE)
+ && ( tmp->GetParentType() == CT_FUNC_PROTO
+ || tmp->GetParentType() == CT_FUNC_DEF))
+ {
+ pc->SetType(CT_TRAILING_RET);
+ LOG_FMT(LNOTE, "%s(%d): set trailing return type for Text() is '%s'\n",
+ __func__, __LINE__, pc->Text()); // Issue #3222
+ // TODO
+ // https://en.cppreference.com/w/cpp/language/function
+ // noptr-declarator ( parameter-list ) cv(optional) ref(optional) except(optional) attr(optional) -> trailing
+ Chunk *next = pc->GetNextNcNnl();
+
+ if (next->Is(CT_DECLTYPE))
+ {
+ // TODO
+ }
+ else if (next->Is(CT_WORD))
+ {
+ next->SetType(CT_TYPE); // Issue #3222
+ next = next->GetNextNcNnl();
+
+ if (next->Is(CT_ARITH))
+ {
+ if (next->GetStr()[0] == '*')
+ {
+ next->SetType(CT_PTR_TYPE);
+ }
+ else if (next->GetStr()[0] == '&') // Issue #3407
+ {
+ next->SetType(CT_BYREF);
+ }
+ }
+ }
+ else
+ {
+ // TODO
+ }
+ }
+ }
+ }
+} // tokenize_trailing_return_types
+
+
+void tokenize_cleanup()
+{
+ LOG_FUNC_ENTRY();
+
+ Chunk *prev = Chunk::NullChunkPtr;
+ Chunk *next;
+ bool in_type_cast = false;
+
+ cpd.unc_stage = unc_stage_e::TOKENIZE_CLEANUP;
+
+ /*
+ * Since [] is expected to be TSQUARE for the 'operator', we need to make
+ * this change in the first pass.
+ */
+ Chunk *pc;
+
+ for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl())
+ {
+ if (pc->Is(CT_SQUARE_OPEN))
+ {
+ next = pc->GetNextNcNnl();
+
+ if (next->Is(CT_SQUARE_CLOSE))
+ {
+ // Change '[' + ']' into '[]'
+ pc->SetType(CT_TSQUARE);
+ pc->Str() = "[]";
+ /*
+ * bug #664: The original m_origColEnd of CT_SQUARE_CLOSE is
+ * stored at m_origColEnd of CT_TSQUARE.
+ * pc->SetOrigColEnd(pc->GetOrigColEnd() + 1);
+ */
+ pc->SetOrigColEnd(next->GetOrigColEnd());
+ Chunk::Delete(next);
+ }
+ }
+
+ if ( pc->Is(CT_SEMICOLON)
+ && pc->TestFlags(PCF_IN_PREPROC)
+ && !pc->GetNextNcNnl(E_Scope::PREPROC))
+ {
+ LOG_FMT(LNOTE, "%s(%d): %s:%zu Detected a macro that ends with a semicolon. Possible failures if used.\n",
+ __func__, __LINE__, cpd.filename.c_str(), pc->GetOrigLine());
+ }
+ }
+
+ // change := to CT_SQL_ASSIGN Issue #527
+ for (pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNextNcNnl())
+ {
+ if (pc->Is(CT_COLON))
+ {
+ next = pc->GetNextNcNnl();
+
+ if (next->Is(CT_ASSIGN))
+ {
+ // Change ':' + '=' into ':='
+ pc->SetType(CT_SQL_ASSIGN);
+ pc->Str() = ":=";
+ pc->SetOrigColEnd(next->GetOrigColEnd());
+ Chunk::Delete(next);
+ }
+ }
+ }
+
+ // We can handle everything else in the second pass
+ pc = Chunk::GetHead();
+ next = pc->GetNextNcNnl();
+
+ while ( pc->IsNotNullChunk()
+ && next->IsNotNullChunk())
+ {
+ if ( pc->Is(CT_DOT)
+ && language_is_set(LANG_ALLC))
+ {
+ pc->SetType(CT_MEMBER);
+ }
+
+ if ( pc->Is(CT_NULLCOND)
+ && language_is_set(LANG_CS))
+ {
+ pc->SetType(CT_MEMBER);
+ }
+
+ // Determine the version stuff (D only)
+ if (pc->Is(CT_D_VERSION))
+ {
+ if (next->Is(CT_PAREN_OPEN))
+ {
+ pc->SetType(CT_D_VERSION_IF);
+ }
+ else
+ {
+ if (next->IsNot(CT_ASSIGN))
+ {
+ LOG_FMT(LERR, "%s(%d): %s:%zu: version: Unexpected token %s\n",
+ __func__, __LINE__, cpd.filename.c_str(), pc->GetOrigLine(), get_token_name(next->GetType()));
+ exit(EX_SOFTWARE);
+ }
+ pc->SetType(CT_WORD);
+ }
+ }
+
+ // Determine the scope stuff (D only)
+ if (pc->Is(CT_D_SCOPE))
+ {
+ if (next->Is(CT_PAREN_OPEN))
+ {
+ pc->SetType(CT_D_SCOPE_IF);
+ }
+ else
+ {
+ pc->SetType(CT_TYPE);
+ }
+ }
+
+ /*
+ * Change CT_BASE before CT_PAREN_OPEN to CT_WORD.
+ * public myclass() : base() {}
+ * -or-
+ * var x = (T)base.y;
+ */
+ if ( pc->Is(CT_BASE)
+ && ( next->Is(CT_PAREN_OPEN)
+ || next->Is(CT_DOT)))
+ {
+ pc->SetType(CT_WORD);
+ }
+
+ if ( pc->Is(CT_ENUM)
+ && ( next->Is(CT_STRUCT)
+ || next->Is(CT_CLASS)))
+ {
+ next->SetType(CT_ENUM_CLASS);
+ }
+ Chunk *next_non_attr = language_is_set(LANG_CPP) ? skip_attribute_next(next) : next;
+
+ /*
+ * Change CT_WORD after CT_ENUM, CT_UNION, CT_STRUCT, or CT_CLASS to CT_TYPE
+ * Change CT_WORD before CT_WORD to CT_TYPE
+ */
+ if (next_non_attr->Is(CT_WORD))
+ {
+ if (pc->IsClassEnumStructOrUnion())
+ {
+ next_non_attr->SetType(CT_TYPE);
+ }
+
+ if (pc->Is(CT_WORD))
+ {
+ pc->SetType(CT_TYPE);
+ }
+ }
+
+ /*
+ * change extern to qualifier if extern isn't followed by a string or
+ * an open parenthesis
+ */
+ if (pc->Is(CT_EXTERN))
+ {
+ if (next->Is(CT_STRING))
+ {
+ // Probably 'extern "C"'
+ }
+ else if (next->Is(CT_PAREN_OPEN))
+ {
+ // Probably 'extern (C)'
+ }
+ else
+ {
+ // Something else followed by a open brace
+ Chunk *tmp = next->GetNextNcNnl();
+
+ if ( tmp->IsNullChunk()
+ || tmp->IsNot(CT_BRACE_OPEN))
+ {
+ pc->SetType(CT_QUALIFIER);
+ }
+ }
+ }
+
+ /*
+ * Change CT_STAR to CT_PTR_TYPE if preceded by
+ * CT_TYPE, CT_QUALIFIER, or CT_PTR_TYPE
+ * or by a
+ * CT_WORD which is preceded by CT_DC_MEMBER: '::aaa *b'
+ */
+ if ( (next->Is(CT_STAR))
+ || ( language_is_set(LANG_CPP)
+ && (next->Is(CT_CARET)))
+ || ( language_is_set(LANG_CS | LANG_VALA)
+ && (next->Is(CT_QUESTION))
+ && (strcmp(pc->Text(), "null") != 0)))
+ {
+ if ( pc->Is(CT_TYPE)
+ || pc->Is(CT_QUALIFIER)
+ || pc->Is(CT_PTR_TYPE))
+ {
+ next->SetType(CT_PTR_TYPE);
+ }
+ }
+
+ if ( pc->Is(CT_TYPE_CAST)
+ && next->Is(CT_ANGLE_OPEN))
+ {
+ next->SetParentType(CT_TYPE_CAST);
+ in_type_cast = true;
+ }
+
+ if (pc->Is(CT_DECLTYPE))
+ {
+ flag_cpp_decltype(pc);
+ }
+
+ // Change angle open/close to CT_COMPARE, if not a template thingy
+ if ( pc->Is(CT_ANGLE_OPEN)
+ && pc->GetParentType() != CT_TYPE_CAST)
+ {
+ /*
+ * pretty much all languages except C use <> for something other than
+ * comparisons. "#include<xxx>" is handled elsewhere.
+ */
+ if (language_is_set(LANG_OC | LANG_CPP | LANG_CS | LANG_JAVA | LANG_VALA))
+ {
+ // bug #663
+ check_template(pc, in_type_cast);
+ }
+ else
+ {
+ // convert CT_ANGLE_OPEN to CT_COMPARE
+ pc->SetType(CT_COMPARE);
+ }
+ }
+
+ if ( pc->Is(CT_ANGLE_CLOSE)
+ && pc->GetParentType() != CT_TEMPLATE)
+ {
+ if (in_type_cast)
+ {
+ in_type_cast = false;
+ pc->SetParentType(CT_TYPE_CAST);
+ }
+ else
+ {
+ next = handle_double_angle_close(pc);
+ }
+ }
+
+ if (language_is_set(LANG_D))
+ {
+ // Check for the D string concat symbol '~'
+ if ( pc->Is(CT_INV)
+ && ( prev->Is(CT_STRING)
+ || prev->Is(CT_WORD)
+ || next->Is(CT_STRING)))
+ {
+ pc->SetType(CT_CONCAT);
+ }
+
+ // Check for the D template symbol '!' (word + '!' + word or '(')
+ if ( pc->Is(CT_NOT)
+ && prev->Is(CT_WORD)
+ && ( next->Is(CT_PAREN_OPEN)
+ || next->Is(CT_WORD)
+ || next->Is(CT_TYPE)
+ || next->Is(CT_NUMBER)
+ || next->Is(CT_NUMBER_FP)
+ || next->Is(CT_STRING)
+ || next->Is(CT_STRING_MULTI)))
+ {
+ pc->SetType(CT_D_TEMPLATE);
+ }
+
+ // handle "version(unittest) { }" vs "unittest { }"
+ if ( pc->Is(CT_UNITTEST)
+ && prev->Is(CT_PAREN_OPEN))
+ {
+ pc->SetType(CT_WORD);
+ }
+
+ // handle 'static if' and merge the tokens
+ if ( pc->Is(CT_IF)
+ && prev->IsString("static"))
+ {
+ // delete PREV and merge with IF
+ pc->Str().insert(0, ' ');
+ pc->Str().insert(0, prev->GetStr());
+ pc->SetOrigCol(prev->GetOrigCol());
+ pc->SetOrigLine(prev->GetOrigLine());
+ Chunk *to_be_deleted = prev;
+ prev = prev->GetPrevNcNnl();
+
+ if (prev->IsNotNullChunk())
+ {
+ Chunk::Delete(to_be_deleted);
+ }
+ }
+ }
+
+ if (language_is_set(LANG_CPP))
+ {
+ // Change Word before '::' into a type
+ if ( pc->Is(CT_WORD)
+ && next->Is(CT_DC_MEMBER))
+ {
+ prev = pc->GetPrev();
+
+ if (prev->IsNullChunk()) // Issue #3010
+ {
+ pc->SetType(CT_TYPE);
+ }
+ else
+ {
+ if (prev->Is(CT_COLON))
+ {
+ // nothing to do
+ }
+ else
+ {
+ pc->SetType(CT_TYPE);
+ }
+ }
+ }
+
+ // Set parent type for 'if constexpr'
+ if ( prev->Is(CT_IF)
+ && pc->Is(CT_QUALIFIER)
+ && pc->IsString("constexpr"))
+ {
+ pc->SetType(CT_CONSTEXPR);
+ }
+ }
+
+ // Change get/set to CT_WORD if not followed by a brace open
+ if ( pc->Is(CT_GETSET)
+ && next->IsNot(CT_BRACE_OPEN))
+ {
+ if ( next->Is(CT_SEMICOLON)
+ && ( prev->Is(CT_BRACE_CLOSE)
+ || prev->Is(CT_BRACE_OPEN)
+ || prev->Is(CT_SEMICOLON)))
+ {
+ pc->SetType(CT_GETSET_EMPTY);
+ next->SetParentType(CT_GETSET);
+ }
+ else
+ {
+ pc->SetType(CT_WORD);
+ }
+ }
+
+ /*
+ * Interface is only a keyword in MS land if followed by 'class' or 'struct'
+ * likewise, 'class' may be a member name in Java.
+ */
+ if ( pc->Is(CT_CLASS)
+ && !CharTable::IsKw1(next->GetStr()[0]))
+ {
+ if ( next->IsNot(CT_DC_MEMBER)
+ && next->IsNot(CT_ATTRIBUTE)) // Issue #2570
+ {
+ pc->SetType(CT_WORD);
+ }
+ else if ( prev->Is(CT_DC_MEMBER)
+ || prev->Is(CT_TYPE))
+ {
+ pc->SetType(CT_TYPE);
+ }
+ else if (next->Is(CT_DC_MEMBER))
+ {
+ Chunk *next2 = next->GetNextNcNnlNet();
+
+ if ( next2->Is(CT_INV) // CT_INV hasn't turned into CT_DESTRUCTOR just yet
+ || ( next2->Is(CT_CLASS) // constructor isn't turned into CT_FUNC* just yet
+ && !strcmp(pc->Text(), next2->Text())))
+ {
+ pc->SetType(CT_TYPE);
+ }
+ }
+ }
+
+ /*
+ * Change item after operator (>=, ==, etc) to a CT_OPERATOR_VAL
+ * Usually the next item is part of the operator.
+ * In a few cases the next few tokens are part of it:
+ * operator + - common case
+ * operator >> - need to combine '>' and '>'
+ * operator ()
+ * operator [] - already converted to TSQUARE
+ * operator new []
+ * operator delete []
+ * operator const char *
+ * operator const B&
+ * operator std::allocator<U>
+ *
+ * In all cases except the last, this will put the entire operator value
+ * in one chunk.
+ */
+ if (pc->Is(CT_OPERATOR))
+ {
+ Chunk *tmp2 = next->GetNext();
+
+ // Handle special case of () operator -- [] already handled
+ if (next->Is(CT_PAREN_OPEN))
+ {
+ Chunk *tmp = next->GetNext();
+
+ if (tmp->Is(CT_PAREN_CLOSE))
+ {
+ next->Str() = "()";
+ next->SetType(CT_OPERATOR_VAL);
+ Chunk::Delete(tmp);
+ next->SetOrigColEnd(next->GetOrigColEnd() + 1);
+ }
+ }
+ else if ( next->Is(CT_ANGLE_CLOSE)
+ && tmp2->Is(CT_ANGLE_CLOSE)
+ && tmp2->GetOrigCol() == next->GetOrigColEnd())
+ {
+ next->Str().append('>');
+ next->SetOrigColEnd(next->GetOrigColEnd() + 1);
+ next->SetType(CT_OPERATOR_VAL);
+ Chunk::Delete(tmp2);
+ }
+ else if (next->TestFlags(PCF_PUNCTUATOR))
+ {
+ next->SetType(CT_OPERATOR_VAL);
+ }
+ else
+ {
+ next->SetType(CT_TYPE);
+
+ /*
+ * Replace next with a collection of all tokens that are part of
+ * the type.
+ */
+ tmp2 = next;
+ Chunk *tmp;
+
+ while ((tmp = tmp2->GetNext())->IsNotNullChunk())
+ {
+ if ( tmp->IsNot(CT_WORD)
+ && tmp->IsNot(CT_TYPE)
+ && tmp->IsNot(CT_QUALIFIER)
+ && tmp->IsNot(CT_STAR)
+ && tmp->IsNot(CT_CARET)
+ && tmp->IsNot(CT_AMP)
+ && tmp->IsNot(CT_TSQUARE))
+ {
+ break;
+ }
+ // Change tmp into a type so that space_needed() works right
+ make_type(tmp);
+ size_t num_sp = space_needed(tmp2, tmp);
+
+ while (num_sp-- > 0)
+ {
+ next->Str().append(" ");
+ }
+ next->Str().append(tmp->GetStr());
+ tmp2 = tmp;
+ }
+
+ while ((tmp2 = next->GetNext()) != tmp)
+ {
+ Chunk::Delete(tmp2);
+ }
+ next->SetType(CT_OPERATOR_VAL);
+
+ next->SetOrigColEnd(next->GetOrigCol() + next->Len());
+ }
+ next->SetParentType(CT_OPERATOR);
+
+ LOG_FMT(LOPERATOR, "%s(%d): %zu:%zu operator '%s'\n",
+ __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), next->Text());
+ }
+
+ // Change private, public, protected into either a qualifier or label
+ if (pc->Is(CT_ACCESS))
+ {
+ // Handle Qt slots - maybe should just check for a CT_WORD?
+ if ( next->IsString("slots")
+ || next->IsString("Q_SLOTS"))
+ {
+ Chunk *tmp = next->GetNext();
+
+ if (tmp->Is(CT_COLON))
+ {
+ next = tmp;
+ }
+ }
+
+ if (next->Is(CT_COLON))
+ {
+ next->SetType(CT_ACCESS_COLON);
+ Chunk *tmp;
+
+ if ((tmp = next->GetNextNcNnl())->IsNotNullChunk())
+ {
+ tmp->SetFlagBits(PCF_STMT_START | PCF_EXPR_START);
+ log_ruleStart("start statementi/ expression", tmp);
+ }
+ }
+ else
+ {
+ pc->SetType(( pc->IsString("signals")
+ || pc->IsString("Q_SIGNALS"))
+ ? CT_WORD : CT_QUALIFIER);
+ }
+ }
+
+ // Look for <newline> 'EXEC' 'SQL'
+ if ( ( pc->IsString("EXEC", false)
+ && next->IsString("SQL", false))
+ || ( (*pc->GetStr().c_str() == '$')
+ && pc->IsNot(CT_SQL_WORD)
+ /* but avoid breaking tokenization for C# 6 interpolated strings. */
+ && ( !language_is_set(LANG_CS)
+ || ( pc->Is(CT_STRING)
+ && (!pc->GetStr().startswith("$\""))
+ && (!pc->GetStr().startswith("$@\""))))))
+ {
+ Chunk *tmp = pc->GetPrev();
+
+ if (tmp->IsNewline())
+ {
+ if (*pc->GetStr().c_str() == '$')
+ {
+ pc->SetType(CT_SQL_EXEC);
+
+ if (pc->Len() > 1)
+ {
+ // SPLIT OFF '$'
+ Chunk nc;
+
+ nc = *pc;
+ pc->Str().resize(1);
+ pc->SetOrigColEnd(pc->GetOrigCol() + 1);
+
+ nc.SetType(CT_SQL_WORD);
+ nc.Str().pop_front();
+ nc.SetOrigCol(nc.GetOrigCol() + 1);
+ nc.SetColumn(nc.GetColumn() + 1);
+ nc.CopyAndAddAfter(pc);
+
+ next = pc->GetNext();
+ }
+ }
+ tmp = next->GetNext();
+
+ if (tmp->IsString("BEGIN", false))
+ {
+ pc->SetType(CT_SQL_BEGIN);
+ }
+ else if (tmp->IsString("END", false))
+ {
+ pc->SetType(CT_SQL_END);
+ }
+ else
+ {
+ pc->SetType(CT_SQL_EXEC);
+ }
+
+ // Change words into CT_SQL_WORD until CT_SEMICOLON
+ while (tmp->IsNotNullChunk())
+ {
+ if (tmp->Is(CT_SEMICOLON))
+ {
+ break;
+ }
+
+ if ( (tmp->Len() > 0)
+ && ( unc_isalpha(*tmp->GetStr().c_str())
+ || (*tmp->GetStr().c_str() == '$')))
+ {
+ tmp->SetType(CT_SQL_WORD);
+ }
+ tmp = tmp->GetNextNcNnl();
+ }
+ }
+ }
+
+ // handle MS abomination 'for each'
+ if ( pc->Is(CT_FOR)
+ && next->IsString("each")
+ && (next == pc->GetNext()))
+ {
+ // merge the two with a space between
+ pc->Str().append(' ');
+ pc->Str() += next->GetStr();
+ pc->SetOrigColEnd(next->GetOrigColEnd());
+ Chunk::Delete(next);
+ next = pc->GetNextNcNnl();
+
+ // label the 'in'
+ if (next->Is(CT_PAREN_OPEN))
+ {
+ Chunk *tmp = next->GetNextNcNnl();
+
+ while ( tmp->IsNotNullChunk()
+ && tmp->IsNot(CT_PAREN_CLOSE))
+ {
+ if (tmp->IsString("in"))
+ {
+ tmp->SetType(CT_IN);
+ break;
+ }
+ tmp = tmp->GetNextNcNnl();
+ }
+ }
+ }
+
+ /*
+ * ObjectiveC allows keywords to be used as identifiers in some situations
+ * This is a dirty hack to allow some of the more common situations.
+ */
+ if (language_is_set(LANG_OC))
+ {
+ if ( ( pc->Is(CT_IF)
+ || pc->Is(CT_FOR)
+ || pc->Is(CT_WHILE))
+ && !next->Is(CT_PAREN_OPEN))
+ {
+ pc->SetType(CT_WORD);
+ }
+
+ if ( pc->Is(CT_DO)
+ && ( prev->Is(CT_MINUS)
+ || next->Is(CT_SQUARE_CLOSE)))
+ {
+ pc->SetType(CT_WORD);
+ }
+
+ // Fix self keyword back to word when mixing c++/objective-c
+ if ( pc->Is(CT_THIS)
+ && !strcmp(pc->Text(), "self")
+ && ( next->Is(CT_COMMA)
+ || next->Is(CT_PAREN_CLOSE)))
+ {
+ pc->SetType(CT_WORD);
+ }
+
+ // Fix self keyword back to word when mixing c++/objective-c
+ if ( pc->Is(CT_THIS)
+ && !strcmp(pc->Text(), "self")
+ && ( next->Is(CT_COMMA)
+ || next->Is(CT_PAREN_CLOSE)))
+ {
+ pc->SetType(CT_WORD);
+ }
+ }
+
+ // Vala allows keywords to be used as identifiers
+ if (language_is_set(LANG_VALA))
+ {
+ if ( find_keyword_type(pc->Text(), pc->Len()) != CT_WORD
+ && ( prev->Is(CT_DOT)
+ || next->Is(CT_DOT)
+ || prev->Is(CT_MEMBER)
+ || next->Is(CT_MEMBER)
+ || prev->Is(CT_TYPE)))
+ {
+ pc->SetType(CT_WORD);
+ }
+ }
+
+ // Another hack to clean up more keyword abuse
+ if ( pc->Is(CT_CLASS)
+ && ( prev->Is(CT_DOT)
+ || next->Is(CT_DOT)
+ || prev->Is(CT_MEMBER) // Issue #3031
+ || next->Is(CT_MEMBER)))
+ {
+ pc->SetType(CT_WORD);
+ }
+
+ // Detect Objective C class name
+ if ( pc->Is(CT_OC_IMPL)
+ || pc->Is(CT_OC_INTF)
+ || pc->Is(CT_OC_PROTOCOL))
+ {
+ if (next->IsNot(CT_PAREN_OPEN))
+ {
+ next->SetType(CT_OC_CLASS);
+ }
+ next->SetParentType(pc->GetType());
+
+ Chunk *tmp = next->GetNextNcNnl();
+
+ if (tmp->IsNotNullChunk())
+ {
+ tmp->SetFlagBits(PCF_STMT_START | PCF_EXPR_START);
+ log_ruleStart("start statementi/ expression", tmp);
+ }
+ tmp = pc->GetNextType(CT_OC_END, pc->GetLevel());
+
+ if (tmp->IsNotNullChunk())
+ {
+ tmp->SetParentType(pc->GetType());
+ }
+ }
+
+ if (pc->Is(CT_OC_INTF))
+ {
+ Chunk *tmp = pc->GetNextNcNnl(E_Scope::PREPROC);
+
+ while ( tmp->IsNotNullChunk()
+ && tmp->IsNot(CT_OC_END))
+ {
+ if (get_token_pattern_class(tmp->GetType()) != pattern_class_e::NONE)
+ {
+ LOG_FMT(LOBJCWORD, "%s(%d): @interface %zu:%zu change '%s' (%s) to CT_WORD\n",
+ __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), tmp->Text(),
+ get_token_name(tmp->GetType()));
+ tmp->SetType(CT_WORD);
+ }
+ tmp = tmp->GetNextNcNnl(E_Scope::PREPROC);
+ }
+ }
+
+ /*
+ * Detect Objective-C categories and class extensions:
+ * @interface ClassName (CategoryName)
+ * @implementation ClassName (CategoryName)
+ * @interface ClassName ()
+ * @implementation ClassName ()
+ */
+ if ( ( pc->GetParentType() == CT_OC_IMPL
+ || pc->GetParentType() == CT_OC_INTF
+ || pc->Is(CT_OC_CLASS))
+ && next->Is(CT_PAREN_OPEN))
+ {
+ next->SetParentType(pc->GetParentType());
+
+ Chunk *tmp = next->GetNext();
+
+ if ( tmp->IsNotNullChunk()
+ && tmp->GetNext()->IsNotNullChunk())
+ {
+ if (tmp->Is(CT_PAREN_CLOSE))
+ {
+ //tmp->SetType(CT_OC_CLASS_EXT);
+ tmp->SetParentType(pc->GetParentType());
+ }
+ else
+ {
+ tmp->SetType(CT_OC_CATEGORY);
+ tmp->SetParentType(pc->GetParentType());
+ }
+ }
+ tmp = pc->GetNextType(CT_PAREN_CLOSE, pc->GetLevel());
+
+ if (tmp->IsNotNullChunk())
+ {
+ tmp->SetParentType(pc->GetParentType());
+ }
+ }
+
+ /*
+ * Detect Objective C @property:
+ * @property NSString *stringProperty;
+ * @property(nonatomic, retain) NSMutableDictionary *shareWith;
+ */
+ if (pc->Is(CT_OC_PROPERTY))
+ {
+ if (next->IsNot(CT_PAREN_OPEN))
+ {
+ next->SetFlagBits(PCF_STMT_START | PCF_EXPR_START);
+ log_ruleStart("start statement/ expression", next);
+ }
+ else
+ {
+ cleanup_objc_property(pc);
+ }
+ }
+
+ /*
+ * Detect Objective C @selector:
+ * @selector(msgNameWithNoArg)
+ * @selector(msgNameWith1Arg:)
+ * @selector(msgNameWith2Args:arg2Name:)
+ */
+ if ( pc->Is(CT_OC_SEL)
+ && next->Is(CT_PAREN_OPEN))
+ {
+ next->SetParentType(pc->GetType());
+
+ Chunk *tmp = next->GetNext();
+
+ if (tmp->IsNotNullChunk())
+ {
+ tmp->SetType(CT_OC_SEL_NAME);
+ tmp->SetParentType(pc->GetType());
+
+ while ((tmp = tmp->GetNextNcNnl())->IsNotNullChunk())
+ {
+ if (tmp->Is(CT_PAREN_CLOSE))
+ {
+ tmp->SetParentType(CT_OC_SEL);
+ break;
+ }
+ tmp->SetType(CT_OC_SEL_NAME);
+ tmp->SetParentType(pc->GetType());
+ }
+ }
+ }
+
+ // Handle special preprocessor junk
+ if (pc->Is(CT_PREPROC))
+ {
+ pc->SetParentType(next->GetType());
+ }
+
+ // Detect "pragma region" and "pragma endregion"
+ if ( pc->Is(CT_PP_PRAGMA)
+ && next->Is(CT_PREPROC_BODY))
+ {
+ if ( (strncmp(next->GetStr().c_str(), "region", 6) == 0)
+ || (strncmp(next->GetStr().c_str(), "endregion", 9) == 0))
+ // TODO: probably better use strncmp
+ {
+ pc->SetType((*next->GetStr().c_str() == 'r') ? CT_PP_REGION : CT_PP_ENDREGION);
+
+ prev->SetParentType(pc->GetType());
+ }
+ }
+
+ // Change 'default(' into a sizeof-like statement
+ if ( language_is_set(LANG_CS)
+ && pc->Is(CT_DEFAULT)
+ && next->Is(CT_PAREN_OPEN))
+ {
+ pc->SetType(CT_SIZEOF);
+ }
+
+ if ( pc->Is(CT_UNSAFE)
+ && next->IsNot(CT_BRACE_OPEN))
+ {
+ pc->SetType(CT_QUALIFIER);
+ }
+
+ if ( ( pc->Is(CT_USING)
+ || ( pc->Is(CT_TRY)
+ && language_is_set(LANG_JAVA)))
+ && next->Is(CT_PAREN_OPEN))
+ {
+ pc->SetType(CT_USING_STMT);
+ }
+
+ // Add minimal support for C++0x rvalue references
+ if ( pc->Is(CT_BOOL)
+ && language_is_set(LANG_CPP)
+ && pc->IsString("&&"))
+ {
+ if (prev->Is(CT_TYPE))
+ {
+ // Issue # 1002
+ if (!pc->TestFlags(PCF_IN_TEMPLATE))
+ {
+ pc->SetType(CT_BYREF);
+ }
+ }
+ }
+
+ /*
+ * HACK: treat try followed by a colon as a qualifier to handle this:
+ * A::A(int) try : B() { } catch (...) { }
+ */
+ if ( pc->Is(CT_TRY)
+ && pc->IsString("try")
+ && next->Is(CT_COLON))
+ {
+ pc->SetType(CT_QUALIFIER);
+ }
+
+ /*
+ * If Java's 'synchronized' is in a method declaration, it should be
+ * a qualifier.
+ */
+ if ( language_is_set(LANG_JAVA)
+ && pc->Is(CT_SYNCHRONIZED)
+ && next->IsNot(CT_PAREN_OPEN))
+ {
+ pc->SetType(CT_QUALIFIER);
+ }
+
+ // change CT_DC_MEMBER + CT_FOR into CT_DC_MEMBER + CT_FUNC_CALL
+ if ( pc->Is(CT_FOR)
+ && pc->GetPrev()->Is(CT_DC_MEMBER))
+ {
+ pc->SetType(CT_FUNC_CALL);
+ }
+ // TODO: determine other stuff here
+
+ prev = pc;
+ pc = next;
+ next = pc->GetNextNcNnl();
+ }
+} // tokenize_cleanup
+
+
+static void cleanup_objc_property(Chunk *start)
+{
+ assert(start->Is(CT_OC_PROPERTY));
+
+ Chunk *open_paren = start->GetNextType(CT_PAREN_OPEN, start->GetLevel());
+
+ if (open_paren->IsNullChunk())
+ {
+ LOG_FMT(LTEMPL, "%s(%d): Property is not followed by opening paren\n", __func__, __LINE__);
+ return;
+ }
+ open_paren->SetParentType(start->GetType());
+
+ Chunk *tmp = start->GetNextType(CT_PAREN_CLOSE, start->GetLevel());
+
+ if (tmp->IsNotNullChunk())
+ {
+ tmp->SetParentType(start->GetType());
+ tmp = tmp->GetNextNcNnl();
+
+ if (tmp->IsNotNullChunk())
+ {
+ tmp->SetFlagBits(PCF_STMT_START | PCF_EXPR_START);
+ log_ruleStart("start statement/ expression", tmp);
+
+ tmp = tmp->GetNextType(CT_SEMICOLON, start->GetLevel());
+
+ if (tmp->IsNotNullChunk())
+ {
+ tmp->SetParentType(start->GetType());
+ }
+ }
+ }
+ mark_selectors_in_property_with_open_paren(open_paren);
+ mark_attributes_in_property_with_open_paren(open_paren);
+}
+
+
+static void mark_selectors_in_property_with_open_paren(Chunk *open_paren)
+{
+ assert(open_paren->Is(CT_PAREN_OPEN));
+
+ Chunk *tmp = open_paren;
+
+ while (tmp->IsNot(CT_PAREN_CLOSE))
+ {
+ if ( tmp->Is(CT_WORD)
+ && ( tmp->IsString("setter")
+ || tmp->IsString("getter")))
+ {
+ tmp = tmp->GetNext();
+
+ while ( tmp->IsNotNullChunk()
+ && tmp->IsNot(CT_COMMA)
+ && tmp->IsNot(CT_PAREN_CLOSE))
+ {
+ if ( tmp->Is(CT_WORD)
+ || tmp->IsString(":"))
+ {
+ tmp->SetType(CT_OC_SEL_NAME);
+ }
+ tmp = tmp->GetNext();
+ }
+ }
+ else
+ {
+ tmp = tmp->GetNext();
+ }
+ }
+}
+
+
+static void mark_attributes_in_property_with_open_paren(Chunk *open_paren)
+{
+ assert(open_paren->Is(CT_PAREN_OPEN));
+
+ Chunk *tmp = open_paren;
+
+ while (tmp->IsNot(CT_PAREN_CLOSE))
+ {
+ Chunk *next = tmp->GetNext();
+
+ if ( ( tmp->Is(CT_COMMA)
+ || tmp->Is(CT_PAREN_OPEN))
+ && ( next->Is(CT_WORD)
+ || next->Is(CT_TYPE)))
+ {
+ next->SetType(CT_OC_PROPERTY_ATTR);
+ }
+ tmp = next;
+ }
+}