Code::Blocks  SVN r11506
parserthread.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3
3  * http://www.gnu.org/licenses/gpl-3.0.html
4  *
5  * $Revision: 11485 $
6  * $Id: parserthread.cpp 11485 2018-10-03 09:05:53Z ollydbg $
7  * $HeadURL: https://svn.code.sf.net/p/codeblocks/code/trunk/src/plugins/codecompletion/parser/parserthread.cpp $
8  */
9 
10 #include <sdk.h>
11 
12 #ifndef CB_PRECOMP
13  #include <cctype>
14  #include <queue>
15 
16  #include <wx/app.h>
17  #include <wx/msgdlg.h>
18 
19  #include <cbexception.h>
20  #include <globals.h>
21  #include <logmanager.h>
22  #include <manager.h>
23 #endif
24 
25 #include <wx/tokenzr.h>
26 
27 #include "parserthread.h"
28 #include "parser.h"
29 #include "expression.h" // used to calculate the enumerator value
30 
31 #define CC_PARSERTHREAD_DEBUG_OUTPUT 0
32 
33 #if defined(CC_GLOBAL_DEBUG_OUTPUT)
34  #if CC_GLOBAL_DEBUG_OUTPUT == 1
35  #undef CC_PARSERTHREAD_DEBUG_OUTPUT
36  #define CC_PARSERTHREAD_DEBUG_OUTPUT 1
37  #elif CC_GLOBAL_DEBUG_OUTPUT == 2
38  #undef CC_PARSERTHREAD_DEBUG_OUTPUT
39  #define CC_PARSERTHREAD_DEBUG_OUTPUT 2
40  #endif
41 #endif
42 
43 #ifdef CC_PARSER_TEST
44  #define ADDTOKEN(format, args...) \
45  CCLogger::Get()->AddToken(F(format, ##args))
46  #define TRACE(format, args...) \
47  CCLogger::Get()->DebugLog(F(format, ##args))
48  #define TRACE2(format, args...) \
49  CCLogger::Get()->DebugLog(F(format, ##args))
50 #else
51  #if CC_PARSERTHREAD_DEBUG_OUTPUT == 1
52  #define ADDTOKEN(format, args...) \
53  CCLogger::Get()->AddToken(F(format, ##args))
54  #define TRACE(format, args...) \
55  CCLogger::Get()->DebugLog(F(format, ##args))
56  #define TRACE2(format, args...)
57  #elif CC_PARSERTHREAD_DEBUG_OUTPUT == 2
58  #define ADDTOKEN(format, args...) \
59  CCLogger::Get()->AddToken(F(format, ##args))
60  #define TRACE(format, args...) \
61  do \
62  { \
63  if (g_EnableDebugTrace) \
64  CCLogger::Get()->DebugLog(F(format, ##args)); \
65  } \
66  while (false)
67  #define TRACE2(format, args...) \
68  CCLogger::Get()->DebugLog(F(format, ##args))
69  #else
70  #define ADDTOKEN(format, args...)
71  #define TRACE(format, args...)
72  #define TRACE2(format, args...)
73  #endif
74 #endif
75 
76 #define CC_PARSERTHREAD_TESTDESTROY 0
77 
78 #if CC_PARSERTHREAD_TESTDESTROY
79 #define IS_ALIVE IsStillAlive(wxString(__PRETTY_FUNCTION__, wxConvUTF8))
80 #else
81 #define IS_ALIVE !TestDestroy()
82 #endif
83 
84 const wxString g_UnnamedSymbol = _T("__Unnamed");
85 
86 namespace ParserConsts
87 {
88  // length: 0
89  const wxString empty (_T(""));
90  const wxChar null (_T('\0'));
91  // length: 1
92  const wxChar eol_chr (_T('\n'));
93  const wxString space (_T(" "));
94  const wxChar space_chr (_T(' '));
95  const wxChar tab_chr (_T('\t'));
96  const wxString equals (_T("="));
97  const wxChar equals_chr (_T('='));
98  const wxString hash (_T("#"));
99  const wxChar hash_chr (_T('#'));
100  const wxString plus (_T("+"));
101  const wxChar plus_chr (_T('+'));
102  const wxString dash (_T("-"));
103  const wxChar dash_chr (_T('-'));
104  const wxString ptr (_T("*"));
105  const wxChar ptr_chr (_T('*'));
106  const wxString ref (_T("&"));
107  const wxChar ref_chr (_T('&'));
108  const wxString comma (_T(","));
109  const wxChar comma_chr (_T(','));
110  const wxString dot (_T("."));
111  const wxChar dot_chr (_T('.'));
112  const wxString colon (_T(":"));
113  const wxChar colon_chr (_T(':'));
114  const wxString semicolon (_T(";"));
115  const wxChar semicolon_chr (_T(';'));
116  const wxChar opbracket_chr (_T('('));
117  const wxChar clbracket_chr (_T(')'));
118  const wxString opbracket (_T("("));
119  const wxString clbracket (_T(")"));
120  const wxString opbrace (_T("{"));
121  const wxChar opbrace_chr (_T('{'));
122  const wxString clbrace (_T("}"));
123  const wxChar clbrace_chr (_T('}'));
124  const wxString oparray (_T("["));
125  const wxChar oparray_chr (_T('['));
126  const wxString clarray (_T("]"));
127  const wxChar clarray_chr (_T(']'));
128  const wxString tilde (_T("~"));
129  const wxString lt (_T("<"));
130  const wxChar lt_chr (_T('<'));
131  const wxString gt (_T(">"));
132  const wxChar gt_chr (_T('>'));
133  const wxChar underscore_chr (_T('_'));
134  const wxChar question_chr (_T('?'));
135  // length: 2
136  const wxString dcolon (_T("::"));
137  const wxString opbracesemicolon(_T("{;"));
138  const wxString commaclbrace (_T(",}"));
139  const wxString semicolonopbrace(_T(";{"));
140  const wxString semicolonclbrace(_T(";}"));
141  const wxString gtsemicolon (_T(">;"));
142  const wxString quot (_T("\""));
143  const wxString kw_do (_T("do"));
144  const wxString kw_if (_T("if"));
145  // length: 3
146  const wxString spaced_colon (_T(" : "));
147  const wxString kw__C_ (_T("\"C\""));
148  const wxString kw_for (_T("for"));
149  const wxString kw_try (_T("try"));
150  const wxString commasemicolonopbrace(_T(",;{"));
151  // length: 4
152  const wxString kw___at (_T("__at"));
153  const wxString kw_else (_T("else"));
154  const wxString kw_enum (_T("enum"));
155  const wxString kw_elif (_T("elif"));
156  const wxString kw_case (_T("case"));
157  // length: 5
158  const wxString kw__CPP_ (_T("\"C++\""));
159  const wxString kw___asm (_T("__asm"));
160  const wxString kw_catch (_T("catch"));
161  const wxString kw_class (_T("class"));
162  const wxString kw_const (_T("const"));
163  const wxString kw_union (_T("union"));
164  const wxString kw_using (_T("using"));
165  const wxString kw_throw (_T("throw"));
166  const wxString kw_while (_T("while"));
167  // length: 6
168  const wxString kw_delete (_T("delete"));
169  const wxString kw_extern (_T("extern"));
170  const wxString kw_friend (_T("friend"));
171  const wxString kw_inline (_T("inline"));
172  const wxString kw_public (_T("public"));
173  const wxString kw_return (_T("return"));
174  const wxString kw_static (_T("static"));
175  const wxString kw_struct (_T("struct"));
176  const wxString kw_switch (_T("switch"));
177  // length: 7
178  const wxString kw_include (_T("include"));
179  const wxString kw_private (_T("private"));
180  const wxString kw_typedef (_T("typedef"));
181  const wxString kw_virtual (_T("virtual"));
182  // length: 8
183  const wxString kw_noexcept (_T("noexcept"));
184  const wxString kw_operator (_T("operator"));
185  const wxString kw_template (_T("template"));
186  const wxString kw_typename (_T("typename"));
187  const wxString kw_volatile (_T("volatile"));
188  // length: 9
189  const wxString kw_namespace (_T("namespace"));
190  const wxString kw_protected (_T("protected"));
191  // length: 10
192  const wxString kw_declspec (_T("__declspec"));
193  // length: 13
194  const wxString kw_attribute (_T("__attribute__"));
195 }
196 
198  const wxString& bufferOrFilename,
199  bool isLocal,
200  ParserThreadOptions& parserThreadOptions,
201  TokenTree* tokenTree) :
202  m_Tokenizer(tokenTree),
203  m_Parent(parent),
204  m_TokenTree(tokenTree),
205  m_LastParent(0),
206  m_LastScope(tsUndefined),
207  m_FileSize(0),
208  m_FileIdx(0),
209  m_IsLocal(isLocal),
210  m_Options(parserThreadOptions),
211  m_ParsingTypedef(false),
212  m_Buffer(bufferOrFilename),
213  m_StructUnionUnnamedCount(0),
214  m_EnumUnnamedCount(0)
215 {
216  m_Tokenizer.SetTokenizerOption(parserThreadOptions.wantPreprocessor,
217  parserThreadOptions.storeDocumentation);
218  if (!m_TokenTree)
219  cbThrow(_T("m_TokenTree is a nullptr?!"));
220 }
221 
223 {
224  // wait for file loader object to complete (can't abort it)
225  if (m_Options.loader)
226  {
227  m_Options.loader->Sync();
228  delete m_Options.loader;
229  }
230 }
231 
232 wxChar ParserThread::SkipToOneOfChars(const wxString& chars, bool supportNesting, bool singleCharToken)
233 {
234  unsigned int level = m_Tokenizer.GetNestingLevel();
235  while (IS_ALIVE)
236  {
237  wxString token = m_Tokenizer.GetToken(); // grab next token...
238  if (token.IsEmpty())
239  return ParserConsts::null; // eof
240 
241  // if supportNesting==true, we only do a match in the same brace/nesting level,
242  // thus we preserve the brace level when the function returned. But if
243  // supportNesting==false, we do not consider the brace level on matching.
244  if (!supportNesting || m_Tokenizer.GetNestingLevel() == level)
245  {
246  // only consider tokens of length one, if requested
247  if (singleCharToken && token.length() > 1)
248  continue;
249 
250  wxChar ch = token.GetChar(0);
251  if (chars.Find(ch) != wxNOT_FOUND) // match one char
252  return ch;
253  }
254  }
255 
256  return ParserConsts::null; // not found
257 }
258 
260 {
261  // need to force the tokenizer _not_ skip anything
262  // or else default values for template params would cause us to miss everything (because of the '=' symbol)
263  TokenizerState oldState = m_Tokenizer.GetState();
265 
266  // skip tokens until we reach }
267  // block nesting is taken into consideration too ;)
268 
269  // this is the nesting level we start at
270  // we subtract 1 because we 're already inside the block
271  // (since we 've read the {)
272  unsigned int level = m_Tokenizer.GetNestingLevel() - 1;
273  while (IS_ALIVE)
274  {
275  wxString token = m_Tokenizer.GetToken();
276  if (token.IsEmpty())
277  break; // eof
278 
279  // if we reach the initial nesting level, we are done
280  if (level == m_Tokenizer.GetNestingLevel())
281  break;
282  }
283 
284  // reset tokenizer's functionality
285  m_Tokenizer.SetState(oldState);
286 }
287 
289 {
290  // need to force the tokenizer _not_ skip anything
291  // or else default values for template params would cause us to miss everything (because of the '=' symbol)
292  TokenizerState oldState = m_Tokenizer.GetState();
294 
295  int nestLvl = 0;
296  // NOTE: only exit this loop with 'break' so the tokenizer's state can
297  // be reset afterwards (i.e. don't use 'return')
298  while (IS_ALIVE)
299  {
300  wxString tmp = m_Tokenizer.GetToken();
301  if (tmp==ParserConsts::lt)
302  ++nestLvl;
303  else if (tmp==ParserConsts::gt)
304  --nestLvl;
305  else if (tmp==ParserConsts::semicolon)
306  {
307  // unget token - leave ; on the stack
309  break;
310  }
311  else if (tmp.IsEmpty())
312  break;
313  if (nestLvl <= 0)
314  break;
315  }
316 
317  // reset tokenizer's functionality
318  m_Tokenizer.SetState(oldState);
319 }
320 
322 {
323  m_Tokenizer.InitFromBuffer(buffer);
324  if (!m_Tokenizer.IsOK())
325  return false;
326 
327  result.clear();
328 
329  wxArrayString nsStack;
331  m_ParsingTypedef = false;
332 
333  while (m_Tokenizer.NotEOF() && IS_ALIVE)
334  {
335  wxString token = m_Tokenizer.GetToken();
336  if (token.IsEmpty())
337  continue;
338 
339  if (token == ParserConsts::kw_using)
341  else if (token == ParserConsts::opbrace)
342  SkipBlock();
343  else if (token == ParserConsts::kw_namespace)
344  {
345  wxString name = m_Tokenizer.GetToken();
346  if (name == ParserConsts::opbrace)
347  name = wxEmptyString; // anonymous namespace
348  else
349  {
350  wxString next = m_Tokenizer.PeekToken();
351  if (next == ParserConsts::equals)
352  {
354  continue;
355  }
356  else if (next == ParserConsts::opbrace)
357  {
359  name += ParserConsts::dcolon;
360  }
361  }
362 
363  nsStack.Add(name);
364  NameSpace ns;
365  for (size_t i = 0; i < nsStack.Count(); ++i)
366  ns.Name << nsStack[i];
368  ns.EndLine = -1;
369 
370  result.push_back(ns);
371  }
372  else if (token == ParserConsts::clbrace)
373  {
374  NameSpaceVec::reverse_iterator it;
375  for (it = result.rbegin(); it != result.rend(); ++it)
376  {
377  NameSpace& ns = *it;
378  if (ns.EndLine == -1)
379  {
380  ns.EndLine = m_Tokenizer.GetLineNumber() - 1;
381  break;
382  }
383  }
384 
385  if (!nsStack.IsEmpty())
386  nsStack.RemoveAt(nsStack.GetCount() - 1);
387  }
388  }
389  return true;
390 }
391 
393 {
394  m_Tokenizer.InitFromBuffer(buffer);
395  if (!m_Tokenizer.IsOK())
396  return false;
397 
398  result.Clear();
399  m_Str.Clear();
401  m_ParsingTypedef = false;
402 
403  // Notice: clears the queue "m_EncounteredTypeNamespaces"
404  while (!m_EncounteredTypeNamespaces.empty())
406 
407  // Notice: clears the queue "m_EncounteredNamespaces"
408  while (!m_EncounteredNamespaces.empty())
410 
411  while (m_Tokenizer.NotEOF() && IS_ALIVE)
412  {
413  wxString token = m_Tokenizer.GetToken();
414  if (token.IsEmpty())
415  continue;
416 
417  if (token==ParserConsts::kw_namespace)
418  {
419  // need this too
420  token = m_Tokenizer.GetToken();
422 
423  if (!token.IsEmpty())
424  result.Add(token);
425  }
427  {
428  SkipBlock();
429  }
430  else if (token==ParserConsts::kw_using)
431  {
432  // there are some kinds of using keyword usage
433  // (1) using namespace A;
434  // (2) using namespace A::B; // where B is a namespace
435  // (3) using A::B; // where B is NOT a namespace
436  // (4) using A = B; // doesn't import anything, so we don't handle this here
437  token = m_Tokenizer.GetToken();
438  wxString peek = m_Tokenizer.PeekToken();
439  if (token == ParserConsts::kw_namespace || peek == ParserConsts::dcolon)
440  {
441  if (peek == ParserConsts::dcolon) // using declaration, such as case (3)
442  m_Str << token; // push the A to the m_Str(type stack)
443  else //handling the case (1) and (2)
444  {
445  // using directive
446  while (IS_ALIVE) // support full namespaces
447  {
451  else
452  break;
453  }
454  }
455  // m_Str must end with a namespace for CC to work
456  // now, m_Str contains "A" in case (1) and (3), and "A::B" in case (2)
457  if (!m_Str.IsEmpty())
458  result.Add(m_Str);
459  m_Str.Clear();
460  }
461  else
463  }
464  }
465  return true;
466 }
467 
469 {
470  if (!m_Buffer.IsEmpty())
471  {
472  if (!m_Options.useBuffer)
473  {
474  if (wxFileExists(m_Buffer))
475  {
476  wxFile file(m_Buffer);
477  if (file.IsOpened())
478  {
480  m_FileSize = file.Length();
481 
482  TRACE(_T("InitTokenizer() : m_Filename='%s', m_FileSize=%u."), m_Filename.wx_str(), m_FileSize);
483 
485  // must delete the loader, since it was allocated by SDK's Load() function
487 
488  if (!ret) { TRACE(_T("InitTokenizer() : Could not initialise tokenizer for file '%s'."), m_Filename.wx_str()); }
489  return ret;
490  }
491  }
492 
493  TRACE(_T("InitTokenizer() : Could not open file: '%s'."), m_Buffer.wx_str());
494  return false;
495  }
496  else
497  {
498  // record filename for buffer parsing
501 
503  }
504  }
505 
506  TRACE(_T("InitTokenizer() : Buffer is empty."));
507  return false;
508 }
509 
511 {
512  if (!IS_ALIVE || !InitTokenizer())
513  return false;
514 
515  TRACE(_T("Parse() : Parsing '%s'"), m_Filename.wx_str());
516 
517  bool result = false;
518  m_ParsingTypedef = false;
519 
520  do
521  {
522  if (!m_TokenTree || !m_Tokenizer.IsOK())
523  break;
524 
525  if (!m_Options.useBuffer) // Parse a file
526  {
527  // the second parameter of ReserveFileForParsing() is false, so set it to fpsBeingParsed
529  if (!m_FileIdx)
530  break;
531  }
532 
533  DoParse();
534 
535  if (!m_Options.useBuffer) // Parsing a file
537 
538  result = true;
539  }
540  while (false);
541 
542  return result;
543 }
544 
546 {
547  // need to reset tokenizer's behaviour
548  // don't forget to reset that if you add any early exit condition!
549  TokenizerState oldState = m_Tokenizer.GetState();
551 
552  m_Str.Clear();
553  m_LastToken.Clear();
555 
556  // Notice: clears the queue "m_EncounteredTypeNamespaces"
557  while (!m_EncounteredTypeNamespaces.empty())
559 
560  // Notice: clears the queue "m_EncounteredNamespaces"
561  while (!m_EncounteredNamespaces.empty())
563 
564  while (m_Tokenizer.NotEOF() && IS_ALIVE)
565  {
566  wxString token = m_Tokenizer.GetToken();
567  if (token.IsEmpty())
568  continue;
569 
570  TRACE(_T("DoParse() : Loop:m_Str='%s', token='%s'"), m_Str.wx_str(), token.wx_str());
571 
572  bool switchHandled = true;
573  switch (token.Length())
574  {
575  // ---------------------------------------------------------------
576  // token length of 1
577  // ---------------------------------------------------------------
578  case 1:
579  switch (static_cast<wxChar>(token[0]))
580  {
582  {
583  m_Str.Clear();
585  // Notice: clears the queue "m_EncounteredTypeNamespaces"
586  while (!m_EncounteredTypeNamespaces.empty())
589  }
590  break;
591 
593  {
594  m_Str.Clear();
596  }
597  break;
598 
600  {
602  {
603  m_Str.Clear();
605  }
606  else
607  switchHandled = false;
608  }
609  break;
610 
612  {
614  SkipBlock();
615  m_Str.Clear();
616  }
617  break;
618 
620  {
621  m_LastParent = 0L;
623  m_Str.Clear();
624  // the only time we get to find a } is when recursively called by e.g. HandleClass
625  // we have to return now...
627  {
628  m_Tokenizer.SetState(oldState); // This uses the top-level oldState (renamed shadowed versions below)
629  return;
630  }
631  }
632  break;
633 
635  {
642  m_Str.Clear();
643  }
644  break;
645 
647  {
648  token = m_Tokenizer.GetToken();
649  // only the ptOthers kinds of preprocessor directives will be passed here
650  // see details in: Tokenizer::SkipPreprocessorBranch()
651  // those could be: "#include" or "#warning" or "#xxx" and more
652  if (token == ParserConsts::kw_include)
653  HandleIncludes();
654  else // handle "#warning" or "#xxx" and more, just skip them
656 
657  m_Str.Clear();
658  }
659  break;
660 
663  {
664  m_PointerOrRef << token;
665  }
666  break;
667 
669  {
670  // pattern int a = 3;
671  // m_Str.Clear();
674  }
675  break;
676 
678  {
679  m_Str.Clear();
681  }
682  break;
683 
685  {
686  m_Str.Clear();
688  }
689  break;
690 
692  {
694  {
695  m_Str.Clear();
697  }
698  }
699  break;
700 
702  {
704  }
705  break;
706 
708  break;
709 
710  default:
711  switchHandled = false;
712  break;
713  }
714  break;
715 
716  // ---------------------------------------------------------------
717  // token length of 2
718  // ---------------------------------------------------------------
719  case 2:
720  if (token == ParserConsts::kw_if || token == ParserConsts::kw_do)
721  {
724  else
726 
727  m_Str.Clear();
728  }
729  else
730  switchHandled = false;
731  break;
732 
733  // ---------------------------------------------------------------
734  // token length of 3
735  // ---------------------------------------------------------------
736  case 3:
737  if (token == ParserConsts::kw_for)
738  {
741  else
743 
744  m_Str.Clear();
745  }
746  else
747  switchHandled = false;
748  break;
749 
750  // ---------------------------------------------------------------
751  // token length of 4
752  // ---------------------------------------------------------------
753  case 4:
754  if (token == ParserConsts::kw_else)
755  {
758  m_Str.Clear();
759  }
760  else if (token == ParserConsts::kw_enum)
761  {
762  m_Str.Clear();
764  HandleEnum();
765  else
767  }
768  else if (token == ParserConsts::kw_case)
769  {
770  m_Str.Clear();
772  }
773  else if (token == ParserConsts::kw___at)
774  {
775  m_Tokenizer.GetToken(); // skip arguments
776  }
777  else
778  switchHandled = false;
779  break;
780 
781  // ---------------------------------------------------------------
782  // token length of 5
783  // ---------------------------------------------------------------
784  case 5:
785  if (token == ParserConsts::kw_while || token == ParserConsts::kw_catch)
786  {
789  else
791 
792  m_Str.Clear();
793  }
794  else if (token == ParserConsts::kw_const)
795  {
796  m_Str << token << _T(" ");
797  }
798  else if (token==ParserConsts::kw_using)
799  {
800  // there are some kinds of using keyword usage
801  // (1) using namespace A;
802  // (2) using namespace A::B;
803  // (3) using A::B;
804  // (4) using A = B;
805  token = m_Tokenizer.GetToken();
806  wxString peek = m_Tokenizer.PeekToken();
807  if (peek == ParserConsts::kw_namespace)
808  {
809  while (true) // support full namespaces
810  {
814  else
815  break;
816  }
817  if ( !m_Str.IsEmpty()
818  && m_LastParent != 0L
819  && m_LastParent->m_Index != -1
821  {
824  else
826  }
827  else if ( !m_Str.IsEmpty()
828  && (m_LastParent == 0 || m_LastParent->m_Index == -1) )
829  {
830  // using namespace in global scope
831  // "using namespace first::second::third;"
832 
833  Token* foundNsToken = nullptr;
835  while (tokenizer.HasMoreTokens())
836  {
837  std::queue<wxString> nsQuqe;
838  nsQuqe.push(tokenizer.GetNextToken());
839  foundNsToken = FindTokenFromQueue(nsQuqe, foundNsToken, true, foundNsToken);
840  foundNsToken->m_TokenKind = tkNamespace;
841  }
842  m_UsedNamespacesIds.insert(foundNsToken->m_Index);
843  }
844  }
845  else if (peek == ParserConsts::equals)
846  {
847  // Type alias pattern: using AAA = BBB::CCC;
848  // Handle same as a typedef
849  wxString args;
850  size_t lineNr = m_Tokenizer.GetLineNumber();
851  Token* tdef = DoAddToken(tkTypedef, token, lineNr, 0, 0, args);
852 
853  m_Tokenizer.GetToken(); // eat equals
854  wxString type;
855 
856  while (IS_ALIVE) // support full namespaces
857  {
858  type << m_Tokenizer.GetToken();
860  type << m_Tokenizer.GetToken();
861  else
862  break;
863  }
864 
865  if (tdef)
866  {
867  tdef->m_FullType = type;
868  tdef->m_BaseType = type;
869  if (tdef->IsValidAncestor(type))
870  tdef->m_AncestorsString = type;
871  }
872  }
873  else
875 
876  m_Str.Clear();
877  }
878  else if (token == ParserConsts::kw_class)
879  {
880  m_Str.Clear();
883  else
885  }
886  else if (token == ParserConsts::kw_union)
887  {
888  m_Str.Clear();
891  else
893  }
894  else
895  switchHandled = false;
896  break;
897 
898  // ---------------------------------------------------------------
899  // token length of 6
900  // ---------------------------------------------------------------
901  case 6:
902  if (token == ParserConsts::kw_delete)
903  {
904  m_Str.Clear();
906  }
907  else if (token == ParserConsts::kw_switch)
908  {
911  else
912  m_Tokenizer.GetToken(); // skip arguments
913  m_Str.Clear();
914  }
915  else if (token == ParserConsts::kw_return)
916  {
918  m_Str.Clear();
919  }
920  else if (token == ParserConsts::kw_extern)
921  {
922  // check for "C", "C++"
925  {
927  {
928  m_Tokenizer.GetToken(); // "eat" {
929  DoParse(); // time for recursion ;)
930  }
931  }
932  else
933  {
934  // do nothing, just skip keyword "extern", otherwise uncomment:
935  //SkipToOneOfChars(ParserConsts::semicolon); // skip externs
937  }
938  m_Str.Clear();
939  }
940  else if ( token == ParserConsts::kw_static
941  || token == ParserConsts::kw_inline )
942  {
943  // do nothing, just skip keyword "static" / "inline"
944  }
945  else if (token == ParserConsts::kw_friend)
946  {
947  // friend methods can be either the decl only or an inline implementation
949  m_Str.Clear();
950  }
951  else if (token == ParserConsts::kw_struct)
952  {
953  m_Str.Clear();
956  else
958  }
959  else
960  switchHandled = false;
961  break;
962 
963  // ---------------------------------------------------------------
964  // token length of 7
965  // ---------------------------------------------------------------
966  case 7:
967  if (token == ParserConsts::kw_typedef)
968  {
970  HandleTypedef();
971  else
973  m_Str.Clear();
974  }
975  else if (token == ParserConsts::kw_virtual)
976  {
977  // do nothing, just skip keyword "virtual"
978  }
979  else
980  switchHandled = false;
981  break;
982 
983  // ---------------------------------------------------------------
984  // token length of 8
985  // ---------------------------------------------------------------
986  case 8:
987  if (token == ParserConsts::kw_template)
988  {
989  // There are some template definitions that are not working like
990  // within gcc headers (NB: This syntax is a GNU extension):
991  // extern template
992  // const codecvt<char, char, mbstate_t>&
993  // use_facet<codecvt<char, char, mbstate_t> >(const locale&);
994  // read <> as a whole token
996  TRACE(_T("DoParse() : Template argument='%s'"), m_TemplateArgument.wx_str());
997  m_Str.Clear();
1000  }
1001  else if (token == ParserConsts::kw_noexcept)
1002  {
1003  m_Str << token << _T(" ");
1004  }
1005  else if (token == ParserConsts::kw_operator)
1006  {
1007  wxString func = token;
1008  while (IS_ALIVE)
1009  {
1010  token = m_Tokenizer.GetToken();
1011  if (!token.IsEmpty())
1012  {
1013  if (token.GetChar(0) == ParserConsts::opbracket_chr)
1014  {
1015  // check for operator()()
1016  wxString peek = m_Tokenizer.PeekToken();
1017  if ( !peek.IsEmpty()
1018  && peek.GetChar(0) != ParserConsts::opbracket_chr)
1020  else
1021  func << token;
1022  break;
1023  }
1024  else
1025  func << token;
1026  }
1027  else
1028  break;
1029  }
1030  HandleFunction(func, true);
1031  }
1032  else
1033  switchHandled = false;
1034  break;
1035 
1036  // ---------------------------------------------------------------
1037  // token length of 9
1038  // ---------------------------------------------------------------
1039  case 9:
1040  if (token == ParserConsts::kw_namespace)
1041  {
1042  m_Str.Clear();
1043  HandleNamespace();
1044  }
1045  else
1046  switchHandled = false;
1047  break;
1048 
1049  // ---------------------------------------------------------------
1050  // token length of 10
1051  // ---------------------------------------------------------------
1052  case 10:
1053  if (token == ParserConsts::kw_declspec)
1054  {
1055  // Handle stuff like: int __declspec ((whatever)) fun();
1056  // __declspec already be eat
1057  m_Tokenizer.GetToken(); // eat (( whatever ))
1058  }
1059  else
1060  switchHandled = false;
1061  break;
1062 
1063  // ---------------------------------------------------------------
1064  // token length of 13
1065  // ---------------------------------------------------------------
1066  case 13:
1067  if (token == ParserConsts::kw_attribute)
1068  {
1069  // Handle stuff like: int __attribute__((whatever)) fun();
1070  // __attribute__ already be eat
1071  m_Tokenizer.GetToken(); // eat (( whatever ))
1072  }
1073  else
1074  switchHandled = false;
1075  break;
1076 
1077  // token length of other than 1 .. 13
1078  default:
1079  switchHandled = false;
1080  break;
1081  }
1082 
1084  {
1085  // Handle: __asm assembly-instruction [ ; ] OR
1086  // __asm { assembly-instruction-list } [ ; ] OR
1087  // __asm __volatile("assembly-instruction-list");
1088  // TODO: You can also put __asm in front of each assembly instruction:
1089  // __asm mov al, 2
1090  // __asm mov dx, 0xD007
1091  // OR: __asm mov al, 2 __asm mov dx, 0xD007
1093  }
1094  else if (!switchHandled)
1095  {
1096  // since we can't recognize the pattern by token, then the token
1097  // is normally an identifier style lexeme, now we try to peek the next token
1098  wxString peek = m_Tokenizer.PeekToken();
1099  if (!peek.IsEmpty())
1100  {
1101 
1102  if ( (peek.GetChar(0) == ParserConsts::opbracket_chr)
1104  {
1105  if ( m_Str.IsEmpty()
1106  && m_EncounteredNamespaces.empty()
1107  && m_EncounteredTypeNamespaces.empty()
1108  && (!m_LastParent || m_LastParent->m_Name != token) ) // if func has same name as current scope (class)
1109  {
1110  // see what is inside the (...)
1111  wxString arg = m_Tokenizer.GetToken(); // eat args ()
1112  // try to see whether the peek pattern is (* BBB)
1113  int pos = peek.find(ParserConsts::ptr);
1114  if (pos != wxNOT_FOUND)
1115  {
1116  peek = m_Tokenizer.PeekToken();
1117  // see whether there is a (...) after (* BBB)
1118  if (peek.GetChar(0) == ParserConsts::opbracket_chr)
1119  {
1120  // pattern: AAA (* BBB) (...)
1121  // where peek is (...) and arg is (* BBB)
1122 
1123  // NOTE: support func ptr in local block, show return type.
1124  // if (!m_Options.useBuffer || m_Options.bufferSkipBlocks)
1125  // HandleFunction(arg); // function
1126  // AAA now becomes the last element of stacked type string
1127  // which is the return type of function ptr
1128  m_Str << token << ParserConsts::space_chr;
1129  // BBB is now the function ptr's name
1130  HandleFunction(/*function name*/ arg,
1131  /*isOperator*/ false,
1132  /*isPointer*/ true);
1133  }
1134  }
1135  else // wxString arg = m_Tokenizer.GetToken(); // eat args ()
1136  m_Str = token + arg;
1137  }
1138  // NOTE: support some more cases..., such as m_Str is not empty
1139  // if (!m_Options.useBuffer || m_Options.bufferSkipBlocks)
1140  // HandleFunction(token); // function
1141  // else
1142  // m_Tokenizer.GetToken(); // eat args when parsing block
1143 
1144  // list of function ptrs
1145  // eg: void (*fun1)(void), (*fun2)(size_t size);
1146  // where, m_Str=void, token=(*fun2), peek=(size_t size)
1147 
1148  // function ptr with pointer return type
1149  // eg: void *(*Alloc)(void *p, size_t size);
1150  // where, m_Str=void, token=(*Alloc), peek=(void *p, size_t size)
1151  else if (token.GetChar(0) == ParserConsts::opbracket_chr)
1152  {
1153  int pos = token.find(ParserConsts::ptr);
1154  if (pos != wxNOT_FOUND)
1155  {
1156  wxString arg = token;
1157  HandleFunction(/*function name*/ arg,
1158  /*isOperator*/ false,
1159  /*isPointer*/ true);
1160  }
1161  }
1162  else
1163  {
1164  // pattern unsigned int (*getClientLibVersion)(char** result);
1165  // currently, m_Str = unsigned, token = int, peek = (*getClientLibVersion)
1166  // this may be a function pointer declaration, we can guess without
1167  // reading the next token, if "peek" has a ptr char and only 1 argument
1168  // in it.
1169 
1170  // see what is inside the (...)
1171  // try to see whether the peek pattern is (* BBB)
1172  if (peek.GetChar(1) == ParserConsts::ptr)
1173  {
1174  wxString arg = peek;
1175  m_Str << token;
1176  token = m_Tokenizer.GetToken(); //consume the peek
1177  // BBB is now the function ptr's name
1178  HandleFunction(/*function name*/ arg,
1179  /*isOperator*/ false,
1180  /*isPointer*/ true);
1181  }
1183  {
1184  // pattern AAA BBB (...) in global namespace (not in local block)
1185  // so, this is mostly like a function declaration, but in-fact this
1186  // can also be a global variable initialized with ctor, but for
1187  // simplicity, we drop the later case
1188  HandleFunction(token); // function
1189  }
1190  else
1191  {
1192  // local variables initialized with ctor
1193  if (!m_Str.IsEmpty() && m_Options.handleVars)
1194  {
1195  Token* newToken = DoAddToken(tkVariable, token, m_Tokenizer.GetLineNumber());
1196  if (newToken && !m_TemplateArgument.IsEmpty())
1197  ResolveTemplateArgs(newToken);
1198  }
1199  m_Tokenizer.GetToken(); // eat args when parsing block
1200  }
1201  }
1202  }
1203  else if ( (peek == ParserConsts::colon)
1204  && (token != ParserConsts::kw_private)
1205  && (token != ParserConsts::kw_protected)
1206  && (token != ParserConsts::kw_public) )
1207  {
1208  // example decl to encounter a colon is when defining a bitfield: int x:1,y:1,z:1;
1209  // token should hold the var (x/y/z)
1210  // m_Str should hold the type (int)
1211  if (m_Options.handleVars)
1213 
1214  m_Tokenizer.GetToken(); // skip colon
1215  m_Tokenizer.GetToken(); // skip bitfield
1216  }
1217  else if (peek==ParserConsts::comma)
1218  {
1219  // example decl to encounter a comma: int x,y,z;
1220  // token should hold the var (x/y/z)
1221  // m_Str should hold the type (int)
1222  if (!m_Str.IsEmpty() && m_Options.handleVars)
1223  {
1224  Token* newToken = DoAddToken(tkVariable, token, m_Tokenizer.GetLineNumber());
1225  if (newToken && !m_TemplateArgument.IsEmpty())
1226  ResolveTemplateArgs(newToken);
1227  }
1228 
1229  // else it's a syntax error; let's hope we can recover from this...
1230  // skip comma (we had peeked it)
1232  }
1233  else if (peek==ParserConsts::lt)
1234  {
1235  // a template, e.g. someclass<void>::memberfunc
1236  // we have to skip <>, so we 're left with someclass::memberfunc
1237  // about 'const' handle, e.g.
1238  /* template<typename T> class A{};
1239  const A<int> var; */
1241  GetTemplateArgs();
1242  else
1243  SkipAngleBraces();
1244  peek = m_Tokenizer.PeekToken();
1245  if (peek==ParserConsts::dcolon)
1246  {
1247  TRACE(_T("DoParse() : peek='::', token='") + token + _T("', m_LastToken='") + m_LastToken + _T("', m_Str='") + m_Str + _T("'"));
1248  if (m_Str.IsEmpty())
1249  m_EncounteredTypeNamespaces.push(token); // it's a type's namespace
1250  else
1251  m_EncounteredNamespaces.push(token);
1252  m_Tokenizer.GetToken(); // eat ::
1253  }
1254  else // case like, std::map<int, int> somevar;
1255  m_Str << token << ParserConsts::space_chr;
1256  }
1257  else if (peek==ParserConsts::dcolon)
1258  {
1259  wxString str_stripped(m_Str); str_stripped.Trim(true).Trim(false);
1260  if ( str_stripped.IsEmpty()
1261  || str_stripped.IsSameAs(ParserConsts::kw_const)
1262  || str_stripped.IsSameAs(ParserConsts::kw_volatile) ) // what else?!
1263  m_EncounteredTypeNamespaces.push(token); // it's a type's namespace
1264  else
1265  m_EncounteredNamespaces.push(token);
1266  m_Tokenizer.GetToken(); // eat ::
1267  }
1268  // NOTE: opbracket_chr already handled above
1269  else if ( peek==ParserConsts::semicolon
1270  || peek==ParserConsts::oparray_chr
1271  || peek==ParserConsts::equals_chr)
1272  {
1273  if ( !m_Str.IsEmpty()
1274  && ( wxIsalpha(token.GetChar(0))
1275  || (token.GetChar(0) == ParserConsts::underscore_chr) ) )
1276  {
1277  // pattern: m_Str AAA;
1278  // pattern: m_Str AAA[X][Y];
1279  // pattern: m_Str AAA = BBB;
1280  // where AAA is the variable name, m_Str contains type string
1281  if (m_Options.handleVars)
1282  {
1283  Token* newToken = DoAddToken(tkVariable, token, m_Tokenizer.GetLineNumber());
1284  if (newToken && !m_TemplateArgument.IsEmpty())
1285  ResolveTemplateArgs(newToken);
1286  }
1287  else
1289  }
1290 
1291  if (peek==ParserConsts::oparray_chr)
1293  else if (peek==ParserConsts::equals_chr)
1294  {
1297  }
1298  }
1299  else if (!m_EncounteredNamespaces.empty())
1300  {
1301  // Notice: clears the queue "m_EncounteredNamespaces", too
1302  while (!m_EncounteredNamespaces.empty())
1303  {
1306  }
1307  m_Str = token;
1308  }
1309  else
1310  m_Str << token << ParserConsts::space_chr;
1311  }
1312  }
1313 
1314  m_LastToken = token;
1315  }
1316 
1317  // reset tokenizer behaviour
1318  m_Tokenizer.SetState(oldState);
1319 }
1320 
1321 Token* ParserThread::TokenExists(const wxString& name, const Token* parent, short int kindMask)
1322 {
1323  // no critical section needed here:
1324  // all functions that call this, already entered a critical section.
1325 
1326  // Lookup in local parent or in global scope
1327  int foundIdx = m_TokenTree->TokenExists(name, parent ? parent->m_Index : -1, kindMask);
1328  if (foundIdx != wxNOT_FOUND)
1329  return m_TokenTree->at(foundIdx);
1330 
1331  // Lookup in included namespaces
1332  foundIdx = m_TokenTree->TokenExists(name, m_UsedNamespacesIds, kindMask);
1333  return m_TokenTree->at(foundIdx);
1334 }
1335 
1336 Token* ParserThread::TokenExists(const wxString& name, const wxString& baseArgs, const Token* parent, TokenKind kind)
1337 {
1338  // no critical section needed here:
1339  // all functions that call this, already entered a critical section.
1340 
1341  // Lookup in local parent or in global scope
1342  int foundIdx = m_TokenTree->TokenExists(name, baseArgs, parent ? parent->m_Index : -1, kind);
1343  if(foundIdx != wxNOT_FOUND)
1344  return m_TokenTree->at(foundIdx);
1345 
1346  // Lookup in included namespaces
1347  foundIdx = m_TokenTree->TokenExists(name, baseArgs, m_UsedNamespacesIds, kind);
1348  return m_TokenTree->at(foundIdx);
1349 }
1350 
1352 {
1353  TRACE(_T("GetTokenBaseType() : Searching within m_Str='%s'"), m_Str.wx_str());
1354 
1355  // Compensate for spaces between namespaces (e.g. NAMESPACE :: SomeType)
1356  // which is valid C++ construct.
1357  // Also, spaces that follow a semicolon are removed.
1358  int pos = 0;
1359  while (pos < static_cast<int>(m_Str.Length()))
1360  {
1361  if ( wxIsspace(m_Str.GetChar(pos))
1362  && ( ( (pos > 0)
1363  && (m_Str.GetChar(pos - 1) == ParserConsts::colon_chr) )
1364  || ( (pos < static_cast<int>(m_Str.Length()) - 1)
1365  && (m_Str.GetChar(pos + 1) == ParserConsts::colon_chr) ) ) )
1366  {
1367  m_Str.Remove(pos, 1);
1368  }
1369  else
1370  ++pos;
1371  }
1372 
1373  TRACE(_T("GetTokenBaseType() : Compensated m_Str='%s'"), m_Str.wx_str());
1374 
1375  // TODO (Morten#5#): Handle stuff like the following gracefully:
1376  // int __cdecl __MINGW_NOTHROW vscanf (const char * __restrict__, __VALIST);
1377 
1378  // m_Str contains the full text before the token's declaration
1379  // an example, for a variable Token: "const wxString& s;"
1380  // m_Str would be: const wxString&
1381  // what we do here is locate the actual return value (wxString in this example)
1382  // it will be needed by code completion code ;)
1383  // Note that generally the returned type string is the identifier like token near the variable
1384  // name, there may be some exceptions. E.g. "wxString const &s;", here, "const" should not be
1385  // returned as a type name.
1386 
1387  pos = m_Str.Length() - 1; // search start at the end of m_Str
1388 
1389  while (pos >= 0)
1390  {
1391  // we walk m_Str backwards until we find a non-space character which also is
1392  // not * or &
1393  // const wxString&
1394  // in this example, we would stop here ^
1395  while ( (pos >= 0)
1396  && ( wxIsspace(m_Str.GetChar(pos))
1397  || (m_Str.GetChar(pos) == ParserConsts::ptr_chr)
1398  || (m_Str.GetChar(pos) == ParserConsts::ref_chr)) )
1399  {
1400  --pos;
1401  }
1402 
1403  if (pos >= 0)
1404  {
1405  // we have the end of the word we're interested in
1406  int end = pos;
1407 
1408  // continue walking backwards until we find the start of the word
1409  // const wxString&
1410  // in this example, we would stop here ^
1411  while ( (pos >= 0)
1412  && ( wxIsalnum(m_Str.GetChar(pos))
1414  || (m_Str.GetChar(pos) == ParserConsts::colon_chr)) )
1415  {
1416  --pos;
1417  }
1418  wxString typeCandidate = m_Str.Mid(pos + 1, end - pos);
1419  // "const" should not be returned as a type name, so we try next candidate.
1420  if (typeCandidate.IsSameAs(ParserConsts::kw_const))
1421  continue;
1422 
1423  TRACE(_T("GetTokenBaseType() : Found '%s'"), typeCandidate.wx_str());
1424  return typeCandidate;
1425  }
1426  }
1427 
1428  TRACE(_T("GetTokenBaseType() : Returning '%s'"), m_Str.wx_str());
1429  return m_Str; // token ends at start of phrase
1430 }
1431 
1432 Token* ParserThread::FindTokenFromQueue(std::queue<wxString>& q, Token* parent, bool createIfNotExist,
1433  Token* parentIfCreated)
1434 {
1435  if (q.empty())
1436  return 0;
1437 
1438  wxString ns = q.front();
1439  q.pop();
1440 
1441  Token* result = TokenExists(ns, parent, tkNamespace | tkClass);
1442 
1443  // if we can't find one in global namespace, then we check the local parent
1444  if (!result && parent == 0)
1445  {
1446  result = TokenExists(ns, parentIfCreated, tkNamespace | tkClass);
1447  }
1448 
1449  if (!result && createIfNotExist)
1450  {
1451  result = new Token(ns, m_FileIdx, 0, ++m_TokenTree->m_TokenTicketCount);
1452  result->m_TokenKind = q.empty() ? tkClass : tkNamespace;
1453  result->m_IsLocal = m_IsLocal;
1454  result->m_ParentIndex = parentIfCreated ? parentIfCreated->m_Index : -1;
1455  int newidx = m_TokenTree->insert(result);
1456  if (parentIfCreated)
1457  parentIfCreated->AddChild(newidx);
1458 
1459  TRACE(_T("FindTokenFromQueue() : Created unknown class/namespace %s (%d) under %s (%d)"),
1460  ns.wx_str(),
1461  newidx,
1462  parent ? parent->m_Name.wx_str() : _T("<globals>"),
1463  parent ? parent->m_Index : -1);
1464  }
1465 
1466  if (q.empty())
1467  return result;
1468 
1469  if (result)
1470  result = FindTokenFromQueue(q, result, createIfNotExist, parentIfCreated);
1471 
1472  return result;
1473 }
1474 
1476  const wxString& name,
1477  int line,
1478  int implLineStart,
1479  int implLineEnd,
1480  const wxString& args,
1481  bool isOperator,
1482  bool isImpl)
1483 {
1484  if (name.IsEmpty())
1485  {
1486  TRACE(_T("DoAddToken() : Token name is empty!"));
1487  return 0; // oops!
1488  }
1489 
1490  Token* newToken = 0;
1491  wxString newname(name);
1492  m_Str.Trim(true).Trim(false);
1493  if (kind == tkDestructor)
1494  {
1495  // special class destructors case
1496  newname.Prepend(ParserConsts::tilde);
1497  m_Str.Clear();
1498  }
1499 
1500  wxString baseArgs;
1501  if (kind & tkAnyFunction)
1502  {
1503  if ( !GetBaseArgs(args, baseArgs) )
1504  kind = tkVariable;
1505  }
1506 
1507  Token* localParent = 0;
1508 
1509  // preserve m_EncounteredTypeNamespaces; needed further down this function
1510  std::queue<wxString> q = m_EncounteredTypeNamespaces;
1511  if ((kind == tkDestructor || kind == tkConstructor) && !q.empty())
1512  {
1513  // look in m_EncounteredTypeNamespaces
1514  localParent = FindTokenFromQueue(q, 0, true, m_LastParent);
1515  if (localParent)
1516  newToken = TokenExists(newname, baseArgs, localParent, kind);
1517  if (newToken)
1518  { TRACE(_T("DoAddToken() : Found token (ctor/dtor).")); }
1519  }
1520 
1521  // check for implementation member function
1522  if (!newToken && !m_EncounteredNamespaces.empty())
1523  {
1524  localParent = FindTokenFromQueue(m_EncounteredNamespaces, 0, true, m_LastParent);
1525  if (localParent)
1526  newToken = TokenExists(newname, baseArgs, localParent, kind);
1527  if (newToken)
1528  {
1529  TRACE(_T("DoAddToken() : Found token (member function)."));
1530  // Special handling function implementation here, a function declaration and its
1531  // function implementation share one Token. But the function implementation's arguments
1532  // should take precedence, as they will be used for code-completion.
1533  if (isImpl && (kind & tkAnyFunction))
1534  newToken->m_Args = args;
1535  }
1536  }
1537 
1538  // none of the above; check for token under parent
1539  if (!newToken)
1540  {
1541  newToken = TokenExists(newname, baseArgs, m_LastParent, kind);
1542  if (newToken)
1543  {
1544  TRACE(_T("DoAddToken() : Found token (parent)."));
1545  // Special handling function implementation, see comments above
1546  if (isImpl && (kind & tkAnyFunction))
1547  newToken->m_Args = args;
1548  }
1549  }
1550 
1551  // need to check if the current token already exists in the tokenTree
1552  // if newToken is valid (non zero), it points to a Token with same kind and same name, so there
1553  // is a chance we can update the existing Token and not create a new one. This usually happens
1554  // we are reparsing a header file, but some class definition Token is shared with an implementation
1555  // file, so the Token can be updated.
1556  // In some special cases, the a new Token instance is need. E.g. token's template argument is
1557  // checked to support template specialization
1558  // eg: template<typename T> class A {...} and template<> class A<int> {...}
1559  // we record them as different tokens
1560  if ( newToken
1561  && (newToken->m_TemplateArgument == m_TemplateArgument)
1562  && ( kind & tkAnyFunction
1563  || newToken->m_Args == args
1564  || kind & tkAnyContainer ) )
1565  {
1566  ; // nothing to do
1567  }
1568  else
1569  {
1570  newToken = new Token(newname, m_FileIdx, line, ++m_TokenTree->m_TokenTicketCount);
1571  TRACE(_T("DoAddToken() : Created token='%s', file_idx=%u, line=%d, ticket=%lu"), newname.wx_str(),
1572  m_FileIdx, line, static_cast<unsigned long>(m_TokenTree->m_TokenTicketCount));
1573 
1574  Token* finalParent = localParent ? localParent : m_LastParent;
1575  if (kind == tkVariable && m_Options.parentIdxOfBuffer != -1)
1576  finalParent = m_TokenTree->at(m_Options.parentIdxOfBuffer);
1577 
1578  newToken->m_ParentIndex = finalParent ? finalParent->m_Index : -1;
1579  newToken->m_TokenKind = kind;
1580  newToken->m_Scope = m_LastScope;
1581  newToken->m_BaseArgs = baseArgs;
1582 
1583  if (newToken->m_TokenKind == tkClass)
1584  newToken->m_BaseArgs = args; // save template args
1585  else
1586  newToken->m_Args = args;
1587 
1588  int newidx = m_TokenTree->insert(newToken);
1589 
1590  if (finalParent)
1591  finalParent->AddChild(newidx);
1592  }
1593 
1594  if (!(kind & (tkConstructor | tkDestructor)))
1595  {
1596  wxString tokenFullType = m_Str;
1597  if (!m_PointerOrRef.IsEmpty())
1598  {
1599  tokenFullType << m_PointerOrRef;
1600  m_PointerOrRef.Clear();
1601  }
1602  wxString tokenBaseType = GetTokenBaseType();
1603  if (tokenBaseType.Find(ParserConsts::space_chr) == wxNOT_FOUND)
1604  {
1605  // token type must contain all namespaces
1606  wxString prepend;
1607 
1608  // Notice: clears the queue "m_EncounteredTypeNamespaces", too
1609  while (!m_EncounteredTypeNamespaces.empty())
1610  {
1611  prepend << m_EncounteredTypeNamespaces.front() << ParserConsts::dcolon;
1613  }
1614 
1615  TRACE(_T("DoAddToken() : Prepending '%s'"), prepend.wx_str());
1616  tokenBaseType.Prepend(prepend);
1617  }
1618  newToken->m_FullType = tokenFullType;
1619  newToken->m_BaseType = tokenBaseType;
1620  }
1621 
1622  newToken->m_IsLocal = m_IsLocal;
1623  newToken->m_IsTemp = m_Options.isTemp;
1624  newToken->m_IsOperator = isOperator;
1625 
1626  if (!isImpl)
1627  {
1628  newToken->m_FileIdx = m_FileIdx;
1629  newToken->m_Line = line;
1630  }
1631  else
1632  {
1633  newToken->m_ImplFileIdx = m_FileIdx;
1634  newToken->m_ImplLine = line;
1635  newToken->m_ImplLineStart = implLineStart;
1636  newToken->m_ImplLineEnd = implLineEnd;
1638  }
1639 
1640  // this will append the doxygen style comments to the Token
1641  m_Tokenizer.SetLastTokenIdx(newToken->m_Index);
1642 
1643  TRACE(_T("DoAddToken() : Added/updated token '%s' (%d), kind '%s', type '%s', actual '%s'. Parent is %s (%d)"),
1644  name.wx_str(), newToken->m_Index, newToken->GetTokenKindString().wx_str(), newToken->m_FullType.wx_str(),
1645  newToken->m_BaseType.wx_str(), m_TokenTree->at(newToken->m_ParentIndex) ?
1647  newToken->m_ParentIndex);
1648  ADDTOKEN(_T("Token: Index %7d Line %7d: Type: %s: -> '%s'"),
1649  newToken->m_Index, line, newToken->GetTokenKindString().wx_str(), name.wx_str());
1650 
1651  // Notice: clears the queue "m_EncounteredTypeNamespaces"
1652  while (!m_EncounteredTypeNamespaces.empty())
1654 
1655  // Notice: clears the queue "m_EncounteredNamespaces"
1656  while (!m_EncounteredNamespaces.empty())
1658 
1659  return newToken;
1660 }
1661 
1663 {
1664  wxString filename;
1665  bool isGlobal = !m_IsLocal;
1666  wxString token = m_Tokenizer.GetToken();
1667 
1668  // now token holds something like:
1669  // "someheader.h"
1670  // < and will follow iostream.h, >
1671  if (!token.IsEmpty())
1672  {
1673  if (token.GetChar(0) == '"')
1674  {
1675  // "someheader.h"
1676  // don't use wxString::Replace(); it's too costly
1677  size_t pos = 0;
1678  while (pos < token.Length())
1679  {
1680  wxChar c = token.GetChar(pos);
1681  if (c != _T('"'))
1682  filename << c;
1683  ++pos;
1684  }
1685  }
1686  else if (token.GetChar(0) == ParserConsts::lt_chr)
1687  {
1688  isGlobal = true;
1689  // next token is filename, next is '.' (dot), next is extension
1690  // basically we'll loop until '>' (gt)
1691  while (IS_ALIVE)
1692  {
1693  token = m_Tokenizer.GetToken();
1694  if (token.IsEmpty())
1695  break;
1696  if (token.GetChar(0) != ParserConsts::gt_chr)
1697  filename << token;
1698  else
1699  break;
1700  }
1701  }
1702  }
1703 
1705  return;
1706 
1707  if (!filename.IsEmpty())
1708  {
1709  TRACE(_T("HandleIncludes() : Found include file '%s'"), filename.wx_str());
1710  do
1711  {
1712  // setting all #includes as global
1713  // it's amazing how many projects use #include "..." for global headers (MSVC mainly - booh)
1714  isGlobal = true;
1715 
1717  {
1718  TRACE(_T("HandleIncludes() : File '%s' not requested to parse after checking options, skipping"), filename.wx_str());
1719  break; // Nothing to do!
1720  }
1721 
1722  wxString real_filename = m_Parent->GetFullFileName(m_Filename, filename, isGlobal);
1723  // Parser::GetFullFileName is thread-safe :)
1724 
1725  if (real_filename.IsEmpty())
1726  {
1727  TRACE(_T("HandleIncludes() : File '%s' not found, skipping"), filename.wx_str());
1728  break; // File not found, do nothing.
1729  }
1730 
1731  if (m_TokenTree->IsFileParsed(real_filename))
1732  {
1733  TRACE(_T("HandleIncludes() : File '%s' is already being parsed, skipping"), real_filename.wx_str());
1734  break; // Already being parsed elsewhere
1735  }
1736 
1737  TRACE(_T("HandleIncludes() : Adding include file '%s'"), real_filename.wx_str());
1738  m_Parent->ParseFile(real_filename, isGlobal, true);
1739  }
1740  while (false);
1741  }
1742 }
1743 
1745 {
1746  wxString ns = m_Tokenizer.GetToken();
1747  int line = m_Tokenizer.GetLineNumber();
1748 
1749  if (ns == ParserConsts::opbrace)
1750  {
1751  // parse inside anonymous namespace
1752  Token* lastParent = m_LastParent;
1753  TokenScope lastScope = m_LastScope;
1754 
1755  DoParse();
1756 
1757  m_LastParent = lastParent;
1758  m_LastScope = lastScope;
1759  }
1760  else
1761  {
1762 
1763  while (true)
1764  {
1765  // for namespace aliases to be parsed, we need to tell the tokenizer
1766  // not to skip the usually unwanted tokens. One of those tokens is the
1767  // "assignment" (=).
1768  // we just have to remember to revert this setting below, or else problems will follow
1770 
1771  wxString next = m_Tokenizer.PeekToken(); // named namespace
1772  if (next==ParserConsts::opbrace)
1773  {
1775 
1776  // use the existing copy (if any)
1777  Token* newToken = TokenExists(ns, m_LastParent, tkNamespace);
1778  if (!newToken)
1779  newToken = DoAddToken(tkNamespace, ns, line);
1780  if (!newToken)
1781  {
1782  TRACE(_T("HandleNamespace() : Unable to create/add new token: ") + ns);
1783  return;
1784  }
1785 
1786  m_Tokenizer.GetToken(); // eat {
1787  int lineStart = m_Tokenizer.GetLineNumber();
1788 
1789  Token* lastParent = m_LastParent; // save status, will restore after DoParse()
1790  TokenScope lastScope = m_LastScope;
1791 
1792  m_LastParent = newToken;
1793  // default scope is: public for namespaces (actually no, but emulate it)
1795 
1796  DoParse();
1797 
1798  m_LastParent = lastParent;
1799  m_LastScope = lastScope;
1800 
1801  // update implementation file and lines of namespace.
1802  // this doesn't make much sense because namespaces are all over the place,
1803  // but do it anyway so that buffer-based parsing returns the correct values.
1804  newToken->m_ImplFileIdx = m_FileIdx;
1805  newToken->m_ImplLine = line;
1806  newToken->m_ImplLineStart = lineStart;
1807  newToken->m_ImplLineEnd = m_Tokenizer.GetLineNumber();
1808 
1809  // the namespace body is correctly parsed
1810  break;
1811  }
1812  else if (next==ParserConsts::equals)
1813  {
1814  // namespace alias; example from cxxabi.h:
1815  //
1816  // namespace __cxxabiv1
1817  // {
1818  // ...
1819  // }
1820  // namespace abi = __cxxabiv1; <-- we 're in this case now
1821 
1822  m_Tokenizer.GetToken(); // eat '='
1824 
1825  Token* lastParent = m_LastParent;
1826  Token* aliasToken = NULL;
1827 
1828  while (IS_ALIVE)
1829  {
1830  wxString aliasStr = m_Tokenizer.GetToken();
1831 
1832  // use the existing copy (if any)
1833  aliasToken = TokenExists(aliasStr, m_LastParent, tkNamespace);
1834  if (!aliasToken)
1835  aliasToken = DoAddToken(tkNamespace, aliasStr, line);
1836  if (!aliasToken)
1837  return;
1838 
1840  {
1842  m_LastParent = aliasToken;
1843  }
1844  else
1845  break;
1846  }
1847 
1848  aliasToken->m_Aliases.Add(ns);
1849  m_LastParent = lastParent;
1850 
1851  // the namespace alias statement is correctly parsed
1852  break;
1853  }
1854  else
1855  {
1857  // probably some kind of error in code ?
1859 
1860  // in case of the code:
1861  //
1862  // # define _GLIBCXX_VISIBILITY(V) _GLIBCXX_PSEUDO_VISIBILITY(V)
1863  // namespace std _GLIBCXX_VISIBILITY(default)
1864  // {
1865  // class vector
1866  // {
1867  // size_t size();
1868  // }
1869  // }
1870  // we still want to parse the body of the namespace, but skip the tokens before "{"
1872  wxString peek = m_Tokenizer.PeekToken();
1873  if(peek == ParserConsts::opbrace)
1874  continue;
1875  else
1876  break;
1877  }
1878  } // while(true)
1879  }
1880 }
1881 
1883 {
1884  // need to force the tokenizer _not_ skip anything
1885  // as we 're manually parsing class decls
1886  // don't forget to reset that if you add any early exit condition!
1887  TokenizerState oldState = m_Tokenizer.GetState();
1889 
1890  int lineNr = m_Tokenizer.GetLineNumber();
1891  wxString ancestors;
1892  wxString lastCurrent;
1893  while (IS_ALIVE)
1894  {
1895  wxString current = m_Tokenizer.GetToken(); // class name
1896  wxString next = m_Tokenizer.PeekToken();
1897 
1898  // remove __attribute__ or __declspec qualifiers
1899  if (current == ParserConsts::kw_attribute || current == ParserConsts::kw_declspec)
1900  {
1901  TRACE(_T("HandleClass() : Skip __attribute__ or __declspec"));
1902 
1903  // Handle stuff like: __attribute__(( whatever ))
1904  m_Tokenizer.GetToken(); // eat __attribute__
1905  current = m_Tokenizer.GetToken(); // eat (( whatever ))
1906  next = m_Tokenizer.PeekToken(); // peek again
1907  }
1908 
1909  TRACE(_T("HandleClass() : Found class '%s', next='%s'"), current.wx_str(), next.wx_str());
1910 
1911  if (current.IsEmpty() || next.IsEmpty())
1912  break;
1913 
1914  // -------------------------------------------------------------------
1915  if (next == ParserConsts::lt) // template specialization
1916  // -------------------------------------------------------------------
1917  {
1918  // eg: template<> class A<int> {...}, then we update template argument with "<int>"
1919  GetTemplateArgs();
1920  next = m_Tokenizer.PeekToken();
1921  }
1922 
1923  // -------------------------------------------------------------------
1924  if (next == ParserConsts::colon) // has ancestor(s)
1925  // -------------------------------------------------------------------
1926  {
1927  TRACE(_T("HandleClass() : Class '%s' has ancestors"), current.wx_str());
1928  m_Tokenizer.GetToken(); // eat ":"
1929  while (IS_ALIVE)
1930  {
1931  wxString tmp = m_Tokenizer.GetToken();
1932  next = m_Tokenizer.PeekToken();
1933  // -----------------------------------------------------------
1934  if ( tmp == ParserConsts::kw_public
1935  || tmp == ParserConsts::kw_protected
1936  || tmp == ParserConsts::kw_private )
1937  // -----------------------------------------------------------
1938  {
1939  continue;
1940  }
1941 
1942  // -----------------------------------------------------------
1943  if (!(tmp == ParserConsts::comma || tmp == ParserConsts::gt))
1944  // -----------------------------------------------------------
1945  {
1946  // fix for namespace usage in ancestors
1947  if (tmp == ParserConsts::dcolon || next == ParserConsts::dcolon)
1948  ancestors << tmp;
1949  else
1950  ancestors << tmp << ParserConsts::comma_chr;
1951  TRACE(_T("HandleClass() : Adding ancestor ") + tmp);
1952  }
1953 
1954  // -----------------------------------------------------------
1955  if ( next.IsEmpty()
1956  || next == ParserConsts::opbrace
1957  || next == ParserConsts::semicolon )
1958  // -----------------------------------------------------------
1959  {
1960  break;
1961  }
1962  // -----------------------------------------------------------
1963  else if (next == ParserConsts::lt)
1964  // -----------------------------------------------------------
1965  {
1966  // template class
1967  //m_Tokenizer.GetToken(); // reach "<"
1968  // must not "eat" the token,
1969  // SkipAngleBraces() will do it to see what it must match
1970  SkipAngleBraces();
1971  // also need to 'unget' the last token (>)
1972  // so next iteration will see the { or ; in 'next'
1974  }
1975  }
1976  TRACE(_T("HandleClass() : Ancestors: ") + ancestors);
1977  }
1978 
1979  // -------------------------------------------------------------------
1980  if (current == ParserConsts::opbrace) // unnamed class/struct/union
1981  // -------------------------------------------------------------------
1982  {
1983  wxString unnamedTmp;
1984  unnamedTmp.Printf(_T("%s%s%u_%lu"),
1985  g_UnnamedSymbol.wx_str(),
1986  (ct == ctClass ? _T("Class") : (ct == ctUnion ? _T("Union") : _T("Struct"))),
1987  m_FileIdx, static_cast<unsigned long>(m_StructUnionUnnamedCount++));
1988  Token* newToken = DoAddToken(tkClass, unnamedTmp, lineNr);
1989  // Maybe it is a bug here. I just fixed it.
1990  if (!newToken)
1991  {
1992  TRACE(_T("HandleClass() : Unable to create/add new token: ") + unnamedTmp);
1993 
1994  // restore tokenizer's functionality
1995  m_Tokenizer.SetState(oldState);
1996  return;
1997  }
1998 
2000  wxArrayString formals;
2002 #ifdef CC_PARSER_TEST
2003  for (size_t i = 0; i < formals.GetCount(); ++i)
2004  TRACE(_T("The template formal arguments are '%s'."), formals[i].wx_str());
2005 #endif
2006  newToken->m_TemplateType = formals;
2008 
2009  Token* lastParent = m_LastParent;
2010  TokenScope lastScope = m_LastScope;
2011  bool parsingTypedef = m_ParsingTypedef;
2012 
2013  m_LastParent = newToken;
2014  // default scope is: private for classes, public for structs, public for unions
2015  m_LastScope = ct == ctClass ? tsPrivate : tsPublic;
2016  m_ParsingTypedef = false;
2017 
2018  newToken->m_ImplLine = lineNr;
2020 
2021  newToken->m_IsAnonymous = true;
2022 
2023  DoParse(); // recursion
2024 
2025  m_LastParent = lastParent;
2026  m_LastScope = lastScope;
2027  m_ParsingTypedef = parsingTypedef;
2028 
2029  m_LastUnnamedTokenName = unnamedTmp; // used for typedef'ing anonymous class/struct/union
2030 
2031  // we should now be right after the closing brace
2032  // no vars are defined on a typedef, only types
2033  // In the former example, aa is not part of the typedef.
2034  if (m_ParsingTypedef)
2035  {
2036  m_Str.Clear();
2037  TRACE(_T("HandleClass() : Unable to create/add new token: ") + current);
2038  if ( !ReadClsNames(newToken->m_Name) )
2039  { TRACE(_T("HandleClass() : ReadClsNames returned false [1].")); }
2040  break;
2041  }
2042  else
2043  {
2044  m_Str = newToken->m_Name;
2045  if ( !ReadVarNames() )
2046  { TRACE(_T("HandleClass() : ReadVarNames returned false [1].")); }
2047  m_Str.Clear();
2048  break;
2049  }
2050  }
2051  // -------------------------------------------------------------------
2052  else if (next == ParserConsts::opbrace)
2053  // -------------------------------------------------------------------
2054  {
2055  // for a template class definition like
2056  // template <typename x, typename y>class AAA : public BBB, CCC {;}
2057  // we would like to show its ancestors and template formal parameters on the tooltip,
2058  // so we re-used the m_Args member to store those informations, the tooltip shows like:
2059  // class AAA<x,y> : BBB, CCC {...} instead of class AAA {...}
2060  wxStringTokenizer tkz(ancestors, ParserConsts::comma);
2061  wxString args;
2062  while (tkz.HasMoreTokens())
2063  {
2064  const wxString& ancestor = tkz.GetNextToken();
2065  if (ancestor.IsEmpty())
2066  continue;
2067  if (args.IsEmpty())
2069  else
2070  args += ParserConsts::comma;
2071  args += ParserConsts::space + ancestor;
2072  }
2073  wxArrayString formals;
2075  if (!formals.IsEmpty())
2077 
2078  Token* newToken = DoAddToken(tkClass, current, lineNr, 0, 0, args);
2079  if (!newToken)
2080  {
2081  TRACE(_T("HandleClass() : Unable to create/add new token: ") + current);
2082 
2083  // restore tokenizer's functionality
2084  m_Tokenizer.SetState(oldState);
2085  return;
2086  }
2087  newToken->m_AncestorsString = ancestors;
2088 
2089  m_Tokenizer.GetToken(); // eat {
2090 
2091  Token* lastParent = m_LastParent; // save status, and will restore after DoParse()
2092  TokenScope lastScope = m_LastScope;
2093  bool parsingTypedef = m_ParsingTypedef;
2094 
2095  m_LastParent = newToken;
2096  // default scope is: private for classes, public for structs, public for unions
2097  m_LastScope = ct == ctClass ? tsPrivate : tsPublic;
2098  m_ParsingTypedef = false;
2099 
2100  newToken->m_ImplLine = lineNr;
2102 
2104 
2105 #ifdef CC_PARSER_TEST
2106  for (size_t i = 0; i < formals.GetCount(); ++i)
2107  TRACE(_T("The template formal arguments are '%s'."), formals[i].wx_str());
2108 #endif
2109  newToken->m_TemplateType = formals;
2111 
2112  DoParse();
2113 
2114  newToken->m_ImplLineEnd = m_Tokenizer.GetLineNumber();
2115 
2116  m_ParsingTypedef = parsingTypedef;
2117  m_LastParent = lastParent;
2118  m_LastScope = lastScope;
2119 
2120  // we should now be right after the closing brace
2121  // no vars are defined on a typedef, only types
2122  // In the former example, aa is not part of the typedef.
2123  if (m_ParsingTypedef)
2124  {
2125  m_Str.Clear();
2126  if ( !ReadClsNames(newToken->m_Name) )
2127  { TRACE(_T("HandleClass() : ReadClsNames returned false [2].")); }
2128  break;
2129  }
2130  else
2131  {
2132  m_Str = newToken->m_Name; // pattern: class A{} b; b is a variable
2133  if ( !ReadVarNames() )
2134  { TRACE(_T("HandleClass() : ReadVarNames returned false [2].")); }
2135  m_Str.Clear();
2136  break;
2137  }
2138  }
2139  // -------------------------------------------------------------------
2140  else if (next == ParserConsts::semicolon)
2141  // -------------------------------------------------------------------
2142  {
2143  // e.g. struct A {}; struct B { struct A a; };
2144  if ( m_LastParent
2146  && !lastCurrent.IsEmpty() )
2147  {
2148  m_Str << lastCurrent << ParserConsts::space_chr;
2150  break;
2151  }
2152  else
2153  break; // forward decl; we don't care
2154  }
2155  // -------------------------------------------------------------------
2156  else if (next.GetChar(0) == ParserConsts::opbracket_chr) // function: struct xyz& DoSomething()...
2157  // -------------------------------------------------------------------
2158  {
2159  HandleFunction(current);
2160  break;
2161  }
2162  // -------------------------------------------------------------------
2163  else if ( (next.GetChar(0) == ParserConsts::ptr_chr)
2164  || (next.GetChar(0) == ParserConsts::ref_chr) )
2165  // -------------------------------------------------------------------
2166  {
2167  // e.g. typedef struct A * a;
2169  {
2170  wxString args;
2171 
2172  Token* newToken = DoAddToken(tkClass, current, lineNr, 0, 0, args);
2173 
2174  if (!newToken)
2175  {
2176  TRACE(_T("HandleClass() : Unable to create/add new token: ") + current);
2177 
2178  // restore tokenizer's functionality
2179  m_Tokenizer.SetState(oldState);
2180  return;
2181  }
2182  newToken->m_AncestorsString = ancestors;
2183 
2185 
2186  m_Str.Clear();
2187  if ( !ReadClsNames(newToken->m_Name) )
2188  {
2189  TRACE(_T("HandleClass() : ReadClsNames returned false [2]."));
2190  }
2191 
2192  break;
2193  }
2194  else
2195  m_Str << current;
2196  break;
2197  }
2198  // -------------------------------------------------------------------
2199  else if(next == ParserConsts::equals)
2200  // -------------------------------------------------------------------
2201  {
2202  // some patterns like: struct AAA a = {.x = 1, .y=2};
2203  // In (ANSI) C99, you can use a designated initializer to initialize a structure
2204  if (!lastCurrent.IsEmpty() )
2205  {
2206  m_Str << lastCurrent << ParserConsts::space_chr;
2208  }
2209  // so we have to eat the brace pair
2210  SkipToOneOfChars(ParserConsts::semicolon, /* supportNesting*/ true, /*singleCharToken*/ true);
2211  break;
2212  }
2213  // -------------------------------------------------------------------
2214  else
2215  // -------------------------------------------------------------------
2216  {
2217  // might be instantiation, see the following
2218  // e.g. struct HiddenStruct { int val; }; struct HiddenStruct yy;
2219  if (m_ParsingTypedef)
2220  {
2222  break;
2223  }
2224  if (TokenExists(current, m_LastParent, tkClass))
2225  {
2226  if (!TokenExists(next, m_LastParent, tkVariable))
2227  {
2228  wxString farnext;
2229 
2230  m_Tokenizer.GetToken(); // go ahead of identifier
2231  farnext = m_Tokenizer.PeekToken();
2232 
2233  if (farnext == ParserConsts::semicolon)
2234  {
2235  if (m_Options.handleVars)
2236  {
2237  m_Str = current;
2239  m_Str.Clear();
2240  }
2241 
2242  m_Tokenizer.GetToken(); // eat semi-colon
2243  break;
2244  }
2245  else
2246  m_Tokenizer.UngetToken(); // restore the identifier
2247  }
2248  }
2249  }
2250  lastCurrent = current;
2251  }
2252 
2253  // restore tokenizer's functionality
2254  m_Tokenizer.SetState(oldState);
2255 }
2256 
2257 void ParserThread::HandleFunction(wxString& name, bool isOperator, bool isPointer)
2258 {
2259  TRACE(_T("HandleFunction() : Adding function '")+name+_T("': m_Str='")+m_Str+_T("'"));
2260  int lineNr = m_Tokenizer.GetLineNumber();
2261  wxString args = m_Tokenizer.GetToken();
2262  wxString peek = m_Tokenizer.PeekToken();
2263  TRACE(_T("HandleFunction() : name='")+name+_T("', args='")+args+_T("', peek='")+peek+_T("'"));
2264 
2265  // NOTE: Avoid using return, because m_Str needs to be cleared
2266  // at the end of this function.
2267 
2268  // special case for function pointers
2269  if (isPointer)
2270  {
2271  int pos = name.find(ParserConsts::ptr);
2272 
2273  // pattern: m_Str AAA (*BBB) (...);
2274  // pattern: m_Str AAA (*BBB) (...) = some_function;
2275  if (pos != wxNOT_FOUND && ( peek == ParserConsts::semicolon
2276  || peek == ParserConsts::equals
2277  || peek == ParserConsts::comma))
2278  {
2279  name.RemoveLast(); // remove ")"
2280  name.Remove(0, pos+1).Trim(false); // remove "(* "
2281 
2282  // pattern: m_Str AAA (*BBB[X][Y]) (...);
2283  // Trim(true) for safety, in case the name contains a trailing space
2284  pos = name.find(ParserConsts::oparray_chr);
2285  if (pos != wxNOT_FOUND)
2286  name.Remove(pos).Trim(true);
2287 
2288  TRACE(_T("HandleFunction() : Add token name='")+name+_T("', args='")+args+_T("', return type='") + m_Str+ _T("'"));
2289  Token* newToken = DoAddToken(tkFunction, name, lineNr, 0, 0, args);
2290  if (newToken)
2291  {
2292  newToken->m_IsConst = false;
2294  if (!m_TemplateArgument.IsEmpty() && newToken->m_TemplateMap.empty())
2295  ResolveTemplateArgs(newToken);
2296  }
2297  else
2298  {
2299  TRACE(_T("HandleFunction() : Unable to create/add new token: ") + name);
2300  }
2302  }
2303  }
2305  {
2306  int lineStart = 0;
2307  int lineEnd = 0;
2308  bool isCtor = m_Str.IsEmpty();
2309  bool isDtor = m_Str.StartsWith(ParserConsts::tilde);
2310  Token* localParent = 0;
2311 
2312  if ((isCtor || isDtor) && !m_EncounteredTypeNamespaces.empty())
2313  {
2314  // probably a ctor/dtor
2315  std::queue<wxString> q = m_EncounteredTypeNamespaces; // preserve m_EncounteredTypeNamespaces; needed in DoAddToken()
2316  localParent = FindTokenFromQueue(q, m_LastParent);
2317 
2318  TRACE(_T("HandleFunction() : Ctor/Dtor '%s', m_Str='%s', localParent='%s'"),
2319  name.wx_str(),
2320  m_Str.wx_str(),
2321  localParent ? localParent->m_Name.wx_str() : _T("<none>"));
2322  }
2323  else
2324  {
2325  std::queue<wxString> q = m_EncounteredNamespaces; // preserve m_EncounteredNamespaces; needed in DoAddToken()
2326  localParent = FindTokenFromQueue(q, m_LastParent);
2327 
2328  TRACE(_T("HandleFunction() : !(Ctor/Dtor) '%s', m_Str='%s', localParent='%s'"),
2329  name.wx_str(),
2330  m_Str.wx_str(),
2331  localParent ? localParent->m_Name.wx_str() : _T("<none>"));
2332  }
2333 
2334  bool isCtorOrDtor = m_LastParent && name == m_LastParent->m_Name;
2335 
2336  if (!isCtorOrDtor)
2337  isCtorOrDtor = localParent && name == localParent->m_Name;
2338 
2339  if (!isCtorOrDtor && m_Options.useBuffer)
2340  isCtorOrDtor = isCtor || isDtor;
2341 
2342  TRACE(_T("HandleFunction() : Adding function '%s', ': m_Str='%s', enc_ns='%s'."),
2343  name.wx_str(),
2344  m_Str.wx_str(),
2345  m_EncounteredNamespaces.size() ? m_EncounteredNamespaces.front().wx_str() : wxT("nil"));
2346 
2347  bool isImpl = false;
2348  bool isConst = false;
2349  bool isNoExcept = false;
2350  while (!peek.IsEmpty()) // !eof
2351  {
2352  if (peek == ParserConsts::colon) // probably a ctor with member initializers
2353  {
2355  m_Tokenizer.UngetToken(); // leave brace there
2356  peek = m_Tokenizer.PeekToken();
2357  continue;
2358  }
2359  else if (peek == ParserConsts::opbrace)// function implementation
2360  {
2361  isImpl = true;
2362  m_Tokenizer.GetToken(); // eat {
2363  lineStart = m_Tokenizer.GetLineNumber();
2364  SkipBlock(); // skip to matching }
2365  lineEnd = m_Tokenizer.GetLineNumber();
2366  break;
2367  }
2368  else if ( peek == ParserConsts::clbrace
2369  || peek == ParserConsts::semicolon
2370  || peek == ParserConsts::comma)
2371  break; // function decl
2372  else if (peek == ParserConsts::kw_const)
2373  isConst = true;
2374  else if (peek == ParserConsts::kw_noexcept)
2375  isNoExcept = true;
2376  else if (peek == ParserConsts::kw_throw)
2377  {
2378  // Handle something like: std::string MyClass::MyMethod() throw(std::exception)
2379  wxString arg = m_Tokenizer.GetToken(); // eat args ()
2380  }
2381  else if (peek == ParserConsts::kw_try)
2382  {
2383  // function-try-block pattern: AAA(...)try{}catch{}
2384  m_Tokenizer.GetToken(); // eat the try keyword
2385 
2387  {
2388  // skip ctor initialization list
2390  m_Tokenizer.UngetToken(); // leave brace there
2391  }
2393  {
2394  isImpl = true;
2395  m_Tokenizer.GetToken(); // eat {
2396  lineStart = m_Tokenizer.GetLineNumber();
2397  SkipBlock(); // skip to matching }
2398 
2400  {
2401  m_Tokenizer.GetToken(); // eat catch
2402  m_Tokenizer.GetToken(); // eat catch args
2403 
2405  {
2406  m_Tokenizer.GetToken(); // eat {
2407  SkipBlock(); // skip to matching }
2408  }
2409  }
2410 
2411  lineEnd = m_Tokenizer.GetLineNumber();
2412  break;
2413  }
2414  }
2415  else
2416  {
2417  TRACE(_T("HandleFunction() : Possible macro '%s' in function '%s' (file name='%s', line numer %d)."),
2418  peek.wx_str(), name.wx_str(), m_Filename.wx_str(), m_Tokenizer.GetLineNumber());
2419  break; // darned macros that do not end with a semicolon :/
2420  }
2421 
2422  // if we reached here, eat the token so peek gets a new value
2424  peek = m_Tokenizer.PeekToken();
2425  } // while
2426 
2427  TRACE(_T("HandleFunction() : Add token name='")+name+_T("', args='")+args+_T("', return type='") + m_Str+ _T("'"));
2428  TokenKind tokenKind = !isCtorOrDtor ? tkFunction : (isDtor ? tkDestructor : tkConstructor);
2429  Token* newToken = DoAddToken(tokenKind, name, lineNr, lineStart, lineEnd, args, isOperator, isImpl);
2430  if (newToken)
2431  {
2432  newToken->m_IsConst = isConst;
2433  newToken->m_IsNoExcept = isNoExcept;
2435  if (!m_TemplateArgument.IsEmpty() && newToken->m_TemplateMap.empty())
2436  ResolveTemplateArgs(newToken);
2437  }
2438  else
2439  {
2440  TRACE(_T("HandleFunction() : Unable to create/add new token: ") + name);
2441  }
2443  }
2444 
2445  // NOTE: If we peek an equals or comma, this could be a list of function
2446  // declarations. In that case, don't clear return type (m_Str).
2447  peek = m_Tokenizer.PeekToken();
2448  if (peek != ParserConsts::equals && peek != ParserConsts::comma)
2449  m_Str.Clear();
2450 }
2451 
2453 {
2454  // if these aren't empty at this point, we have a syntax error
2455  if (!m_Str.empty())
2456  return;
2457 
2458  if (!m_PointerOrRef.empty())
2459  return;
2460 
2461  if (!m_TemplateArgument.empty())
2462  return;
2463 
2464  // conditional arguments can look like this:
2465  // (int i = 12)
2466  // (Foo *bar = getFooBar())
2467  // (var <= 12 && (getType() != 23))
2468  wxString args = m_Tokenizer.GetToken();
2469 
2470  // remove braces
2471  if (args.StartsWith(_T("(")))
2472  args = args.Mid(1, args.length() - 1);
2473 
2474  if (args.EndsWith(_T(")")))
2475  args = args.Mid(0, args.length() - 1);
2476 
2477  // parse small tokens inside for loop head
2478  TokenTree tree;
2479  wxString fileName = m_Tokenizer.GetFilename();
2480  Tokenizer smallTokenizer(&tree);
2481 
2482  smallTokenizer.InitFromBuffer(args, fileName, m_Tokenizer.GetLineNumber());
2483 
2484  while (IS_ALIVE)
2485  {
2486  wxString token = smallTokenizer.GetToken();
2487  if (token.empty())
2488  break;
2489 
2490  wxString peek = smallTokenizer.PeekToken();
2491 
2492  if (peek.empty())
2493  {
2494  if (!m_Str.empty())
2495  {
2496  // remove template argument if there is one
2497  wxString varType, templateArgs;
2498  RemoveTemplateArgs(m_Str, varType, templateArgs);
2499 
2500  m_Str = varType;
2501  m_TemplateArgument = templateArgs;
2502 
2503  Token *newToken = DoAddToken(tkVariable, token, smallTokenizer.GetLineNumber());
2504  if (newToken && !m_TemplateArgument.IsEmpty())
2505  ResolveTemplateArgs(newToken);
2506  else
2507  { TRACE(_T("HandleConditionalArguments() : Unable to create/add new token: ") + token); }
2508 
2509  }
2510 
2511  break;
2512  }
2513  else
2514  {
2515  if (token == ParserConsts::ref_chr || token == ParserConsts::ptr_chr)
2516  m_PointerOrRef << token;
2517  else
2518  {
2519  if (!m_Str.empty())
2520  m_Str << _T(" ");
2521 
2522  m_Str << token;
2523  }
2524  }
2525  }
2526 
2527  m_Str.clear();
2530 }
2531 
2533 {
2534  // if these aren't empty at this point, we have a syntax error
2535  if (!m_Str.empty())
2536  return;
2537 
2538  if (!m_PointerOrRef.empty())
2539  return;
2540 
2541  if (!m_TemplateArgument.empty())
2542  return;
2543 
2544  // for loop heads look like this:
2545  // ([init1 [, init2 ...] ] ; [cond1 [, cond2 ..]]; [mod1 [, mod2 ..]])
2546  wxString args = m_Tokenizer.GetToken();
2547 
2548  // remove braces
2549  if (args.StartsWith(_T("(")))
2550  args = args.Mid(1, args.length() - 1);
2551  if (args.EndsWith(_T(")")))
2552  args = args.Mid(0, args.length() - 1);
2553 
2554  // parse small tokens inside for loop head
2555  TokenTree tree;
2556  wxString fileName = m_Tokenizer.GetFilename();
2557  Tokenizer smallTokenizer(&tree);
2558 
2559  smallTokenizer.InitFromBuffer(args, fileName, m_Tokenizer.GetLineNumber());
2560 
2561  while (IS_ALIVE)
2562  {
2563  wxString token = smallTokenizer.GetToken();
2564  if (token.empty())
2565  break;
2566 
2567  // pattern for (; ...)
2568  // the first token is a ';'
2569  if (token == ParserConsts::semicolon)
2570  break;
2571 
2572  wxString peek = smallTokenizer.PeekToken();
2573 
2574  bool createNewToken = false;
2575  bool finished = false;
2576 
2577  // pattern for(int i = 5; ...)
2578  // there is a "=" after the token "i"
2579  if (peek == ParserConsts::equals)
2580  {
2581  // skip to ',' or ';'
2582  while (IS_ALIVE)
2583  {
2584  smallTokenizer.GetToken();
2585 
2586  peek = smallTokenizer.PeekToken();
2587  if (peek == ParserConsts::comma
2588  || peek == ParserConsts::semicolon
2589  || peek.empty())
2590  break;
2591  }
2592  }
2593 
2594  if (peek == ParserConsts::comma)
2595  {
2596  smallTokenizer.GetToken(); // eat comma
2597  createNewToken = true;
2598  }
2599  else if (peek == ParserConsts::colon
2600  || peek == ParserConsts::semicolon
2601  || peek.empty())
2602  {
2603  createNewToken = true;
2604  finished = true; // after this point there will be no further declarations
2605  }
2606  else
2607  {
2608  if (token == ParserConsts::ref_chr || token == ParserConsts::ptr_chr)
2609  m_PointerOrRef << token;
2610  else
2611  {
2612  if (!m_Str.empty())
2613  m_Str << _T(" ");
2614 
2615  m_Str << token;
2616  }
2617  }
2618 
2619  if (createNewToken && !m_Str.empty())
2620  {
2621  // remove template argument if there is one
2622  wxString name, templateArgs;
2623  RemoveTemplateArgs(m_Str, name, templateArgs);
2624 
2625  m_Str = name;
2626  m_TemplateArgument = templateArgs;
2627 
2628  Token *newToken = DoAddToken(tkVariable, token, smallTokenizer.GetLineNumber());
2629  if (newToken && !m_TemplateArgument.IsEmpty())
2630  ResolveTemplateArgs(newToken);
2631  else
2632  { TRACE(_T("HandleForLoopArguments() : Unable to create/add new token: ") + token); }
2633 
2634  }
2635 
2636  if (finished)
2637  break;
2638  }
2639 
2640  m_Str.clear();
2643 }
2644 
2646 {
2647  // enums have the following rough definition:
2648  // enum [xxx] { type1 name1 [= 1][, [type2 name2 [= 2]]] };
2649  bool isUnnamed = false;
2650  bool isEnumClass = false;
2651  int lineNr = m_Tokenizer.GetLineNumber();
2652  wxString token = m_Tokenizer.GetToken();
2653  if (token == ParserConsts::kw_class)
2654  {
2655  token = m_Tokenizer.GetToken();
2656  isEnumClass = true;
2657  }
2658 
2659  if (token.IsEmpty())
2660  return;
2661  else if (token==ParserConsts::opbrace)
2662  {
2663  // we have an un-named enum
2664  if (m_ParsingTypedef)
2665  {
2666  token.Printf(_T("%sEnum%u_%lu"), g_UnnamedSymbol.wx_str(), m_FileIdx, static_cast<unsigned long>(m_EnumUnnamedCount++));
2667  m_LastUnnamedTokenName = token;
2668  }
2669  else
2670  token = g_UnnamedSymbol;
2671  m_Tokenizer.UngetToken(); // return '{' back
2672  isUnnamed = true;
2673  }
2674 
2675  Token* newEnum = 0L;
2676  unsigned int level = 0;
2677  if ( wxIsalpha(token.GetChar(0))
2678  || (token.GetChar(0) == ParserConsts::underscore_chr) )
2679  {
2681  {
2682  if (TokenExists(token, m_LastParent, tkEnum))
2683  {
2685  {
2686  wxString ident = m_Tokenizer.GetToken(); // go ahead of identifier
2687 
2689  {
2690  if (m_Options.handleEnums)
2691  {
2692  m_Str = token;
2694  m_Str.Clear();
2695  }
2696 
2697  m_Tokenizer.GetToken(); // eat semi-colon
2698  }
2699  else
2700  m_Tokenizer.UngetToken(); // restore the identifier
2701  }
2702  }
2703 
2704  return;
2705  }
2706 
2707  if (isUnnamed && !m_ParsingTypedef)
2708  {
2709  // for unnamed enums, look if we already have "Unnamed", so we don't
2710  // add a new one for every unnamed enum we encounter, in this scope...
2711  newEnum = TokenExists(token, m_LastParent, tkEnum);
2712  }
2713 
2714  if (!newEnum) // either named or first unnamed enum
2715  {
2716  newEnum = DoAddToken(tkEnum, token, lineNr);
2717  newEnum->m_IsAnonymous = true;
2718  }
2719 
2720  level = m_Tokenizer.GetNestingLevel();
2721  m_Tokenizer.GetToken(); // skip {
2722  }
2723  else
2724  {
2725  if (token.GetChar(0) != ParserConsts::opbrace_chr)
2726  return;
2727  level = m_Tokenizer.GetNestingLevel() - 1; // we 've already entered the { block
2728  }
2729 
2730  int lineStart = m_Tokenizer.GetLineNumber();
2731  //Implementation for showing Enum values: resolves expressions, preprocessor and enum tokens.
2732  int enumValue = 0;
2733  bool updateValue = true;
2734 
2735  const TokenizerState oldState = m_Tokenizer.GetState();
2737 
2738  while (IS_ALIVE)
2739  {
2740  // process enumerators
2741  token = m_Tokenizer.GetToken();
2742  wxString peek = m_Tokenizer.PeekToken();
2743  if (token.IsEmpty() || peek.IsEmpty())
2744  return; //eof
2745  if (token==ParserConsts::clbrace && level == m_Tokenizer.GetNestingLevel())
2746  break;
2747  // assignments (=xxx) are ignored by the tokenizer,
2748  // so we don't have to worry about them here,
2749  // if (peek==ParserConsts::comma || peek==ParserConsts::clbrace || peek==ParserConsts::colon)
2750  if (peek==ParserConsts::colon)
2751  {
2753  }
2754  if (peek == ParserConsts::equals)
2755  {
2756  m_Tokenizer.GetToken(); //eat '='
2757  long result;
2758  updateValue = false;
2759  if (CalcEnumExpression(newEnum, result, peek))
2760  {
2761  enumValue = result;
2762  updateValue = true;
2763  }
2764  }
2765  if (peek == ParserConsts::comma || peek == ParserConsts::clbrace)
2766  {
2767  // this "if", avoids non-valid enumerators
2768  // like a comma (if no enumerators follow)
2769  if ( wxIsalpha(token.GetChar(0))
2770  || (token.GetChar(0) == ParserConsts::underscore_chr) )
2771  {
2772  wxString args;
2773  if (updateValue)
2774  args << enumValue++;
2775 
2776  Token* lastParent = m_LastParent;
2777  m_LastParent = newEnum;
2778  Token* enumerator = DoAddToken(tkEnumerator, token, m_Tokenizer.GetLineNumber(), 0, 0, args);
2779  enumerator->m_Scope = isEnumClass ? tsPrivate : tsPublic;
2780  m_LastParent = lastParent;
2781  }
2782  }
2783  }
2784 
2785  m_Tokenizer.SetState(oldState);
2786 
2787  newEnum->m_ImplLine = lineNr;
2788  newEnum->m_ImplLineStart = lineStart;
2790 
2791 // // skip to ;
2792 // SkipToOneOfChars(ParserConsts::semicolon);
2793 }
2794 
2795 bool ParserThread::CalcEnumExpression(Token* tokenParent, long& result, wxString& peek)
2796 {
2797  // need to force the tokenizer skip raw expression
2798  const TokenizerState oldState = m_Tokenizer.GetState();
2799  // expand macros, but don't read a single parentheses
2801 
2802  Expression exp;
2803  wxString token, next;
2804 
2805  while (IS_ALIVE)
2806  {
2807  token = m_Tokenizer.GetToken();
2808  if (token.IsEmpty())
2809  return false;
2810  if (token == _T("\\"))
2811  continue;
2812  if (token == ParserConsts::comma || token == ParserConsts::clbrace)
2813  {
2815  peek = token;
2816  break;
2817  }
2818  if (token == ParserConsts::dcolon)
2819  {
2822  exp.Clear();
2823  break;
2824  }
2825 
2826  if (wxIsalpha(token[0]) || token[0] == ParserConsts::underscore_chr) // handle enum or macro
2827  {
2828  const Token* tk = m_TokenTree->at(m_TokenTree->TokenExists(token, tokenParent->m_Index, tkEnumerator));
2829 
2830  if (tk) // the enumerator token
2831  {
2832  if (!tk->m_Args.IsEmpty() && wxIsdigit(tk->m_Args[0]))
2833  token = tk->m_Args; // add the value to exp
2834  }
2835  else
2836  {
2839  exp.Clear();
2840  break;
2841  }
2842  }
2843 
2844  // only remaining number now
2845  if (!token.StartsWith(_T("0x")))
2846  exp.AddToInfixExpression(token);
2847  else
2848  {
2849  long value;
2850  if (token.ToLong(&value, 16))
2851  exp.AddToInfixExpression(wxString::Format(_T("%ld"), value));
2852  else
2853  {
2855  exp.Clear();
2856  break;
2857  }
2858  }
2859  }
2860 
2861  // reset tokenizer's functionality
2862  m_Tokenizer.SetState(oldState);
2863 
2864  exp.ConvertInfixToPostfix();
2865  if (exp.CalcPostfix() && exp.GetStatus())
2866  {
2867  result = exp.GetResult();
2868  return true;
2869  }
2870 
2871  return false;
2872 }
2873 
2875 {
2876  // typedefs are handled as tkClass and we put the typedef'd type as the
2877  // class's ancestor. This way, it will work through inheritance.
2878  // Function pointers are a different beast and are handled differently.
2879 
2880  // this is going to be tough :(
2881  // let's see some examples:
2882  //
2883  // relatively easy:
2884  // typedef unsigned int uint32;
2885  // typedef std::map<String, StringVector> AnimableDictionaryMap;
2886  // typedef class|struct|enum [name] {...} type;
2887  //
2888  // special case of above:
2889  // typedef struct __attribute__((packed)) _PSTRUCT {...} PSTRUCT;
2890  //
2891  // harder:
2892  // typedef void dMessageFunction (int errnum, const char *msg, va_list ap);
2893  //
2894  // even harder:
2895  // typedef void (*dMessageFunction)(int errnum, const char *msg, va_list ap);
2896  // or
2897  // typedef void (MyClass::*Function)(int);
2898 
2899  size_t lineNr = m_Tokenizer.GetLineNumber();
2900  bool is_function_pointer = false;
2901  wxString typ;
2902  std::queue<wxString> components;
2903  // get everything on the same line
2904 
2905  TRACE(_T("HandleTypedef() : Typedef start"));
2906  wxString args;
2907  wxString token;
2908  wxString peek;
2909  m_ParsingTypedef = true;
2910 
2911  while (IS_ALIVE)
2912  {
2913  token = m_Tokenizer.GetToken();
2914  peek = m_Tokenizer.PeekToken();
2915 
2916  TRACE(_T("HandleTypedef() : token=%s, peek=%s"), token.wx_str(), peek.wx_str());
2917  if (token.IsEmpty() || token == ParserConsts::semicolon)
2918  {
2919  m_Tokenizer.UngetToken(); // NOTE: preserve ';' for the next GetToken();
2920  break;
2921  }
2922 
2923  if (token == ParserConsts::kw_const)
2924  continue;
2925 
2926  if ( token == ParserConsts::kw_class
2927  || token == ParserConsts::kw_struct
2928  || token == ParserConsts::kw_union)
2929  {
2930  // "typedef struct|class|union"
2931  TRACE(_("HandleTypedef() : Before HandleClass m_LastUnnamedTokenName='%s'"), m_LastUnnamedTokenName.wx_str());
2933  token == ParserConsts::kw_union ? ctUnion :
2934  ctStructure);
2935  token = m_LastUnnamedTokenName;
2936  TRACE(_("HandleTypedef() : After HandleClass m_LastUnnamedTokenName='%s'"), m_LastUnnamedTokenName.wx_str());
2937  }
2938  else if (token == ParserConsts::ptr || token == ParserConsts::ref)
2939  {
2940  m_PointerOrRef << token;
2941  continue;
2942  }
2943  else if (peek == ParserConsts::comma)
2944  {
2946  if (components.size() != 0)
2947  {
2948  wxString ancestor;
2949  while (components.size() > 0)
2950  {
2951  wxString tempToken = components.front();
2952  components.pop();
2953 
2954  if (!ancestor.IsEmpty())
2955  ancestor << ParserConsts::space_chr;
2956  ancestor << tempToken;
2957  }
2958  if ( !ReadClsNames(ancestor) )
2959  {
2960  TRACE(_T("HandleTypedef() : ReadClsNames returned false."));
2961  m_Tokenizer.GetToken(); // eat it
2962  }
2963  }
2964  }
2965  else if (token == ParserConsts::kw_enum)
2966  {
2967  // "typedef enum"
2968  HandleEnum();
2969  token = m_LastUnnamedTokenName;
2970  }
2971 
2972  // keep namespaces together
2973  while (peek == ParserConsts::dcolon)
2974  {
2975  token << peek;
2976  m_Tokenizer.GetToken(); // eat it
2977  token << m_Tokenizer.GetToken(); // get what's next
2978  peek = m_Tokenizer.PeekToken();
2979  }
2980 
2981  if (token.GetChar(0) == ParserConsts::opbracket_chr)
2982  {
2983  // function pointer (probably)
2984  is_function_pointer = true;
2985  if (peek.GetChar(0) == ParserConsts::opbracket_chr)
2986  {
2987  // typedef void (*dMessageFunction)(int errnum, const char *msg, va_list ap);
2988  // typedef void (MyClass::*Function)(int);
2989 
2990  // remove parentheses and keep everything after the dereferencing symbol
2991  token.RemoveLast();
2992  int pos = token.Find(ParserConsts::ptr_chr, true);
2993  if (pos != wxNOT_FOUND)
2994  {
2996  << token.Mid(1, pos)
2998  token.Remove(0, pos + 1);
2999  }
3000  else
3001  {
3002  typ = _T("(*)");
3003  token.Remove(0, 1); // remove opening parenthesis
3004  }
3005  args = peek;
3006  m_Tokenizer.GetToken(); // eat args
3007 
3008  TRACE(_("HandleTypedef() : Pushing component='%s' (typedef args='%s')"), token.Trim(true).Trim(false).wx_str(), args.wx_str());
3009  components.push(token.Trim(true).Trim(false));
3010  }
3011  else
3012  {
3013  // typedef void dMessageFunction (int errnum, const char *msg, va_list ap);
3014 
3015  // last component is already the name and this is the args
3016  args = token;
3017  TRACE(_("HandleTypedef() : Typedef args='%s'"), args.wx_str());
3018  }
3019  break;
3020  }
3021 
3022  TRACE(_("HandleTypedef() : Pushing component='%s', typedef args='%s'"), token.Trim(true).Trim(false).wx_str(), args.wx_str());
3023  components.push(token.Trim(true).Trim(false));
3024 
3025  // skip templates <>
3026  if (peek == ParserConsts::lt)
3027  {
3028  GetTemplateArgs();
3029  continue;
3030  }
3031 
3032  TRACE(_T(" + '%s'"), token.wx_str());
3033  }
3034  TRACE(_T("HandleTypedef() : Typedef done"));
3035  m_ParsingTypedef = false;
3036 
3037  if (components.empty())
3038  return; // invalid typedef
3039 
3040  if (!is_function_pointer && components.size() <= 1)
3041  return; // invalid typedef
3042 
3043  // now get the type
3044  wxString ancestor;
3045  wxString alias;
3046 
3047  // handle the special cases below, a template type parameter is used in typedef
3048  // template<typename _Tp>
3049  // class c2
3050  // {
3051  // public:
3052  // typedef _Tp alise;
3053  //
3054  // };
3055  if ( (components.size() == 2)
3056  && m_LastParent
3059  && m_LastParent->m_TemplateType.Index(components.front()) != wxNOT_FOUND )
3060  {
3061  wxArrayString templateType = m_LastParent->m_TemplateType;
3062  alias = components.front();
3063  components.pop();
3064  ancestor = components.front();
3065  }
3066  else
3067  {
3068  while (components.size() > 1)
3069  {
3070  token = components.front();
3071  components.pop();
3072 
3073  if (!ancestor.IsEmpty())
3074  ancestor << ParserConsts::space_chr;
3075  ancestor << token;
3076  }
3077  }
3078 
3079  // no return type
3080  m_Str.Clear();
3081 
3082  TRACE(_("HandleTypedef() : Adding typedef: name='%s', ancestor='%s', args='%s'"), components.front().wx_str(), ancestor.wx_str(), args.wx_str());
3083  Token* tdef = DoAddToken(tkTypedef /*tkClass*/, components.front(), lineNr, 0, 0, args);
3084  if (tdef)
3085  {
3086  wxString actualAncestor = ancestor.BeforeFirst(ParserConsts::lt_chr).Trim();
3087  TRACE(_("HandleTypedef() : Ancestor='%s', actual ancestor='%s'"), ancestor.wx_str(), actualAncestor.wx_str());
3088 
3089  if (is_function_pointer)
3090  {
3091  tdef->m_FullType = ancestor + typ; // + args;
3092  tdef->m_BaseType = actualAncestor;
3093  if (tdef->IsValidAncestor(ancestor))
3094  tdef->m_AncestorsString = ancestor;
3095  }
3096  else
3097  {
3098  tdef->m_FullType = ancestor;
3099  tdef->m_BaseType = actualAncestor;
3100  tdef->m_TemplateAlias = alias;
3101  TRACE(_T("The typedef alias is %s."), tdef->m_TemplateAlias.wx_str());
3102 
3103  if (tdef->IsValidAncestor(ancestor))
3104  tdef->m_AncestorsString = ancestor;
3105  if (!m_TemplateArgument.IsEmpty())
3106  ResolveTemplateArgs(tdef);
3107  }
3108  }
3109 }
3110 
3112 {
3113  bool success = true; // optimistic start value
3114 
3115  while (IS_ALIVE)
3116  {
3117  wxString token = m_Tokenizer.GetToken();
3118 
3119  if (token.IsEmpty()) // end of file / tokens
3120  break;
3121 
3122  if (token==ParserConsts::comma) // another variable name
3123  continue;
3124  else if (token==ParserConsts::semicolon) // end of variable name(s)
3125  {
3127  break;
3128  }
3129  else if (token == ParserConsts::oparray)
3130  {
3132  }
3133  else if (token == ParserConsts::ptr) // variable is a pointer
3134  m_PointerOrRef << token;
3135  else if ( wxIsalpha(token.GetChar(0))
3136  || (token.GetChar(0) == ParserConsts::underscore_chr) )
3137  {
3138  TRACE(_T("ReadVarNames() : Adding variable '%s' as '%s' to '%s'"),
3139  token.wx_str(), m_Str.wx_str(),
3140  (m_LastParent ? m_LastParent->m_Name.wx_str() : _T("<no-parent>")));
3141 
3142  // Detects anonymous ancestor and gives him a name based on the first found alias.
3143  if (m_Str.StartsWith(g_UnnamedSymbol))
3145 
3146  Token* newToken = DoAddToken(tkVariable, token, m_Tokenizer.GetLineNumber());
3147  if (!newToken)
3148  {
3149  TRACE(_T("ReadVarNames() : Unable to create/add new token: ") + token);
3150  break;
3151  }
3152  }
3153  else // unexpected
3154  {
3155  TRACE(F(_T("ReadVarNames() : Unexpected token '%s' for '%s', file '%s', line %d."),
3156  token.wx_str(), m_Str.wx_str(), m_Tokenizer.GetFilename().wx_str(), m_Tokenizer.GetLineNumber()));
3157  CCLogger::Get()->DebugLog(F(_T("ReadVarNames() : Unexpected token '%s' for '%s', file '%s', line %d."),
3158  token.wx_str(), m_Str.wx_str(), m_Tokenizer.GetFilename().wx_str(), m_Tokenizer.GetLineNumber()));
3159  success = false;
3160  break;
3161  }
3162  }
3163  return success;
3164 }
3165 
3167 {
3168  bool success = true; // optimistic start value
3169 
3170  while (IS_ALIVE)
3171  {
3172  wxString token = m_Tokenizer.GetToken();
3173 
3174  if (token.IsEmpty()) // end of file / tokens
3175  break;
3176 
3177  if (token==ParserConsts::comma) // another class name
3178  continue;
3179  else if (token==ParserConsts::semicolon) // end of class name(s)
3180  {
3183  break;
3184  }
3185  else if (token == ParserConsts::ptr) // variable is a pointer
3186  m_PointerOrRef << token;
3187  else if ( wxIsalpha(token.GetChar(0))
3188  || (token.GetChar(0) == ParserConsts::underscore_chr) )
3189  {
3190  TRACE(_T("ReadClsNames() : Adding variable '%s' as '%s' to '%s'"),
3191  token.wx_str(),
3192  m_Str.wx_str(),
3193  (m_LastParent ? m_LastParent->m_Name.wx_str() : _T("<no-parent>")));
3194 
3195  m_Str.clear();
3196  m_Str = ancestor;
3197 
3198  // Detects anonymous ancestor and gives him a name based on the first found alias.
3199  if (m_Str.StartsWith(g_UnnamedSymbol))
3200  {
3202  ancestor = m_Str;
3203  }
3204 
3205  Token* newToken = DoAddToken(tkTypedef, token, m_Tokenizer.GetLineNumber());
3206  if (!newToken)
3207  {
3208  TRACE(_T("ReadClsNames() : Unable to create/add new token: ") + token);
3209  break;
3210  }
3211  else
3212  newToken->m_AncestorsString = ancestor;
3213  }
3214  else // unexpected
3215  {
3216  TRACE(F(_T("ReadClsNames() : Unexpected token '%s' for '%s', file '%s', line %d."),
3217  token.wx_str(), m_Str.wx_str(), m_Tokenizer.GetFilename().wx_str(), m_Tokenizer.GetLineNumber()));
3218  CCLogger::Get()->DebugLog(F(_T("ReadClsNames() : Unexpected token '%s' for '%s', file '%s', line %d."),
3219  token.wx_str(), m_Str.wx_str(), m_Tokenizer.GetFilename().wx_str(), m_Tokenizer.GetLineNumber()));
3220  // The following code snippet freezes CC here:
3221  // typedef std::enable_if<N > 1, get_type_N<N-1, Tail...>> type;
3223  // Note: Do NOT remove m_Tokenizer.UngetToken();, otherwise it freezes somewhere else
3224  success = false;
3225  break;
3226  }
3227  }
3228  return success;
3229 }
3230 
3231 bool ParserThread::GetBaseArgs(const wxString& args, wxString& baseArgs)
3232 {
3233  const wxChar* ptr = args.wx_str(); // pointer to current char in args string
3234  wxString word; // compiled word of last arg
3235  bool skip = false; // skip the next char (do not add to stripped args)
3236  bool sym = false; // current char symbol
3237  bool one = true; // only one argument
3238  // ( int abc = 5 , float * def )
3239  // ^
3240  // ptr point to the next char of "int"
3241  // word = "int"
3242  // sym = true means ptr is point to an identifier like token
3243  // here, if we find an identifier like token which is "int", we just skip the next token
3244  // until we meet a "," or ")".
3245 
3246 
3247  TRACE(_T("GetBaseArgs() : args='%s'."), args.wx_str());
3248  baseArgs.Alloc(args.Len() + 1);
3249 
3250  // Verify ptr is valid (still within the range of the string)
3251  while (*ptr != ParserConsts::null)
3252  {
3253  switch (*ptr)
3254  {
3255  case ParserConsts::eol_chr:
3256  // skip the "\r\n"
3257  while (*ptr != ParserConsts::null && *ptr <= ParserConsts::space_chr)
3258  ++ptr;
3259  break;
3261  // take care of args like:
3262  // - enum my_enum the_enum_my_enum
3263  // - const int the_const_int
3264  // - volatile long the_volatile_long
3265  if ( (word == ParserConsts::kw_enum)
3266  || (word == ParserConsts::kw_const)
3267  || (word == ParserConsts::kw_volatile) )
3268  skip = false; // don't skip this (it's part of the stripped arg)
3269  else
3270  skip = true; // safely skip this as it is the args name
3271  word = _T(""); // reset
3272  sym = false;
3273  break;
3274  case ParserConsts::ptr_chr: // handle pointer args
3275  // handle multiple pointer like in: main (int argc, void** argv)
3276  // or ((int *, char ***))
3277  while (*(ptr+1) != ParserConsts::null && *(ptr+1) == ParserConsts::ptr_chr)
3278  {
3279  baseArgs << *ptr; // append one more '*' to baseArgs
3280  ptr++; // next char
3281  }
3282  // ...and fall through:
3283  case ParserConsts::ref_chr: // handle references
3284  word = _T(""); // reset
3285  skip = true;
3286  sym = true;
3287 
3288  // TODO (Morten#5#): Do comment the following even more. It's still not exactly clear to me...
3289  // verify completeness of last stripped argument (handle nested brackets correctly)
3290  {
3291  // extract last stripped argument from baseArgs
3292  wxString lastStrippedArg;
3293  int lastArgComma = baseArgs.Find(ParserConsts::comma_chr, true);
3294  if (lastArgComma)
3295  lastStrippedArg = baseArgs.Mid(1);
3296  else
3297  lastStrippedArg = baseArgs.Mid(lastArgComma);
3298 
3299 
3300  // input: (float a = 0.0, int* f1(char x, char y), void z)
3301  // output: (float, int*, z)
3302  // the internal "(char x, char y)" should be removed
3303  // No opening brackets in last stripped arg?
3304  // this means if we have function pointer in the argument
3305  // input: void foo(double (*fn)(double))
3306  // we should not skip the content after '*', since the '(' before '*' is already
3307  // pushed to the lastStrippedArg.
3308  if ( lastStrippedArg.Find(ParserConsts::opbracket_chr) == wxNOT_FOUND )
3309  {
3310  baseArgs << *ptr; // append to baseArgs
3311 
3312  // find end
3313  int brackets = 0;
3314  ptr++; // next char
3315 
3316  while (*ptr != ParserConsts::null)
3317  {
3318  if (*ptr == ParserConsts::opbracket_chr)
3319  brackets++;
3320  else if (*ptr == ParserConsts::clbracket_chr)
3321  {
3322  if (brackets == 0)
3323  break;
3324  brackets--;
3325  }
3326  else if (*ptr == ParserConsts::comma_chr && brackets == 0)
3327  {
3328  // don't stop at the inner comma char, such as '^' pointed below
3329  // (float a = 0.0, int* f1(char x, char y), void z)
3330  // ^
3331  skip = false;
3332  break;
3333  }
3334  ptr++; // next char
3335  }
3336  }
3337  }
3338  break;
3339  case ParserConsts::colon_chr: // namespace handling like for 'std::vector'
3340  skip = false;
3341  sym = true;
3342  break;
3343  case ParserConsts::oparray_chr: // array handling like for 'int[20]'
3344  // [ 128 ] -> [128]
3345  // space between the [] is stripped
3346  while ( *ptr != ParserConsts::null
3347  && *ptr != ParserConsts::clarray_chr )
3348  {
3349  if (*ptr != ParserConsts::space_chr)
3350  baseArgs << *ptr; // append to baseArgs, skipping spaces
3351  ptr++; // next char
3352  }
3353  skip = true;
3354  sym = true;
3355  break;
3356  case ParserConsts::lt_chr: // template arg handling like for 'vector<int>'
3357  // < int > -> <int>
3358  // space between the <> is stripped
3359  // note that embeded <> such as vector<vector<int>> is not handled here
3360  while ( *ptr != ParserConsts::null
3361  && *ptr != ParserConsts::gt_chr )
3362  {
3363  if (*ptr != ParserConsts::space_chr)
3364  baseArgs << *ptr; // append to baseArgs, skipping spaces
3365  ptr++; // next char
3366  }
3367  skip = true;
3368  sym = true;
3369  break;
3370  case ParserConsts::comma_chr: // fall through
3371  case ParserConsts::clbracket_chr: // fall through
3373  // ( int abc, .....)
3374  // we have just skip the "abc", and now, we see the ","
3375  if (skip && *ptr == ParserConsts::comma_chr)
3376  one = false; // see a comma, which means we have at least two parameter!
3377 
3378  // try to remove the __attribute__(xxx) decoration in the parameter
3379  // such as: int f(__attribute__(xxx) wxCommandEvent & event);
3380  // should be convert to : int f(wxCommandEvent & event);
3382  {
3383  // remove the "__attribute__" keywords from the baseArgs
3384  // the length of "__attribute__" is 13
3385  baseArgs = baseArgs.Mid(0, baseArgs.Len()-13);
3386 
3387  // skip the next "(xxx)
3388  int brackets = 1; // skip the first "(" already
3389  ptr++; // next char
3390 
3391  while (*ptr != ParserConsts::null)
3392  {
3393  if (*ptr == ParserConsts::opbracket_chr)
3394  brackets++;
3395  else if (*ptr == ParserConsts::clbracket_chr)
3396  {
3397  brackets--;
3398  if (brackets == 0)
3399  {
3400  ptr++;
3401  break;
3402  }
3403 
3404  }
3405  ptr++; // next char
3406  }
3407  // skip the spaces after the "__attribute__(xxx)"
3408  while ( *ptr != ParserConsts::null
3409  && *(ptr) == ParserConsts::space_chr )
3410  {
3411  ++ptr; // next char
3412  }
3413  word = _T(""); // reset
3414  sym = false; // no symbol is added
3415  skip = false; // don't skip the next token
3416  break;
3417  }
3418  word = _T(""); // reset
3419  sym = true;
3420  skip = false;
3421  break;
3422  default:
3423  sym = false;
3424  }// switch (*ptr)
3425 
3426  // Now handle the char processed in this loop:
3427  if (!skip || sym)
3428  {
3429  // append to stripped argument and save the last word
3430  // (it's probably a type specifier like 'const' or alike)
3431  if (*ptr != ParserConsts::null)
3432  {
3433  baseArgs << *ptr; // append to baseArgs
3434  if (wxIsalnum(*ptr) || *ptr == ParserConsts::underscore_chr)
3435  word << *ptr; // append to word
3436  }
3437  }
3438 
3439  if (!skip && sym)
3440  {
3441  // skip white spaces and increase pointer
3442  while ( *ptr != ParserConsts::null
3443  && *(ptr+1) == ParserConsts::space_chr )
3444  {
3445  ++ptr; // next char
3446  }
3447  }
3448 
3449  if (*ptr != ParserConsts::null)
3450  {
3451  ++ptr; // next char
3452  }
3453  }
3454 
3455  if (one && baseArgs.Len() > 2)
3456  {
3457  const wxChar ch = baseArgs[1];
3458  if ( (ch <= _T('9') && ch >= _T('0')) // number, 0 ~ 9
3459  || baseArgs.Find(_T('"')) != wxNOT_FOUND // string
3460  || baseArgs.Find(_T('\'')) != wxNOT_FOUND ) // character
3461  {
3462  return false; // not function, it should be variable
3463  }
3464 
3465  if (baseArgs == _T("(void)"))
3466  baseArgs = _T("()");
3467  }
3468 
3469  TRACE(_T("GetBaseArgs() : baseArgs='%s'."), baseArgs.wx_str());
3470  return true;
3471 }
3472 
3474 {
3475  // need to force the tokenizer _not_ skip anything
3476  // otherwise default values for template params would cause us to miss everything (because of the '=' symbol)
3477  TokenizerState oldState = m_Tokenizer.GetState();
3480  int nestLvl = 0;
3481  // NOTE: only exit this loop with 'break' so the tokenizer's state can
3482  // be reset afterwards (i.e. don't use 'return')
3483  while (IS_ALIVE)
3484  {
3485  wxString tmp = m_Tokenizer.GetToken();
3486 
3487  if (tmp==ParserConsts::lt)
3488  {
3489  ++nestLvl;
3490  m_TemplateArgument << tmp;
3491 
3492  }
3493  else if (tmp==ParserConsts::gt)
3494  {
3495  --nestLvl;
3496  m_TemplateArgument << tmp;
3497  }
3498  else if (tmp==ParserConsts::semicolon)
3499  {
3500  // unget token - leave ; on the stack
3503  break;
3504  }
3505  else if (tmp.IsEmpty())
3506  break;
3507  else
3508  m_TemplateArgument << tmp;
3509  if (nestLvl <= 0)
3510  break;
3511  }
3512 
3513  // reset tokenizer's functionality
3514  m_Tokenizer.SetState(oldState);
3515 }
3516 
3518 {
3519  TRACE(_T("The variable template arguments are '%s'."), m_TemplateArgument.wx_str());
3521  wxArrayString actuals;
3523  for (size_t i=0; i<actuals.GetCount(); ++i)
3524  TRACE(_T("The template actual arguments are '%s'."), actuals[i].wx_str());
3525 
3526  newToken->m_TemplateType = actuals;
3527  // now resolve the template normal and actual map
3528  // wxString parentType = m_Str;
3529  std::map<wxString, wxString> templateMap;
3530  ResolveTemplateMap(newToken->m_FullType, actuals, templateMap);
3531  newToken->m_TemplateMap = templateMap;
3532 }
3533 
3534 wxArrayString ParserThread::GetTemplateArgArray(const wxString& templateArgs, bool remove_gt_lt, bool add_last)
3535 {
3536  wxString word;
3537  wxString args = templateArgs;
3538  args.Trim(true).Trim(false);
3539  if (remove_gt_lt)
3540  {
3541  args.Remove(0, 1);
3542  args.RemoveLast();
3543  }
3544 
3545  wxArrayString container;
3546  for (size_t i = 0; i < args.Len(); ++i)
3547  {
3548  wxChar arg = args.GetChar(i);
3549  switch (arg)
3550  {
3552  container.Add(word);
3553  word.clear();
3554  continue;
3555  case ParserConsts::lt_chr:
3556  case ParserConsts::gt_chr:
3558  container.Add(word);
3559  word.clear();
3560  container.Add(args[i]);
3561  continue;
3562  default:
3563  word << args[i];
3564  }
3565  }
3566 
3567  if (add_last && !word.IsEmpty())
3568  container.Add(word);
3569 
3570  return container;
3571 }
3572 
3574 {
3575  wxArrayString container = GetTemplateArgArray(templateArgs, false, false);
3576  size_t n = container.GetCount();
3577  for (size_t j = 0; j < n; ++j)
3578  {
3579  if ( (container[j] == ParserConsts::kw_typename)
3580  || (container[j] == ParserConsts::kw_class) )
3581  {
3582  if ( (j+1) < n )
3583  {
3584  formals.Add(container[j+1]);
3585  ++j; // skip
3586  }
3587  }
3588  }
3589 
3590 }
3591 
3593 {
3594  wxArrayString container = GetTemplateArgArray(templateArgs, true, true);
3595  size_t n = container.GetCount();
3596 
3597  // for debug purposes only
3598  for (size_t j = 0; j < n; ++j)
3599  TRACE(_T("The container elements are '%s'."), container[j].wx_str());
3600 
3601  int level = 0;
3602  for (size_t j = 0; j < n; ++j)
3603  {
3604  if (container[j] == ParserConsts::lt)
3605  {
3606  ++level;
3607  while (level > 0 && (j+1) < n)
3608  {
3609  if (container[j] == ParserConsts::gt)
3610  --level;
3611  ++j; // skip
3612  }
3613 
3614  }
3615  else if (container[j] == ParserConsts::comma)
3616  {
3617  ++j; // skip
3618  continue;
3619  }
3620  else
3621  actuals.Add(container[j]);
3622  ++j; // skip
3623  }
3624 }
3625 
3626 bool ParserThread::ResolveTemplateMap(const wxString& typeStr, const wxArrayString& actuals,
3627  std::map<wxString, wxString>& results)
3628 {
3629  // Check if type is an alias template. If it is, then we use the actual type's template map.
3630  // For example, given:
3631  // template <class T> using AAA = BBB<T>;
3632  // AAA<MyClass> obj;
3633  // When handling obj, typeStr would equal AAA, but we would use BBB's template map.
3634  wxString tokenFullType = typeStr;
3635  TokenIdxSet fullTypeMatches;
3636  size_t matchesCount = m_TokenTree->FindMatches(tokenFullType, fullTypeMatches, true, false, tkTypedef);
3637  if (matchesCount > 0)
3638  {
3639  for (TokenIdxSet::const_iterator it= fullTypeMatches.begin(); it!= fullTypeMatches.end(); ++it)
3640  {
3641  int id = (*it);
3642  Token* token = m_TokenTree->at(id);
3643 
3644  if (token->m_TokenKind == tkTypedef)
3645  {
3646  tokenFullType = token->m_FullType;
3647  // we are only interested in the type name, so remove the scope qualifiers
3648  if (tokenFullType.Find(_T("::")) != wxNOT_FOUND)
3649  tokenFullType = tokenFullType.substr(tokenFullType.Find(_T("::"))+2);
3650  break;
3651  }
3652  }
3653  }
3654 
3655  wxString parentType = tokenFullType;
3656  parentType.Trim(true).Trim(false);
3657  // Note that we only search by the type name, and we don't care about the scope qualifiers
3658  // I add this for temporary support of templates under std, I will write better code later.
3659  TokenIdxSet parentResult;
3660  size_t tokenCounts = m_TokenTree->FindMatches(parentType, parentResult, true, false, tkClass);
3661  if (tokenCounts > 0)
3662  {
3663  for (TokenIdxSet::const_iterator it=parentResult.begin(); it!=parentResult.end(); ++it)
3664  {
3665  int id = (*it);
3666  Token* normalToken = m_TokenTree->at(id);
3667  if (normalToken)
3668  {
3669  // Get the formal template argument lists
3670  wxArrayString formals = normalToken->m_TemplateType;
3671  for (size_t i=0; i<formals.GetCount(); ++i)
3672  TRACE(_T("ResolveTemplateMap get the formal template arguments are '%s'."), formals[i].wx_str());
3673 
3674  size_t n = formals.GetCount() < actuals.GetCount() ? formals.GetCount() : actuals.GetCount();
3675  for (size_t i=0; i<n; ++i)
3676  {
3677  results[formals[i]] = actuals[i];
3678  TRACE(_T("In ResolveTemplateMap function the normal is '%s',the actual is '%s'."), formals[i].wx_str(), actuals[i].wx_str());
3679  }
3680  }
3681  }
3682  return (results.size()>0) ? true : false;
3683  }
3684  else
3685  return false;
3686 }
3687 
3688 void ParserThread::RemoveTemplateArgs(const wxString &exp, wxString &expNoArgs, wxString &templateArgs)
3689 {
3690  expNoArgs.clear();
3691  templateArgs.clear();
3692 
3693  int nestLvl = 0;
3694  for (unsigned int i = 0; i < exp.length(); i++)
3695  {
3696  wxChar c = exp[i];
3697 
3698  if (c == ParserConsts::lt_chr)
3699  {
3700  nestLvl++;
3701  templateArgs << c;
3702  continue;
3703  }
3704 
3705  if (c == ParserConsts::gt_chr)
3706  {
3707  nestLvl--;
3708  templateArgs << c;
3709  continue;
3710  }
3711 
3712  if (nestLvl == 0)
3713  expNoArgs << c;
3714  else
3715  {
3716  bool wanted = true;
3717 
3718  // don't add unwanted whitespaces, i.e. ws around '<' and '>'
3719  if(c == ParserConsts::space)
3720  {
3721  wxChar last = 0;
3722  wxChar next = 0;
3723 
3724  if (i > 0) last = exp[i - 1];
3725  if (i < exp.length() - 1) next = exp[i + 1];
3726 
3727  if (last == ParserConsts::gt || last == ParserConsts::lt)
3728  wanted = false;
3729 
3730  if (next == ParserConsts::gt || next == ParserConsts::lt)
3731  wanted = false;
3732  }
3733 
3734  if (wanted == true)
3735  templateArgs << c;
3736  }
3737  }
3738 }
3739 
3740 bool ParserThread::IsStillAlive(cb_unused const wxString& funcInfo)
3741 {
3742  const bool alive = !TestDestroy();
3743  if (!alive)
3744  {
3745  TRACE(_T("IsStillAlive() : %s "), funcInfo.wx_str());
3746  free(0);
3747  }
3748  return alive;
3749 }
3750 
3751 void ParserThread::RefineAnonymousTypeToken(short int typeMask, wxString alias)
3752 {
3753  // we expect the m_Str are storing the unnamed type token, like UnnamedClassAA_BBB
3754  // AA is the file index, BBB is the unnamed token index
3755  // now, we are going to rename its name to classAA_CCC, CCC is the alias name
3756  Token* unnamedAncestor = TokenExists(m_Str, m_LastParent, typeMask);
3757  if (unnamedAncestor && unnamedAncestor->m_IsAnonymous) // Unnamed ancestor found - rename it to something useful.
3758  {
3759  if (m_Str.Contains(_T("Union")))
3760  m_Str = _T("union");
3761  else if (m_Str.Contains(_T("Struct")))
3762  m_Str = _T("struct");
3763  else
3764  m_Str = _T("tag");
3765  m_Str << m_FileIdx << _T("_") << alias;
3766  m_TokenTree->RenameToken(unnamedAncestor, m_Str);
3767  }
3768 }
3769 
3771 {
3772  wxString str = m_Tokenizer.GetToken();
3773  if (str != wxT("<"))
3774  return wxEmptyString;
3775 
3776  int level = 1; // brace level of '<' and '>'
3777 
3778  while (m_Tokenizer.NotEOF())
3779  {
3780  wxString token = m_Tokenizer.GetToken();
3781  if (token == _T("<"))
3782  {
3783  ++level;
3784  str << token;
3785  }
3786  else if (token == _T(">"))
3787  {
3788  --level;
3789  str << token;
3790  if (level == 0)
3791  break;
3792 
3793  }
3794  else if (token == _T("*") || token == _T("&") || token == _T(","))
3795  {
3796  str << token;
3797  }
3798  else
3799  {
3800  if (str.Last() == _T('<')) // there is no space between '(' and the following token
3801  str << token;
3802  else // otherwise, a space is needed
3803  str << _T(" ") << token;
3804  }
3805 
3806  if (level == 0)
3807  break;
3808  }//while (NotEOF())
3809 
3810  return str;
3811 }
wxString m_LastUnnamedTokenName
TODO: describe me here.
Definition: parserthread.h:459
Token * TokenExists(const wxString &name, const Token *parent=0, short int kindMask=0xFFFF)
if parent is 0, then global namespace will be used, all tokens under parent scope are searched ...
LoaderBase * loader
Definition: parserthread.h:128
wxString F(const wxChar *msg,...)
sprintf-like function
Definition: logmanager.h:20
const wxString kw_if(_T("if"))
std::map< wxString, wxString > m_TemplateMap
a string to string map from formal template argument to actual template argument
Definition: token.h:291
destructor class member function
Definition: token.h:51
int TokenExists(const wxString &name, int parent, short int kindMask)
query tokens by names
Definition: tokentree.cpp:141
bool Parse()
Do the main job (syntax analysis) here.
size_t m_EnumUnnamedCount
Definition: parserthread.h:477
const wxChar tab_chr(_T('\t'))
wxString fileOfBuffer
which file the buffer belongs to, this usually happens when we parse a piece of the cbEditor and the ...
Definition: parserthread.h:76
void UngetToken()
Undo the GetToken.
Definition: tokenizer.cpp:914
void SetTokenizerOption(bool wantPreprocessor, bool storeDocumentation)
Handle condition preprocessor and store documentation or not.
Definition: tokenizer.h:100
const wxString kw_inline(_T("inline"))
variable
Definition: token.h:57
namespace
Definition: token.h:34
std::queue< wxString > m_EncounteredNamespaces
for member funcs implementation or a function declaration below eg: int ClassA::FunctionB(); Encounte...
Definition: parserthread.h:444
const wxChar underscore_chr(_T('_'))
const wxChar clarray_chr(_T(']'))
const wxString kw_class(_T("class"))
int m_ParentIndex
Parent Token index.
Definition: token.h:265
const wxString kw_virtual(_T("virtual"))
constructor class member function
Definition: token.h:48
void RenameToken(Token *token, const wxString &newName)
only the token&#39;s name need to be changed, thus update the index map of the TokenTree ...
Definition: tokentree.cpp:338
size_t InsertFileOrGetIndex(const wxString &filename)
put the filename in the m_FilenameMap, and return the file index, if this file is already in the m_Fi...
Definition: tokentree.cpp:835
class or struct
Definition: token.h:37
const wxString empty(_T(""))
const wxString colon(_T(":"))
bool followLocalIncludes
parse the file in #include "file" directive
Definition: parserthread.h:96
void HandleTypedef()
handle typedef directive
const wxString clarray(_T("]"))
int StartLine
Definition: parserthread.h:30
const wxString & GetFilename() const
Return the opened files name.
Definition: tokenizer.h:121
Token * at(int idx)
Definition: tokentree.h:51
const wxChar dot_chr(_T('.'))
bool wxIsspace(const wxUniChar &c)
bool ResolveTemplateMap(const wxString &typeStr, const wxArrayString &actuals, std::map< wxString, wxString > &results)
associate formal argument with actual template argument
void Delete(std::vector< T > &s)
Definition: safedelete.h:20
read parentheses as token lists, so it return several tokens like &#39;(&#39; ...
Definition: tokenizer.h:24
wxString m_BaseType
this is what the parser believes is the actual return value: e.g.
Definition: token.h:185
bool ReadVarNames()
eg: class ClassA{...} varA, varB, varC This function will read the "varA, varB, varC" ...
bool m_IsAnonymous
Is anonymous token? (e.g.
Definition: token.h:254
const wxString kw_delete(_T("delete"))
static CCLogger * Get()
Definition: cclogger.cpp:60
wxString m_PointerOrRef
a pointer indicator or a references
Definition: parserthread.h:470
const wxString tilde(_T("~"))
void SplitTemplateFormalParameters(const wxString &templateArgs, wxArrayString &formals)
Split formal template argument list.
wxString m_Name
Token&#39;s name, it can be searched in the TokenTree.
Definition: token.h:188
wxString substr(size_t nStart=0, size_t nLen=npos) const
void HandleClass(EClassType ct)
handle class declaration
unsigned int m_ImplLine
function implementation line index
Definition: token.h:219
#define ADDTOKEN(format, args...)
const wxString kw_declspec(_T("__declspec"))
wxFileOffset Length() const
bool isTemp
this value is passed to the generated Token&#39;s m_IsTemp property
Definition: parserthread.h:93
bool IsValidAncestor(const wxString &ancestor)
build in types are not valid ancestors for a type define token
Definition: token.cpp:133
typedef, note typedefs are stored as classes inheriting from the typedef&#39;d type, this takes advantage...
Definition: token.h:45
TokenScope m_LastScope
this member define the scope type of member variables, which is: public, private protected or undefin...
Definition: parserthread.h:410
wxChar SkipToOneOfChars(const wxString &chars, bool supportNesting=false, bool singleCharToken=true)
Continuously eat the tokens until we meet one of the matching characters.
size_t length() const
void InsertTokenBelongToFile(size_t fileIdx, int tokenIdx)
Definition: tokentree.h:212
const wxString plus(_T("+"))
TokenIdxSet m_UsedNamespacesIds
globally included namespaces by "using namespace" statement
Definition: parserthread.h:456
container like tokens, those tokens can have children tokens
Definition: token.h:70
bool wxFileExists(const wxString &filename)
const wxString gt(_T(">"))
const wxChar hash_chr(_T('#'))
unsigned int GetNestingLevel() const
Return the brace "{}" level.
Definition: tokenizer.h:135
const wxString kw_for(_T("for"))
const wxChar comma_chr(_T(','))
const wxString kw_namespace(_T("namespace"))
const wxString kw_friend(_T("friend"))
void SkipAngleBraces()
skip the template argument
const wxString kw_private(_T("private"))
wxString m_BaseArgs
stripped arguments e.g.
Definition: token.h:197
const wxChar opbrace_chr(_T('{'))
int Index(const wxString &sz, bool bCase=true, bool bFromEnd=false) const
const wxString kw_public(_T("public"))
void FlagFileAsParsed(const wxString &filename)
mark the file status as fpsDone, since parsing this file is done
Definition: tokentree.cpp:931
const wxChar space_chr(_T(' '))
const wxChar oparray_chr(_T('['))
const wxChar clbracket_chr(_T(')'))
virtual bool ParseFile(const wxString &filename, bool isGlobal, bool locked=false)
Token * DoAddToken(TokenKind kind, const wxString &name, int line, int implLineStart=0, int implLineEnd=0, const wxString &args=wxEmptyString, bool isOperator=false, bool isImpl=false)
add one token to the token tree
size_t Length() const
unsigned int m_FileIdx
source file index on the "file map tree"
Definition: parserthread.h:419
a container class to hold all the Tokens getting from parsing stage
Definition: tokentree.h:37
unsigned int m_ImplLineStart
if token is impl, opening brace line
Definition: token.h:222
const wxString kw_static(_T("static"))
const wxChar lt_chr(_T('<'))
const wxString semicolon(_T(";"))
const wxChar opbracket_chr(_T('('))
int parentIdxOfBuffer
when parsing a function body, all the tokens are the children of the function token ...
Definition: parserthread.h:79
#define _T(string)
const wxString kw_switch(_T("switch"))
const wxString kw_volatile(_T("volatile"))
void SkipBlock()
skip blocks {}
unsigned int m_Line
Line index where the token was met, which is 1 based.
Definition: token.h:210
unsigned int GetLineNumber() const
Return the line number of the current token string.
Definition: tokenizer.h:127
wxString GetNextToken()
const wxString equals(_T("="))
int m_Index
current Token index in the tree, it is index of the std::vector<Token*>, so use the index...
Definition: token.h:262
bool wxIsdigit(const wxUniChar &c)
wxArrayString GetTemplateArgArray(const wxString &templateArgs, bool remove_gt_lt, bool add_last)
normally the template argument is all in a wxString, this function just split them to a wxArrayString...
const wxString kw_else(_T("else"))
const wxString kw__C_(_T("\\))
unsigned int m_ImplLineEnd
if token is impl, closing brace line
Definition: token.h:225
DLLIMPORT wxString GetStringFromArray(const wxArrayString &array, const wxString &separator=DEFAULT_ARRAY_SEP, bool SeparatorAtEnd=true)
Definition: globals.cpp:122
const wxString dot(_T("."))
bool GetBaseArgs(const wxString &args, wxString &baseArgs)
Converts a full argument list (including variable names) to argument types only and strips spaces...
wxString & Remove(size_t pos)
bool m_IsNoExcept
the member method is noexcept (yes/no)
Definition: token.h:251
const wxString semicolonopbrace(_T(";{"))
const wxString kw_template(_T("template"))
wxArrayString m_Aliases
used for namespace aliases
Definition: token.h:280
bool TestDestroy() const
Be sure to call this function often. If it returns true, quit your task quickly.
#define wxT(string)
bool m_IsTemp
local (automatic) variable
Definition: token.h:245
This is just a simple lexer class.
Definition: tokenizer.h:64
TokenScope m_Scope
public? private? protected?
Definition: token.h:231
wxArrayString m_TemplateType
for a class template, this is the formal template argument list, but for a variable Token...
Definition: token.h:288
#define wxNOT_FOUND
wxString m_AncestorsString
all ancestors comma-separated list, e.g.
Definition: token.h:204
bool m_IsOperator
is operator overload function?
Definition: token.h:237
bool empty() const
size_t find(const wxString &str, size_t nStart=0) const
bool m_IsLocal
if true, means we are parsing a file which belongs to a C::B project, otherwise, we are parsing a fil...
Definition: parserthread.h:424
const wxString kw_extern(_T("extern"))
EFileType FileType(const wxString &filename, bool force_refresh=false)
return a file type, which can be either header files or implementation files or other files ...
void DebugLog(const wxString &msg)
Definition: cclogger.cpp:107
bool ParseBufferForNamespaces(const wxString &buffer, NameSpaceVec &result)
Get the context "namespace XXX { ... }" directive.
wxString m_Filename
the file name of the parsing source
Definition: parserthread.h:413
const wxString oparray(_T("["))
TokenTree * m_TokenTree
a pointer to the token tree, all the tokens will be added to that tree structure
Definition: parserthread.h:400
unsigned int m_FileSize
file size, actually the length of the wxString
Definition: parserthread.h:416
const wxString kw_typename(_T("typename"))
bool Sync()
Definition: filemanager.cpp:36
bool CalcEnumExpression(Token *tokenParent, long &result, wxString &peek)
calculate the value assigned to enumerator
bool handleEnums
whether to parse "enum ..." like statement
Definition: parserthread.h:120
wxUSE_UNICODE_dependent wxChar
const wxString kw_protected(_T("protected"))
unsigned int m_FileIdx
File index in TokenTree.
Definition: token.h:207
const wxString dash(_T("-"))
bool handleClasses
whether to parse "class ...." like statement
Definition: parserthread.h:117
ParserBase * m_Parent
a pointer to its parent Parser object, the Parserthread class has two place to communicate with Parse...
Definition: parserthread.h:397
wxString m_TemplateArgument
holds current template argument(s) when a template occurs
Definition: parserthread.h:473
wxString BeforeFirst(wxUniChar ch, wxString *rest=NULL) const
std::vector< NameSpace > NameSpaceVec
Definition: parserthread.h:34
void GetTemplateArgs()
Read the <xxxx=yyy, zzz> , and store the value in m_TemplateArgs.
const wxString space(_T(" "))
bool Contains(const wxString &str) const
wxString GetTokenBaseType()
return the actual token&#39;s base type.
const wxString kw_include(_T("include"))
const wxString kw_enum(_T("enum"))
const wxChar gt_chr(_T('>'))
const wxString semicolonclbrace(_T(";}"))
a symbol found in the parsed files, it can be many kinds, such as a variable, a class and so on...
Definition: token.h:82
const wxString opbracket(_T("("))
wxString & RemoveLast(size_t n=1)
std::set< int, std::less< int > > TokenIdxSet
Definition: token.h:16
wxString PeekToken()
Do a "look ahead", and return the next token string.
Definition: tokenizer.cpp:869
void HandleEnum()
handle enum declaration
const wxChar clbrace_chr(_T('}'))
const wxString kw_const(_T("const"))
#define TRACE(format, args...)
const wxString kw_while(_T("while"))
const wxString gtsemicolon(_T(">;"))
bool m_ParsingTypedef
this makes a difference in unnamed class/struct/enum handling
Definition: parserthread.h:462
void DoParse()
actually run the syntax analysis
bool Alloc(size_t nLen)
const wxString kw_return(_T("return"))
const wxString opbrace(_T("{"))
const wxString commaclbrace(_T(",}"))
EClassType
specify which "class like type" we are handling: struct or class or union
Definition: parserthread.h:181
bool handleFunctions
whether to parse the functions
Definition: parserthread.h:111
long GetResult() const
Definition: expression.h:87
void RemoveTemplateArgs(const wxString &expr, wxString &expNoArgs, wxString &templateArgs)
remove template arguments from an expression example: &#39;std::list<string>&#39; will be separated into &#39;std...
bool handleVars
whether to parse the variable definition
Definition: parserthread.h:114
const wxString kw_union(_T("union"))
const wxString clbracket(_T(")"))
bool IsSameAs(const wxString &s, bool caseSensitive=true) const
const wxChar dash_chr(_T('-'))
void SetState(TokenizerState state)
Set the Tokenizer skipping options.
Definition: tokenizer.h:109
wxString m_LastToken
hold the previous token string
Definition: parserthread.h:435
const wxChar eol_chr(_T('\n'))
void HandleIncludes()
handle include <XXXX> or include "XXXX" directive.
wxString ReadAngleBrackets()
read <> as a whole token
bool IsEmpty() const
bool m_IsConst
the member method is const (yes/no)
Definition: token.h:248
const wxChar ref_chr(_T('&'))
void HandleConditionalArguments()
parse arguments like: if(int X = getNumber())
const wxString kw_operator(_T("operator"))
bool NotEOF() const
return true if it is Not the end of buffer
Definition: tokenizer.h:183
const wxString ref(_T("&"))
bool IsOpened() const
Tokenizer m_Tokenizer
if we regard the parserThread class as a syntax analyzer, then the Tokenizer class is regard as the l...
Definition: parserthread.h:392
void SplitTemplateActualParameters(const wxString &templateArgs, wxArrayString &actuals)
Split actual template argument list.
const wxString kw_elif(_T("elif"))
const wxString g_UnnamedSymbol
bool wantPreprocessor
handle the #if like preprocessor directives, this value is passed to Tokenizer
Definition: parserthread.h:102
void clear()
const wxStringCharType * wx_str() const
bool InitFromBuffer(const wxString &buffer, const wxString &fileOfBuffer=wxEmptyString, size_t initLineNumber=0)
Initialize the buffer by directly using a wxString&#39;s content.
Definition: tokenizer.cpp:174
#define IS_ALIVE
wxString wxEmptyString
TokenScope
Definition: token.h:21
ParserThread(ParserBase *parent, const wxString &bufferOrFilename, bool isLocal, ParserThreadOptions &parserThreadOptions, TokenTree *tokenTree)
ParserThread constructor.
const wxString & _(const wxString &string)
virtual ~ParserThread()
ParserThread destructor.
wxString & Trim(bool fromRight=true)
void RefineAnonymousTypeToken(short int typeMask, wxString alise)
change an anonymous(unnamed) token&#39;s name to a human readable name, the m_Str is expect to store the ...
wxString m_Args
If it is a function Token, then this value is function arguments, e.g.
Definition: token.h:194
bool CalcPostfix()
Definition: expression.cpp:359
const wxString clbrace(_T("}"))
bool storeDocumentation
should tokenizer detect and store doxygen documentation?
Definition: parserthread.h:126
std::queue< wxString > m_EncounteredTypeNamespaces
namespaces in function return types for a function declaration below: e.g.
Definition: parserthread.h:451
wxString m_Str
This is a very important member variables! It serves as a type stack, eg: parsing the statement: "uns...
Definition: parserthread.h:432
const wxString opbracesemicolon(_T("{;"))
unsigned int m_ImplFileIdx
function implementation file index
Definition: token.h:216
#define cbThrow(message)
Definition: cbexception.h:42
Token * FindTokenFromQueue(std::queue< wxString > &q, Token *parent=0, bool createIfNotExist=false, Token *parentIfCreated=0)
TODO comment here?
const wxString kw_try(_T("try"))
bool wxIsalnum(const wxUniChar &c)
const wxString kw__CPP_(_T("\++\))
const wxChar semicolon_chr(_T(';'))
void SetLastTokenIdx(int tokenIdx)
a Token is added, associate doxygen style documents(comments before the variables) to the Token ...
Definition: tokenizer.cpp:1719
const wxString spaced_colon(_T(" : "))
TokenizerState
Enum defines the skip state of the Tokenizer.
Definition: tokenizer.h:19
wxString m_TemplateArgument
template argument list, comma separated list string
Definition: token.h:283
bool ToLong(long *val, int base=10) const
bool HasMoreTokens() const
undefined or just "all"
Definition: token.h:76
const wxString kw_typedef(_T("typedef"))
enum
Definition: token.h:40
bool IsEmpty() const
bool wxIsalpha(const wxUniChar &c)
void Clear()
const wxString kw_case(_T("case"))
const wxString kw_attribute(_T("__attribute__"))
bool IsStillAlive(const wxString &funcInfo)
Only for debug.
const wxString kw_using(_T("using"))
enumerator
Definition: token.h:60
size_t Len() const
void AddToInfixExpression(wxString token)
Definition: expression.cpp:232
any kind of functions
Definition: token.h:73
bool IsOK() const
If the buffer is correctly loaded, this function return true.
Definition: tokenizer.h:153
const wxString commasemicolonopbrace(_T(",;{"))
bool useBuffer
useBuffer specifies that we&#39;re not parsing a file, but a temporary buffer.
Definition: parserthread.h:71
const wxChar colon_chr(_T(':'))
const wxChar ptr_chr(_T(' *'))
bool InitTokenizer()
initialize the m_Buffer, load from local file or use a buffer in memory
TokenKind m_TokenKind
See TokenKind class.
Definition: token.h:234
void ResolveTemplateArgs(Token *newToken)
this function just associate the formal template argument to actual argument For example, we have such code:
read parentheses as a single token
Definition: tokenizer.h:22
bool EndsWith(const wxString &suffix, wxString *rest=NULL) const
Token * m_LastParent
parent Token, for example, when you are parsing in the class member variables, m_LastParent holds a p...
Definition: parserthread.h:405
bool GetStatus() const
Definition: expression.h:88
bool ParseBufferForUsingNamespace(const wxString &buffer, wxArrayString &result)
Get the context "using namespace XXX" directive.
wxString & Prepend(const wxString &str)
void Clear()
Definition: expression.cpp:226
general function, not constructor nor destructor
Definition: token.h:54
void HandleNamespace()
handle the statement: namespace XXX {
const wxString kw___asm(_T("__asm"))
size_t Add(const wxString &str, size_t copies=1)
const wxChar question_chr(_T('?'))
void HandleFunction(wxString &name, bool isOperator=false, bool isPointer=false)
handle function declaration or definition
const wxString kw_do(_T("do"))
const wxString ptr(_T("*"))
bool StartsWith(const wxString &prefix, wxString *rest=NULL) const
bool handleTypedefs
whether to parse "typedef ..." like statement
Definition: parserthread.h:123
const wxString quot(_T("\))
void HandleForLoopArguments()
parse for loop arguments: for(int X; ...
const wxString kw_catch(_T("catch"))
bool SkipToEOL()
Skip from the current position to the end of line, use with care outside this class! ...
Definition: tokenizer.cpp:555
size_t FindMatches(const wxString &query, TokenIdxSet &result, bool caseSensitive, bool is_prefix, TokenKind kindMask=tkUndefined)
find a collection of matched tokens
Definition: tokentree.cpp:266
size_t GetCount() const
int Find(wxUniChar ch, bool fromEnd=false) const
wxUniChar GetChar(size_t n) const
wxUniChar Last() const
bool followGlobalIncludes
parse the file in #include <file> directive
Definition: parserthread.h:99
size_t m_TokenTicketCount
Definition: tokentree.h:305
bool ReadClsNames(wxString &ancestor)
handle class names, e.g., the code below
const wxString hash(_T("#"))
const wxString kw_throw(_T("throw"))
size_t ReserveFileForParsing(const wxString &filename, bool preliminary=false)
mark a file to be parsed.
Definition: tokentree.cpp:896
const wxString kw___at(_T("__at"))
void RemoveAt(size_t nIndex, size_t count=1)
int initLineOfBuffer
since we are not parsing start from the first line of the file, this is the first line number of the ...
Definition: parserthread.h:84
int insert(Token *newToken)
add a new Token instance to the TokenTree
Definition: tokentree.cpp:111
int Printf(const wxString &pszFormat,...)
const wxString dcolon(_T("::"))
Definition: token.h:26
bool IsFileParsed(const wxString &filename)
is the file name is in the tokentree, and it&#39;s status is either assigned or beingparsed or done also...
Definition: tokentree.cpp:863
wxString m_FullType
this is the full return value (if any): e.g.
Definition: token.h:182
bool Init(const wxString &filename=wxEmptyString, LoaderBase *loader=0)
Initialize the buffer by opening a file through a loader, this function copy the contents from the lo...
Definition: tokenizer.cpp:126
void ConvertInfixToPostfix()
Definition: expression.cpp:250
const wxChar equals_chr(_T('='))
wxString GetTokenKindString() const
the token kind string, e.g.
Definition: token.cpp:311
bool bufferSkipBlocks
do we parse inside the {...} body
Definition: parserthread.h:87
#define NULL
Definition: prefix.cpp:59
bool m_IsLocal
if true, means the token belong to a C::B project, it exists in the project&#39;s source/header files...
Definition: token.h:242
const wxString kw_struct(_T("struct"))
const wxString kw_noexcept(_T("noexcept"))
static wxString Format(const wxString &format,...)
wxString Mid(size_t first, size_t nCount=wxString::npos) const
const wxChar null(_T('\0'))
size_t m_StructUnionUnnamedCount
Definition: parserthread.h:475
const wxString comma(_T(","))
wxString GetToken()
Consume and return the current token string.
Definition: tokenizer.cpp:839
const wxString lt(_T("<"))
TokenizerState GetState()
Return the token reading options value,.
Definition: tokenizer.h:115
wxString GetFullFileName(const wxString &src, const wxString &tgt, bool isGlobal)
wxString Name
Definition: parserthread.h:29
const wxChar plus_chr(_T('+'))
ParserThreadOptions m_Options
parser options, see the ParserThreadOptions structure
Definition: parserthread.h:438
TokenKind
Definition: token.h:29
bool AddChild(int childIdx)
add a child token
Definition: token.cpp:267
wxString m_Buffer
a wxString holding the parsing buffer, if it is a file in the hard disk, then this stands for the fil...
Definition: parserthread.h:467