You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
916 lines
21 KiB
916 lines
21 KiB
/**
|
|
* @file chunk.cpp
|
|
* Manages and navigates the list of chunks.
|
|
*
|
|
* @author Ben Gardner
|
|
* @license GPL v2+
|
|
*/
|
|
|
|
#include "chunk.h"
|
|
|
|
#include "ListManager.h"
|
|
#include "prototypes.h"
|
|
#include "space.h"
|
|
|
|
static ChunkListManager gChunkList; // global chunk list
|
|
|
|
|
|
/*
|
|
* Chunk class methods
|
|
*/
|
|
|
|
// Null Chunk
|
|
Chunk Chunk::NullChunk(true);
|
|
Chunk *const Chunk::NullChunkPtr(&Chunk::NullChunk);
|
|
|
|
|
|
void Chunk::CopyFrom(const Chunk &o)
|
|
{
|
|
m_type = o.m_type;
|
|
m_parentType = o.m_parentType;
|
|
m_origLine = o.m_origLine;
|
|
m_origCol = o.m_origCol;
|
|
m_origColEnd = o.m_origColEnd;
|
|
m_origPrevSp = o.m_origPrevSp;
|
|
m_column = o.m_column;
|
|
m_columnIndent = o.m_columnIndent;
|
|
m_nlCount = o.m_nlCount;
|
|
m_nlColumn = o.m_nlColumn;
|
|
m_level = o.m_level;
|
|
m_braceLevel = o.m_braceLevel;
|
|
m_ppLevel = o.m_ppLevel;
|
|
m_afterTab = o.m_afterTab;
|
|
|
|
m_flags = o.m_flags;
|
|
m_alignmentData = o.m_alignmentData;
|
|
m_indentationData = o.m_indentationData;
|
|
|
|
m_next = Chunk::NullChunkPtr;
|
|
m_prev = Chunk::NullChunkPtr;
|
|
m_parent = Chunk::NullChunkPtr;
|
|
|
|
m_str = o.m_str;
|
|
m_trackingList = o.m_trackingList;
|
|
}
|
|
|
|
|
|
void Chunk::Reset()
|
|
{
|
|
m_type = CT_NONE;
|
|
m_parentType = CT_NONE;
|
|
m_origLine = 0;
|
|
m_origCol = 0;
|
|
m_origColEnd = 0;
|
|
m_origPrevSp = 0;
|
|
m_column = 0;
|
|
m_columnIndent = 0;
|
|
m_nlCount = 0;
|
|
m_nlColumn = 0;
|
|
m_level = 0;
|
|
m_braceLevel = 0;
|
|
m_ppLevel = 999; // use a big value to find some errors
|
|
m_afterTab = false;
|
|
|
|
m_flags = PCF_NONE;
|
|
memset(&m_alignmentData, 0, sizeof(m_alignmentData));
|
|
m_alignmentData.next = NullChunkPtr;
|
|
m_alignmentData.start = NullChunkPtr;
|
|
m_alignmentData.ref = NullChunkPtr;
|
|
memset(&m_indentationData, 0, sizeof(m_indentationData));
|
|
|
|
m_next = Chunk::NullChunkPtr;
|
|
m_prev = Chunk::NullChunkPtr;
|
|
m_parent = Chunk::NullChunkPtr;
|
|
|
|
// for debugging purpose only
|
|
m_str.clear();
|
|
m_trackingList = nullptr;
|
|
}
|
|
|
|
|
|
const char *Chunk::ElidedText(char *for_the_copy) const
|
|
{
|
|
const char *test_it = Text();
|
|
size_t test_it_length = strlen(test_it);
|
|
|
|
size_t truncate_value = uncrustify::options::debug_truncate();
|
|
|
|
if (truncate_value != 0)
|
|
{
|
|
if (test_it_length > truncate_value)
|
|
{
|
|
memset(for_the_copy, 0, 1000);
|
|
|
|
if (test_it_length < truncate_value + 30)
|
|
{
|
|
strncpy(for_the_copy, test_it, truncate_value - 30);
|
|
for_the_copy[truncate_value - 30] = 0;
|
|
}
|
|
else
|
|
{
|
|
strncpy(for_the_copy, test_it, truncate_value);
|
|
for_the_copy[truncate_value] = 0;
|
|
}
|
|
char *message = strcat(for_the_copy, " ... <The string is truncated>");
|
|
|
|
return(message);
|
|
}
|
|
else
|
|
{
|
|
return(test_it);
|
|
}
|
|
}
|
|
return(test_it);
|
|
}
|
|
|
|
|
|
Chunk *Chunk::GetNext(const E_Scope scope) const
|
|
{
|
|
if (scope == E_Scope::ALL)
|
|
{
|
|
return(m_next);
|
|
}
|
|
Chunk *pc = m_next;
|
|
|
|
if (TestFlags(PCF_IN_PREPROC))
|
|
{
|
|
// If in a preproc, return a null chunk if trying to leave
|
|
if (!pc->TestFlags(PCF_IN_PREPROC))
|
|
{
|
|
return(NullChunkPtr);
|
|
}
|
|
return(pc);
|
|
}
|
|
|
|
// Not in a preproc, skip any preproc
|
|
while ( pc->IsNotNullChunk()
|
|
&& pc->TestFlags(PCF_IN_PREPROC))
|
|
{
|
|
pc = pc->m_next;
|
|
}
|
|
return(pc);
|
|
} // Chunk::GetNext
|
|
|
|
|
|
Chunk *Chunk::GetPrev(const E_Scope scope) const
|
|
{
|
|
if (scope == E_Scope::ALL)
|
|
{
|
|
return(m_prev);
|
|
}
|
|
Chunk *pc = m_prev;
|
|
|
|
if (TestFlags(PCF_IN_PREPROC))
|
|
{
|
|
// If in a preproc, return a null chunk if trying to leave
|
|
if (!pc->TestFlags(PCF_IN_PREPROC))
|
|
{
|
|
return(NullChunkPtr);
|
|
}
|
|
return(pc);
|
|
}
|
|
|
|
// Not in a preproc, skip any preproc
|
|
while ( pc->IsNotNullChunk()
|
|
&& pc->TestFlags(PCF_IN_PREPROC))
|
|
{
|
|
pc = pc->m_prev;
|
|
}
|
|
return(pc);
|
|
} // Chunk::GetPrev
|
|
|
|
|
|
static void chunk_log(Chunk *pc, const char *text);
|
|
|
|
|
|
Chunk *Chunk::GetHead()
|
|
{
|
|
return(gChunkList.GetHead());
|
|
}
|
|
|
|
|
|
Chunk *Chunk::GetTail()
|
|
{
|
|
return(gChunkList.GetTail());
|
|
}
|
|
|
|
|
|
Chunk::T_SearchFnPtr Chunk::GetSearchFn(const E_Direction dir)
|
|
{
|
|
return((dir == E_Direction::FORWARD) ? &Chunk::GetNext : &Chunk::GetPrev);
|
|
}
|
|
|
|
|
|
Chunk *Chunk::Search(const T_CheckFnPtr checkFn, const E_Scope scope,
|
|
const E_Direction dir, const bool cond) const
|
|
{
|
|
T_SearchFnPtr searchFnPtr = GetSearchFn(dir);
|
|
Chunk *pc = const_cast<Chunk *>(this);
|
|
|
|
do // loop over the chunk list
|
|
{
|
|
pc = (pc->*searchFnPtr)(scope); // in either direction while
|
|
} while ( pc->IsNotNullChunk() // the end of the list was not reached yet
|
|
&& ((pc->*checkFn)() != cond)); // and the demanded chunk was not found either
|
|
|
|
return(pc); // the latest chunk is the searched one
|
|
}
|
|
|
|
|
|
bool Chunk::IsOnSameLine(const Chunk *end) const
|
|
{
|
|
if (IsNullChunk())
|
|
{
|
|
return(false);
|
|
}
|
|
Chunk *tmp = GetNext();
|
|
|
|
while ( tmp->IsNotNullChunk()
|
|
&& tmp != end)
|
|
{
|
|
if (tmp->Is(CT_NEWLINE))
|
|
{
|
|
return(false);
|
|
}
|
|
tmp = tmp->GetNext();
|
|
}
|
|
return(true);
|
|
}
|
|
|
|
|
|
Chunk *Chunk::SearchTypeLevel(const E_Token type, const E_Scope scope,
|
|
const E_Direction dir, const int level) const
|
|
{
|
|
T_SearchFnPtr searchFnPtr = GetSearchFn(dir);
|
|
Chunk *pc = const_cast<Chunk *>(this);
|
|
|
|
do // loop over the chunk list
|
|
{
|
|
pc = (pc->*searchFnPtr)(scope); // in either direction while
|
|
} while ( pc->IsNotNullChunk() // the end of the list was not reached yet
|
|
&& (!pc->IsTypeAndLevel(type, level))); // and the chunk was not found either
|
|
|
|
return(pc); // the latest chunk is the searched one
|
|
}
|
|
|
|
|
|
Chunk *Chunk::SearchStringLevel(const char *str, const size_t len, int level,
|
|
const E_Scope scope, const E_Direction dir) const
|
|
{
|
|
T_SearchFnPtr searchFnPtr = GetSearchFn(dir);
|
|
Chunk *pc = const_cast<Chunk *>(this);
|
|
|
|
do // loop over the chunk list
|
|
{
|
|
pc = (pc->*searchFnPtr)(scope); // in either direction while
|
|
} while ( pc->IsNotNullChunk() // the end of the list was not reached yet
|
|
&& !pc->IsStringAndLevel(str, len, true, level)); // and the demanded chunk was not found either
|
|
|
|
return(pc); // the latest chunk is the searched one
|
|
}
|
|
|
|
|
|
Chunk *Chunk::SearchPpa(const T_CheckFnPtr checkFn, const bool cond) const
|
|
{
|
|
if (!TestFlags(PCF_IN_PREPROC))
|
|
{
|
|
// if not in preprocessor, do a regular search
|
|
return(Search(checkFn, E_Scope::ALL, E_Direction::FORWARD, cond));
|
|
}
|
|
Chunk *pc = GetNext();
|
|
|
|
while (pc->IsNotNullChunk())
|
|
{
|
|
if (!pc->TestFlags(PCF_IN_PREPROC))
|
|
{
|
|
// Bail if we run off the end of the preprocessor directive, but return
|
|
// the token because the caller may need to know where the search ended
|
|
assert(pc->Is(CT_NEWLINE));
|
|
return(pc);
|
|
}
|
|
|
|
if (pc->Is(CT_NL_CONT))
|
|
{
|
|
// Skip line continuation
|
|
pc = pc->GetNext();
|
|
continue;
|
|
}
|
|
|
|
if ((pc->*checkFn)() == cond)
|
|
{
|
|
// Requested token was found
|
|
return(pc);
|
|
}
|
|
pc = pc->GetNext();
|
|
}
|
|
// Ran out of tokens
|
|
return(Chunk::NullChunkPtr);
|
|
}
|
|
|
|
|
|
static void chunk_log_msg(Chunk *chunk, const log_sev_t log, const char *str)
|
|
{
|
|
LOG_FMT(log, "%s orig line is %zu, orig col is %zu, ",
|
|
str, chunk->GetOrigLine(), chunk->GetOrigCol());
|
|
|
|
if (chunk->Is(CT_NEWLINE))
|
|
{
|
|
LOG_FMT(log, "<Newline>,\n");
|
|
}
|
|
else if (chunk->Is(CT_VBRACE_OPEN))
|
|
{
|
|
LOG_FMT(log, "<VBRACE_OPEN>,\n");
|
|
}
|
|
else if (chunk->Is(CT_VBRACE_CLOSE))
|
|
{
|
|
LOG_FMT(log, "<VBRACE_CLOSE>,\n");
|
|
}
|
|
else
|
|
{
|
|
LOG_FMT(log, "Text() is '%s', type is %s,\n", chunk->Text(), get_token_name(chunk->GetType()));
|
|
}
|
|
}
|
|
|
|
|
|
static void chunk_log(Chunk *pc, const char *text)
|
|
{
|
|
if ( pc->IsNotNullChunk()
|
|
&& (cpd.unc_stage != unc_stage_e::TOKENIZE)
|
|
&& (cpd.unc_stage != unc_stage_e::CLEANUP))
|
|
{
|
|
const log_sev_t log = LCHUNK;
|
|
Chunk *prev = pc->GetPrev();
|
|
Chunk *next = pc->GetNext();
|
|
|
|
chunk_log_msg(pc, log, text);
|
|
|
|
if ( prev->IsNotNullChunk()
|
|
&& next->IsNotNullChunk())
|
|
{
|
|
chunk_log_msg(prev, log, " @ between");
|
|
chunk_log_msg(next, log, " and");
|
|
}
|
|
else if (next->IsNotNullChunk())
|
|
{
|
|
chunk_log_msg(next, log, " @ before");
|
|
}
|
|
else if (prev->IsNotNullChunk())
|
|
{
|
|
chunk_log_msg(prev, log, " @ after");
|
|
}
|
|
LOG_FMT(log, " stage is %s", // Issue #3034
|
|
get_unc_stage_name(cpd.unc_stage));
|
|
log_func_stack_inline(log);
|
|
}
|
|
}
|
|
|
|
|
|
void Chunk::Delete(Chunk * &pc)
|
|
{
|
|
gChunkList.Remove(pc);
|
|
delete pc;
|
|
pc = Chunk::NullChunkPtr;
|
|
}
|
|
|
|
|
|
void Chunk::MoveAfter(Chunk *ref)
|
|
{
|
|
LOG_FUNC_ENTRY();
|
|
|
|
if (ref == this)
|
|
{
|
|
return;
|
|
}
|
|
gChunkList.Remove(this);
|
|
gChunkList.AddAfter(this, ref);
|
|
|
|
// Adjust the original column
|
|
m_column = ref->m_column + space_col_align(ref, this);
|
|
m_origCol = m_column;
|
|
m_origColEnd = m_origCol + Len();
|
|
}
|
|
|
|
|
|
void Chunk::Swap(Chunk *other)
|
|
{
|
|
gChunkList.Swap(this, other);
|
|
}
|
|
|
|
|
|
bool Chunk::IsAddress() const
|
|
{
|
|
if ( IsNotNullChunk()
|
|
&& ( Is(CT_BYREF)
|
|
|| ( Len() == 1
|
|
&& m_str[0] == '&'
|
|
&& IsNot(CT_OPERATOR_VAL))))
|
|
{
|
|
Chunk *prevc = GetPrev();
|
|
|
|
if ( TestFlags(PCF_IN_TEMPLATE)
|
|
&& ( prevc->Is(CT_COMMA)
|
|
|| prevc->Is(CT_ANGLE_OPEN)))
|
|
{
|
|
return(false);
|
|
}
|
|
return(true);
|
|
}
|
|
return(false);
|
|
}
|
|
|
|
|
|
Chunk *Chunk::GetFirstChunkOnLine() const
|
|
{
|
|
Chunk *pc = const_cast<Chunk *>(this);
|
|
Chunk *first = pc;
|
|
|
|
pc = pc->GetPrev();
|
|
|
|
while ( pc->IsNotNullChunk()
|
|
&& !pc->IsNewline())
|
|
{
|
|
first = pc;
|
|
pc = pc->GetPrev();
|
|
}
|
|
return(first);
|
|
}
|
|
|
|
|
|
bool Chunk::IsLastChunkOnLine() const
|
|
{
|
|
if (this == Chunk::GetTail())
|
|
{
|
|
return(true);
|
|
}
|
|
|
|
// if the next chunk is a newline then pc is the last chunk on its line
|
|
if (GetNext()->Is(CT_NEWLINE))
|
|
{
|
|
return(true);
|
|
}
|
|
return(false);
|
|
}
|
|
|
|
|
|
void Chunk::SwapLines(Chunk *other)
|
|
{
|
|
// to swap lines we need to find the first chunk of the lines
|
|
Chunk *pc1 = GetFirstChunkOnLine();
|
|
Chunk *pc2 = other->GetFirstChunkOnLine();
|
|
|
|
if ( pc1->IsNullChunk()
|
|
|| pc2->IsNullChunk()
|
|
|| pc1 == pc2)
|
|
{
|
|
return;
|
|
}
|
|
/*
|
|
* Example start:
|
|
* ? - start1 - a1 - b1 - nl1 - ? - ref2 - start2 - a2 - b2 - nl2 - ?
|
|
* ^- pc1 ^- pc2
|
|
*/
|
|
Chunk *ref2 = pc2->GetPrev();
|
|
|
|
// Move the line started at pc2 before pc1
|
|
while ( pc2->IsNotNullChunk()
|
|
&& !pc2->IsNewline())
|
|
{
|
|
Chunk *tmp = pc2->GetNext();
|
|
gChunkList.Remove(pc2);
|
|
gChunkList.AddBefore(pc2, pc1);
|
|
pc2 = tmp;
|
|
}
|
|
/*
|
|
* Should now be:
|
|
* ? - start2 - a2 - b2 - start1 - a1 - b1 - nl1 - ? - ref2 - nl2 - ?
|
|
* ^- pc1 ^- pc2
|
|
*/
|
|
|
|
// Now move the line started at pc1 after ref2
|
|
while ( pc1->IsNotNullChunk()
|
|
&& !pc1->IsNewline())
|
|
{
|
|
Chunk *tmp = pc1->GetNext();
|
|
gChunkList.Remove(pc1);
|
|
|
|
if (ref2->IsNotNullChunk())
|
|
{
|
|
gChunkList.AddAfter(pc1, ref2);
|
|
}
|
|
else
|
|
{
|
|
gChunkList.AddHead(pc1);
|
|
}
|
|
ref2 = pc1;
|
|
pc1 = tmp;
|
|
}
|
|
/*
|
|
* Should now be:
|
|
* ? - start2 - a2 - b2 - nl1 - ? - ref2 - start1 - a1 - b1 - nl2 - ?
|
|
* ^- pc1 ^- pc2
|
|
*/
|
|
|
|
/*
|
|
* pc1 and pc2 should be the newlines for their lines.
|
|
* swap the chunks and the new line count so that the spacing remains the same.
|
|
*/
|
|
if ( pc1->IsNotNullChunk()
|
|
&& pc2->IsNotNullChunk())
|
|
{
|
|
size_t nlCount = pc1->GetNlCount();
|
|
|
|
pc1->SetNlCount(pc2->GetNlCount());
|
|
pc2->SetNlCount(nlCount);
|
|
|
|
pc1->Swap(pc2);
|
|
}
|
|
} // Chunk::SwapLines
|
|
|
|
|
|
void Chunk::SetResetFlags(PcfFlags resetBits, PcfFlags setBits)
|
|
{
|
|
if (IsNotNullChunk())
|
|
{
|
|
LOG_FUNC_ENTRY();
|
|
const PcfFlags newFlags = (m_flags & ~resetBits) | setBits;
|
|
|
|
if (m_flags != newFlags)
|
|
{
|
|
LOG_FMT(LSETFLG,
|
|
"%s(%d): %016llx^%016llx=%016llx\n"
|
|
"%s(%d): orig line is %zu, orig col is %zu, Text() is '%s', type is %s,",
|
|
__func__, __LINE__,
|
|
static_cast<PcfFlags::int_t>(m_flags),
|
|
static_cast<PcfFlags::int_t>(m_flags ^ newFlags),
|
|
static_cast<PcfFlags::int_t>(newFlags),
|
|
__func__, __LINE__, m_origLine, m_origCol, Text(), get_token_name(m_type));
|
|
LOG_FMT(LSETFLG, " parent type is %s,\n",
|
|
get_token_name(m_parentType));
|
|
log_func_stack_inline(LSETFLG);
|
|
|
|
LOG_FMT(LSETFLG, " before: ");
|
|
log_pcf_flags(LSETFLG, m_flags);
|
|
LOG_FMT(LSETFLG, " after: ");
|
|
log_pcf_flags(LSETFLG, newFlags);
|
|
m_flags = newFlags;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Chunk::SetType(const E_Token token)
|
|
{
|
|
LOG_FUNC_ENTRY();
|
|
|
|
if ( IsNullChunk()
|
|
|| m_type == token)
|
|
{
|
|
return;
|
|
}
|
|
LOG_FMT(LSETTYP, "%s(%d): orig line is %zu, orig col is %zu, Text() is ",
|
|
__func__, __LINE__, m_origLine, m_origCol);
|
|
|
|
if (token == CT_NEWLINE)
|
|
{
|
|
LOG_FMT(LSETTYP, "<Newline>\n");
|
|
}
|
|
else
|
|
{
|
|
LOG_FMT(LSETTYP, "'%s'\n", Text());
|
|
}
|
|
LOG_FMT(LSETTYP, " type is %s, parent type is %s => new type is %s\n",
|
|
get_token_name(m_type), get_token_name(m_parentType), get_token_name(token));
|
|
m_type = token;
|
|
}
|
|
|
|
|
|
void Chunk::SetParentType(const E_Token token)
|
|
{
|
|
LOG_FUNC_ENTRY();
|
|
|
|
if ( IsNullChunk()
|
|
|| m_parentType == token)
|
|
{
|
|
return;
|
|
}
|
|
LOG_FMT(LSETPAR, "%s(%d): orig line is %zu, orig col is %zu, Text() is ",
|
|
__func__, __LINE__, m_origLine, m_origCol);
|
|
|
|
if (token == CT_NEWLINE)
|
|
{
|
|
LOG_FMT(LSETPAR, "<Newline>\n");
|
|
}
|
|
else
|
|
{
|
|
LOG_FMT(LSETPAR, "'%s'\n", Text());
|
|
}
|
|
LOG_FMT(LSETPAR, " type is %s, parent type is %s => new parent type is %s\n",
|
|
get_token_name(m_type), get_token_name(m_parentType), get_token_name(token));
|
|
m_parentType = token;
|
|
}
|
|
|
|
|
|
Chunk *Chunk::CopyAndAdd(Chunk *pos, const E_Direction dir) const
|
|
{
|
|
#ifdef DEBUG
|
|
// test if this chunk is properly set
|
|
if (m_ppLevel == 999)
|
|
{
|
|
fprintf(stderr, "%s(%d): pp level is not set\n", __func__, __LINE__);
|
|
log_func_stack_inline(LSETFLG);
|
|
log_flush(true);
|
|
exit(EX_SOFTWARE);
|
|
}
|
|
|
|
if (m_origLine == 0)
|
|
{
|
|
fprintf(stderr, "%s(%d): no line number\n", __func__, __LINE__);
|
|
log_func_stack_inline(LSETFLG);
|
|
log_flush(true);
|
|
exit(EX_SOFTWARE);
|
|
}
|
|
|
|
if (m_origCol == 0)
|
|
{
|
|
fprintf(stderr, "%s(%d): no column number\n", __func__, __LINE__);
|
|
log_func_stack_inline(LSETFLG);
|
|
log_flush(true);
|
|
exit(EX_SOFTWARE);
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
Chunk *pc = new Chunk(*this);
|
|
|
|
if (pos->IsNotNullChunk())
|
|
{
|
|
(dir == E_Direction::FORWARD) ? gChunkList.AddAfter(pc, pos) : gChunkList.AddBefore(pc, pos);
|
|
}
|
|
else
|
|
{
|
|
(dir == E_Direction::FORWARD) ? gChunkList.AddHead(pc) : gChunkList.AddTail(pc);
|
|
}
|
|
chunk_log(pc, "CopyAndAdd(A):");
|
|
return(pc);
|
|
} // Chunk::CopyAndAdd
|
|
|
|
|
|
Chunk *Chunk::GetNextNbsb() const
|
|
{
|
|
Chunk *pc = const_cast<Chunk *>(this);
|
|
|
|
while ( pc->Is(CT_TSQUARE)
|
|
|| pc->Is(CT_SQUARE_OPEN))
|
|
{
|
|
if (pc->Is(CT_SQUARE_OPEN))
|
|
{
|
|
pc = pc->GetClosingParen();
|
|
}
|
|
pc = pc->GetNextNcNnl();
|
|
}
|
|
return(pc);
|
|
}
|
|
|
|
|
|
Chunk *Chunk::GetPrevNbsb() const
|
|
{
|
|
Chunk *pc = const_cast<Chunk *>(this);
|
|
|
|
while ( pc->Is(CT_TSQUARE)
|
|
|| pc->Is(CT_SQUARE_CLOSE))
|
|
{
|
|
if (pc->Is(CT_SQUARE_CLOSE))
|
|
{
|
|
pc = pc->GetOpeningParen();
|
|
}
|
|
pc = pc->GetPrevNcNnl();
|
|
}
|
|
return(pc);
|
|
}
|
|
|
|
|
|
Chunk *Chunk::GetPpStart() const
|
|
{
|
|
if (!IsPreproc())
|
|
{
|
|
return(Chunk::NullChunkPtr);
|
|
}
|
|
Chunk *pc = const_cast<Chunk *>(this);
|
|
|
|
while (pc->IsNot(CT_PREPROC))
|
|
{
|
|
pc = pc->GetPrev(E_Scope::PREPROC);
|
|
}
|
|
return(pc);
|
|
}
|
|
|
|
|
|
Chunk *Chunk::SkipDcMember() const
|
|
{
|
|
LOG_FUNC_ENTRY();
|
|
|
|
Chunk *pc = const_cast<Chunk *>(this);
|
|
Chunk *nxt = pc->Is(CT_DC_MEMBER) ? pc : pc->GetNextNcNnl(E_Scope::ALL);
|
|
|
|
while (nxt->Is(CT_DC_MEMBER))
|
|
{
|
|
pc = nxt->GetNextNcNnl(E_Scope::ALL);
|
|
|
|
if (pc->IsNullChunk())
|
|
{
|
|
return(Chunk::NullChunkPtr);
|
|
}
|
|
nxt = pc->GetNextNcNnl(E_Scope::ALL);
|
|
}
|
|
return(pc);
|
|
}
|
|
|
|
|
|
int Chunk::ComparePosition(const Chunk *other) const
|
|
{
|
|
if (m_origLine < other->m_origLine)
|
|
{
|
|
return(-1);
|
|
}
|
|
else if (m_origLine == other->m_origLine)
|
|
{
|
|
if (m_origCol < other->m_origCol)
|
|
{
|
|
return(-1);
|
|
}
|
|
else if (m_origCol == other->m_origCol)
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
|
|
bool Chunk::IsOCForinOpenParen() const
|
|
{
|
|
if ( language_is_set(LANG_OC)
|
|
&& Is(CT_SPAREN_OPEN)
|
|
&& GetPrevNcNnl()->Is(CT_FOR))
|
|
{
|
|
Chunk *nxt = const_cast<Chunk *>(this);
|
|
|
|
while ( nxt->IsNotNullChunk()
|
|
&& nxt->IsNot(CT_SPAREN_CLOSE)
|
|
&& nxt->IsNot(CT_IN))
|
|
{
|
|
nxt = nxt->GetNextNcNnl();
|
|
}
|
|
|
|
if (nxt->Is(CT_IN))
|
|
{
|
|
return(true);
|
|
}
|
|
}
|
|
return(false);
|
|
}
|
|
|
|
|
|
bool Chunk::IsStringAndLevel(const char *str, const size_t len,
|
|
bool caseSensitive, const int level) const
|
|
{
|
|
return( ( level < 0
|
|
|| m_level == static_cast<size_t>(level))
|
|
&& Len() == len // the length is as expected
|
|
&& ( ( caseSensitive
|
|
&& memcmp(Text(), str, len) == 0)
|
|
|| ( !caseSensitive
|
|
&& strncasecmp(Text(), str, len) == 0))); // the strings are equal
|
|
}
|
|
|
|
|
|
Chunk *Chunk::GetClosingParen(E_Scope scope) const
|
|
{
|
|
if ( Is(CT_PAREN_OPEN)
|
|
|| Is(CT_SPAREN_OPEN)
|
|
|| Is(CT_FPAREN_OPEN)
|
|
|| Is(CT_TPAREN_OPEN)
|
|
|| Is(CT_BRACE_OPEN)
|
|
|| Is(CT_VBRACE_OPEN)
|
|
|| Is(CT_ANGLE_OPEN)
|
|
|| Is(CT_SQUARE_OPEN))
|
|
{
|
|
return(GetNextType((E_Token)(m_type + 1), m_level, scope));
|
|
}
|
|
return(const_cast<Chunk *>(this));
|
|
}
|
|
|
|
|
|
Chunk *Chunk::GetOpeningParen(E_Scope scope) const
|
|
{
|
|
if ( Is(CT_PAREN_CLOSE)
|
|
|| Is(CT_SPAREN_CLOSE)
|
|
|| Is(CT_FPAREN_CLOSE)
|
|
|| Is(CT_TPAREN_CLOSE)
|
|
|| Is(CT_BRACE_CLOSE)
|
|
|| Is(CT_VBRACE_CLOSE)
|
|
|| Is(CT_ANGLE_CLOSE)
|
|
|| Is(CT_SQUARE_CLOSE))
|
|
{
|
|
return(GetPrevType((E_Token)(m_type - 1), m_level, scope));
|
|
}
|
|
return(const_cast<Chunk *>(this));
|
|
}
|
|
|
|
|
|
bool Chunk::IsCppInheritanceAccessSpecifier() const
|
|
{
|
|
return( language_is_set(LANG_CPP)
|
|
&& ( Is(CT_ACCESS)
|
|
|| Is(CT_QUALIFIER))
|
|
&& ( IsString("private")
|
|
|| IsString("protected")
|
|
|| IsString("public")));
|
|
}
|
|
|
|
|
|
bool Chunk::IsColon() const
|
|
{
|
|
return( Is(CT_ACCESS_COLON)
|
|
|| Is(CT_ASM_COLON)
|
|
|| Is(CT_BIT_COLON)
|
|
|| Is(CT_CASE_COLON)
|
|
|| Is(CT_CLASS_COLON)
|
|
|| Is(CT_COLON)
|
|
|| Is(CT_COND_COLON)
|
|
|| Is(CT_CONSTR_COLON)
|
|
|| Is(CT_CS_SQ_COLON)
|
|
|| Is(CT_D_ARRAY_COLON)
|
|
|| Is(CT_ENUM_COLON)
|
|
|| Is(CT_FOR_COLON)
|
|
|| Is(CT_LABEL_COLON)
|
|
|| Is(CT_OC_COLON)
|
|
|| Is(CT_OC_DICT_COLON)
|
|
|| Is(CT_TAG_COLON)
|
|
|| Is(CT_WHERE_COLON));
|
|
}
|
|
|
|
|
|
bool Chunk::IsDoxygenComment() const
|
|
{
|
|
if (!IsComment())
|
|
{
|
|
return(false);
|
|
}
|
|
|
|
if (Len() < 3)
|
|
{
|
|
return(false);
|
|
}
|
|
// check the third character
|
|
const char *sComment = Text();
|
|
return( (sComment[2] == '/')
|
|
|| (sComment[2] == '!')
|
|
|| (sComment[2] == '@'));
|
|
}
|
|
|
|
|
|
bool Chunk::IsTypeDefinition() const
|
|
{
|
|
return( Is(CT_TYPE)
|
|
|| Is(CT_PTR_TYPE)
|
|
|| Is(CT_BYREF)
|
|
|| Is(CT_DC_MEMBER)
|
|
|| Is(CT_QUALIFIER)
|
|
|| Is(CT_STRUCT)
|
|
|| Is(CT_ENUM)
|
|
|| Is(CT_UNION));
|
|
}
|
|
|
|
|
|
bool Chunk::IsNewlineBetween(const Chunk *other) const
|
|
{
|
|
Chunk *pc = const_cast<Chunk *>(this);
|
|
|
|
while (pc != other)
|
|
{
|
|
if (pc->IsNewline())
|
|
{
|
|
return(true);
|
|
}
|
|
pc = pc->GetNext();
|
|
}
|
|
return(false);
|
|
}
|
|
|
|
|
|
void shift_the_rest_of_the_line(Chunk *first)
|
|
{
|
|
// shift all the tokens in this line to the right Issue #3236
|
|
for (Chunk *temp = first; ; temp = temp->GetNext())
|
|
{
|
|
temp->SetColumn(temp->GetColumn() + 1); // Issue #3236
|
|
temp->SetOrigCol(temp->GetOrigCol() + 1); // Issue #3236
|
|
temp->SetOrigColEnd(temp->GetOrigColEnd() + 1); // Issue #3236
|
|
|
|
if (temp->Is(CT_NEWLINE))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
} //shift_the_rest_of_the_line
|