Code::Blocks  SVN r11506
tokentree.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: 10503 $
6  * $Id: tokentree.cpp 10503 2015-09-26 13:33:16Z ollydbg $
7  * $HeadURL: https://svn.code.sf.net/p/codeblocks/code/trunk/src/plugins/codecompletion/parser/tokentree.cpp $
8  */
9 
10 #include "tokentree.h"
11 
12 #include <wx/tokenzr.h>
13 
14 #include <set>
15 
16 #include "cclogger.h"
17 
18 #define CC_TOKENTREE_DEBUG_OUTPUT 0
19 
20 #if defined(CC_GLOBAL_DEBUG_OUTPUT)
21  #if CC_GLOBAL_DEBUG_OUTPUT == 1
22  #undef CC_TOKENTREE_DEBUG_OUTPUT
23  #define CC_TOKENTREE_DEBUG_OUTPUT 1
24  #elif CC_GLOBAL_DEBUG_OUTPUT == 2
25  #undef CC_TOKENTREE_DEBUG_OUTPUT
26  #define CC_TOKENTREE_DEBUG_OUTPUT 2
27  #endif
28 #endif
29 
30 #if CC_TOKENTREE_DEBUG_OUTPUT == 1
31  #define TRACE(format, args...) \
32  CCLogger::Get()->DebugLog(F(format, ##args))
33  #define TRACE2(format, args...)
34 #elif CC_TOKENTREE_DEBUG_OUTPUT == 2
35  #define TRACE(format, args...) \
36  do \
37  { \
38  if (g_EnableDebugTrace) \
39  CCLogger::Get()->DebugLog(F(format, ##args)); \
40  } \
41  while (false)
42  #define TRACE2(format, args...) \
43  CCLogger::Get()->DebugLog(F(format, ##args))
44 #else
45  #define TRACE(format, args...)
46  #define TRACE2(format, args...)
47 #endif
48 
50 
52  m_TokenTicketCount(255) // Reserve some space for the class browser
53 {
54  m_Tokens.clear();
55  m_Tree.clear();
56 
58  m_FileMap.clear();
59  m_FilesToBeReparsed.clear();
60  m_FreeTokens.clear();
61 
62  m_TopNameSpaces.clear();
63  m_GlobalNameSpaces.clear();
64 
65  m_FileStatusMap.clear();
66 }
67 
68 
70 {
71  clear();
72 }
73 
75 {
76  m_Tree.clear();
77 
79  m_FileMap.clear();
80  m_FilesToBeReparsed.clear();
81  m_FreeTokens.clear();
82 
83  m_TopNameSpaces.clear();
84  m_GlobalNameSpaces.clear();
85 
86  m_FileStatusMap.clear();
87 
88  size_t i;
89  for (i = 0;i < m_Tokens.size(); ++i)
90  {
91  Token* token = m_Tokens[i];
92  if (token)
93  delete token;
94  }
95  m_Tokens.clear();
96 }
97 
99 {
100  return m_Tokens.size();
101 }
102 
104 {
105  if (m_Tokens.size() <= m_FreeTokens.size())
106  return 0;
107 
108  return m_Tokens.size() - m_FreeTokens.size();
109 }
110 
111 int TokenTree::insert(Token* newToken)
112 {
113  if (!newToken)
114  return -1;
115 
116  return AddToken(newToken, -1); // -1 means we add a new slot to the Token list (vector)
117 }
118 
119 int TokenTree::insert(int loc, Token* newToken)
120 {
121  if (!newToken)
122  return -1;
123 
124  return AddToken(newToken, loc);
125 }
126 
127 int TokenTree::erase(int loc)
128 {
129  if (!m_Tokens[loc])
130  return 0;
131 
132  RemoveToken(loc);
133  return 1;
134 }
135 
136 void TokenTree::erase(Token* oldToken)
137 {
138  RemoveToken(oldToken);
139 }
140 
141 int TokenTree::TokenExists(const wxString& name, int parent, short int kindMask)
142 {
143  int idx = m_Tree.GetItemNo(name);
144  if (!idx)
145  return -1;
146 
147  TokenIdxSet& curList = m_Tree.GetItemAtPos(idx);
148  for (TokenIdxSet::const_iterator it = curList.begin(); it != curList.end(); ++it)
149  {
150  int result = *it;
151  if (result < 0 || (size_t)result >= m_Tokens.size())
152  continue;
153 
154  const Token* curToken = m_Tokens[result];
155  if (!curToken)
156  continue;
157 
158  if ((curToken->m_ParentIndex == parent) && (curToken->m_TokenKind & kindMask))
159  {
160  return result;
161  }
162  }
163 
164  return -1;
165 }
166 
167 int TokenTree::TokenExists(const wxString& name, const wxString& baseArgs, int parent, TokenKind kind)
168 {
169  int idx = m_Tree.GetItemNo(name);
170  if (!idx)
171  return -1;
172 
173  TokenIdxSet::const_iterator it;
174  TokenIdxSet& curList = m_Tree.GetItemAtPos(idx);
175  for (it = curList.begin(); it != curList.end(); ++it)
176  {
177  int result = *it;
178  if (result < 0 || (size_t)result >= m_Tokens.size())
179  continue;
180 
181  const Token* curToken = m_Tokens[result];
182  if (!curToken)
183  continue;
184 
185  // for a container token, its args member variable is used to store inheritance information
186  // so, don't compare args for tkAnyContainer
187  if ( (curToken->m_ParentIndex == parent)
188  && (curToken->m_TokenKind == kind)
189  && (curToken->m_BaseArgs == baseArgs || kind & tkAnyContainer) )
190  {
191  return result;
192  }
193  }
194 
195  return -1;
196 }
197 
198 int TokenTree::TokenExists(const wxString& name, const TokenIdxSet& parents, short int kindMask)
199 {
200  int idx = m_Tree.GetItemNo(name);
201  if (!idx)
202  return -1;
203 
204  TokenIdxSet::const_iterator it;
205  TokenIdxSet& curList = m_Tree.GetItemAtPos(idx);
206  for (it = curList.begin(); it != curList.end(); ++it)
207  {
208  int result = *it;
209  if (result < 0 || (size_t)result >= m_Tokens.size())
210  continue;
211 
212  const Token* curToken = m_Tokens[result];
213  if (!curToken)
214  continue;
215 
216  if (curToken->m_TokenKind & kindMask)
217  {
218  for ( TokenIdxSet::const_iterator pIt = parents.begin();
219  pIt != parents.end(); ++pIt )
220  {
221  if (curToken->m_ParentIndex == *pIt)
222  return result;
223  }
224  }
225  }
226 
227  return -1;
228 }
229 
230 int TokenTree::TokenExists(const wxString& name, const wxString& baseArgs, const TokenIdxSet& parents, TokenKind kind)
231 {
232  int idx = m_Tree.GetItemNo(name);
233  if (!idx)
234  return -1;
235 
236  TokenIdxSet::const_iterator it;
237  TokenIdxSet& curList = m_Tree.GetItemAtPos(idx);
238  for (it = curList.begin(); it != curList.end(); ++it)
239  {
240  int result = *it;
241  if (result < 0 || (size_t)result >= m_Tokens.size())
242  continue;
243 
244  const Token* curToken = m_Tokens[result];
245  if (!curToken)
246  continue;
247 
248  // for a container token, their args member variable is used to store inheritance information
249  // so, don't compare args for tkAnyContainer
250  if ( curToken->m_TokenKind == kind
251  && ( curToken->m_BaseArgs == baseArgs
252  || kind & tkAnyContainer ))
253  {
254  for ( TokenIdxSet::const_iterator pIt = parents.begin();
255  pIt != parents.end(); ++pIt )
256  {
257  if (curToken->m_ParentIndex == *pIt)
258  return result;
259  }
260  }
261  }
262 
263  return -1;
264 }
265 
266 size_t TokenTree::FindMatches(const wxString& query, TokenIdxSet& result, bool caseSensitive,
267  bool is_prefix, TokenKind kindMask)
268 {
269  result.clear();
270 
271  std::set<size_t> lists;
272  int numitems = m_Tree.FindMatches(query, lists, caseSensitive, is_prefix);
273  if (!numitems)
274  return 0;
275 
276  // now the lists contains indexes to all the matching keywords
277  // first loop will find all the keywords
278  for (std::set<size_t>::const_iterator it = lists.begin(); it != lists.end(); ++it)
279  {
280  const TokenIdxSet* curset = &(m_Tree.GetItemAtPos(*it));
281  // second loop will get all the items mapped by the same keyword,
282  // for example, we have ClassA::foo, ClassB::foo ...
283  if (curset)
284  {
285  for (TokenIdxSet::const_iterator it2 = curset->begin(); it2 != curset->end(); ++it2)
286  {
287  const Token* token = at(*it2);
288  if ( token
289  && ( (kindMask == tkUndefined)
290  || (token->m_TokenKind & kindMask) ) )
291  result.insert(*it2);
292  }
293  }
294  }
295  return result.size();
296 }
297 
298 size_t TokenTree::FindTokensInFile(const wxString& filename, TokenIdxSet& result, short int kindMask)
299 {
300  result.clear();
301 
302  // get file idx
303  wxString f(filename);
304  // convert the UNIX path style
305  while (f.Replace(_T("\\"),_T("/")))
306  { ; }
307 
308  if ( !m_FilenameMap.HasItem(f) )
309  {
310  TRACE(_T("TokenTree::FindTokensInFile() : File '%s' not found in file names map."), f.wx_str());
311  return 0;
312  }
313 
314  int idx = m_FilenameMap.GetItemNo(f);
315 
316  // now get the tokens set matching this file idx
317  TokenFileMap::iterator itf = m_FileMap.find(idx);
318  if (itf == m_FileMap.end())
319  {
320  TRACE(_T("TokenTree::FindTokensInFile() : No tokens found for file '%s' (index %d)."), f.wx_str(), idx);
321  return 0;
322  }
323 
324  // loop all results and add to final result set after filtering on token kind
325  TokenIdxSet& tokens = itf->second;
326  for (TokenIdxSet::const_iterator it = tokens.begin(); it != tokens.end(); ++it)
327  {
328  const Token* token = at(*it);
329  if (token && (kindMask & token->m_TokenKind))
330  result.insert(*it);
331  }
332 
333  TRACE(_T("TokenTree::FindTokensInFile() : Found %lu results for file '%s'."),
334  static_cast<unsigned long>(result.size()), f.wx_str());
335  return result.size();
336 }
337 
338 void TokenTree::RenameToken(Token* token, const wxString& newName)
339 {
340  if (!token)
341  return;
342  // remove the old token index from the TokenIdxSet mapped by old name.
343  int slotNo = m_Tree.GetItemNo(token->m_Name);
344  if (slotNo)
345  {
346  TokenIdxSet& curList = m_Tree.GetItemAtPos(slotNo);
347  // Note: As we have no way to actually delete keys in the TokenSearchTree,
348  // the previous name index path of the token will still exist, as well as its TokenIdxSet slot,
349  // but this slot will be empty and as result will lead to nothing.
350  // This is the same thing the RemoveToken procedure does.
351  curList.erase(token->m_Index);
352  };
353  token->m_Name = newName;
354 
355  static TokenIdxSet tmpTokens = TokenIdxSet();
356 
357  size_t tokenIdx = m_Tree.AddItem(newName, tmpTokens);
358  TokenIdxSet& curList = m_Tree.GetItemAtPos(tokenIdx);
359 
360  // add the old token index to the TokenIdxSet mapped by new name, note Token index is not changed
361  curList.insert(token->m_Index);
362 }
363 
364 int TokenTree::AddToken(Token* newToken, int forceIdx)
365 {
366  if (!newToken)
367  return -1;
368 
369  const wxString & name = newToken->m_Name;
370 
371  static TokenIdxSet tmpTokens = TokenIdxSet();
372 
373  // Insert the token's name and the token in the (inserted?) list
374  size_t tokenIdx = m_Tree.AddItem(name, tmpTokens);
375  TokenIdxSet& curList = m_Tree.GetItemAtPos(tokenIdx);
376 
377  int newItem = AddTokenToList(newToken, forceIdx);
378  curList.insert(newItem);
379 
380  size_t fIdx = newToken->m_FileIdx;
381  m_FileMap[fIdx].insert(newItem);
382 
383  // Add Token (if applicable) to the namespaces indexes
384  if (newToken->m_ParentIndex < 0)
385  {
386  newToken->m_ParentIndex = -1;
387  m_GlobalNameSpaces.insert(newItem);
388  if (newToken->m_TokenKind == tkNamespace)
389  m_TopNameSpaces.insert(newItem);
390  }
391 
392  // All done!
393  return newItem;
394 }
395 
397 {
398  if (idx<0 || (size_t)idx >= m_Tokens.size())
399  return;
400 
401  RemoveToken(m_Tokens[idx]);
402 }
403 
405 {
406  if (!oldToken)
407  return;
408 
409  int idx = oldToken->m_Index;
410  if (m_Tokens[idx]!=oldToken)
411  return;
412 
413  // Step 1: Detach token from its parent
414 
415  Token* parentToken = 0;
416  if ((size_t)(oldToken->m_ParentIndex) >= m_Tokens.size())
417  oldToken->m_ParentIndex = -1;
418  if (oldToken->m_ParentIndex >= 0)
419  parentToken = m_Tokens[oldToken->m_ParentIndex];
420  if (parentToken)
421  parentToken->m_Children.erase(idx);
422 
423  TokenIdxSet nodes;
424  TokenIdxSet::const_iterator it;
425 
426  // Step 2: Detach token from its ancestors
427 
428  nodes = (oldToken->m_DirectAncestors);
429  for (it = nodes.begin();it!=nodes.end(); ++it)
430  {
431  int ancestoridx = *it;
432  if (ancestoridx < 0 || (size_t)ancestoridx >= m_Tokens.size())
433  continue;
434  Token* ancestor = m_Tokens[ancestoridx];
435  if (ancestor)
436  ancestor->m_Descendants.erase(idx);
437  }
438  oldToken->m_Ancestors.clear();
439  oldToken->m_DirectAncestors.clear();
440 
441  // Step 3: Remove children
442 
443  nodes = (oldToken->m_Children); // Copy the list to avoid interference
444  for (it = nodes.begin();it!=nodes.end(); ++it)
445  RemoveToken(*it);
446  // m_Children SHOULD be empty by now - but clear anyway.
447  oldToken->m_Children.clear();
448 
449  // Step 4: Remove descendants
450 
451  nodes = oldToken->m_Descendants; // Copy the list to avoid interference
452  for (it = nodes.begin();it!=nodes.end(); ++it)
453  {
454  if (*it == idx) // that should not happen, we can not be our own descendant, but in fact that can happen with boost
455  {
456  CCLogger::Get()->DebugLog(_T("Break out the loop to remove descendants, to avoid a crash. We can not be our own descendant!"));
457  break;
458  }
459  RemoveToken(*it);
460  }
461  // m_Descendants SHOULD be empty by now - but clear anyway.
462  oldToken->m_Descendants.clear();
463 
464  // Step 5: Detach token from the SearchTrees
465 
466  int idx2 = m_Tree.GetItemNo(oldToken->m_Name);
467  if (idx2)
468  {
469  TokenIdxSet& curList = m_Tree.GetItemAtPos(idx2);
470  curList.erase(idx);
471  }
472 
473  // Now, from the global namespace (if applicable)
474  if (oldToken->m_ParentIndex == -1)
475  {
476  m_GlobalNameSpaces.erase(idx);
477  m_TopNameSpaces.erase(idx);
478  }
479 
480  // Step 6: Finally, remove it from the list.
481 
482  RemoveTokenFromList(idx);
483 }
484 
485 int TokenTree::AddTokenToList(Token* newToken, int forceidx)
486 {
487  if (!newToken)
488  return -1;
489 
490  int result = -1;
491 
492  // if the token index is specified, then just replace the specified slot to the newToken, this
493  // usually happens we construct the whole TokenTree from cache.
494  // other wise, we just append one to the vector or reused free slots stored in m_FreeTokens
495  // so, it is normal case in any parsing stages.
496  if (forceidx >= 0)
497  {
498  if ((size_t)forceidx >= m_Tokens.size())
499  {
500  int max = 250*((forceidx + 250) / 250);
501  m_Tokens.resize((max),0); // fill next 250 items with null-values
502  }
503  m_Tokens[forceidx] = newToken;
504  result = forceidx;
505  }
506  else
507  {
508  if (m_FreeTokens.size())
509  {
510  result = m_FreeTokens.back();
511  m_FreeTokens.pop_back();
512  m_Tokens[result] = newToken;
513  }
514  else
515  {
516  result = m_Tokens.size();
517  m_Tokens.push_back(newToken);
518  }
519  }
520 
521  newToken->m_TokenTree = this;
522  newToken->m_Index = result;
523 
524  // Clean up extra string memory
525  newToken->m_FullType.Shrink();
526  newToken->m_BaseType.Shrink();
527  newToken->m_Name.Shrink();
528  newToken->m_Args.Shrink();
529  newToken->m_BaseArgs.Shrink();
530  newToken->m_AncestorsString.Shrink();
531  newToken->m_TemplateArgument.Shrink();
532 
533  return result;
534 }
535 
537 {
538  if (idx < 0 || (size_t)idx >= m_Tokens.size())
539  return;
540  Token* oldToken = m_Tokens[idx];
541  if (oldToken)
542  {
543  m_Tokens[idx] = 0;
544  m_FreeTokens.push_back(idx);
545  delete oldToken;
546  }
547 }
548 
549 void TokenTree::RemoveFile(const wxString& filename)
550 {
551  RemoveFile( InsertFileOrGetIndex(filename) );
552 }
553 
554 void TokenTree::RemoveFile(int fileIdx)
555 {
556  if (fileIdx <= 0) return; // nothing to do
557 
558  TokenIdxSet& the_list = m_FileMap[fileIdx];
559  for (TokenIdxSet::const_iterator it = the_list.begin(); it != the_list.end();)
560  {
561  int idx = *it;
562  if (idx < 0 || (size_t)idx > m_Tokens.size())
563  {
564  the_list.erase(it++);
565  continue;
566  }
567 
568  Token* the_token = at(idx);
569  if (!the_token)
570  {
571  the_list.erase(it++);
572  continue;
573  }
574 
575  // do not remove token lightly...
576  // only if both its decl filename and impl filename are either empty or match this file
577  // if one of those filenames do not match the above criteria
578  // just clear the relevant info, leaving the token where it is...
579  bool match1 = the_token->m_FileIdx == 0 || static_cast<int>(the_token->m_FileIdx) == fileIdx;
580  bool match2 = the_token->m_ImplFileIdx == 0 || static_cast<int>(the_token->m_ImplFileIdx) == fileIdx;
581  bool match3 = CheckChildRemove(the_token, fileIdx);
582  if (match1 && match2 && match3)
583  {
584  RemoveToken(the_token); // safe to remove the token
585  the_list.erase(it++);
586  continue;
587  }
588  else
589  {
590  // do not remove token, just clear the matching info
591  if (match1)
592  {
593  the_token->m_FileIdx = 0;
594  the_token->m_Line = 0;
595  the_token->m_Doc.clear();
596  }
597  else if (match2)
598  {
599  the_token->m_ImplFileIdx = 0;
600  the_token->m_ImplLine = 0;
601  the_token->m_ImplDoc.clear();
602  }
603  }
604 
605  ++it;
606  }
607 }
608 
609 bool TokenTree::CheckChildRemove(const Token* token, int fileIdx)
610 {
611  const TokenIdxSet& nodes = (token->m_Children); // Copy the list to avoid interference
612  TokenIdxSet::const_iterator it;
613  for (it = nodes.begin(); it != nodes.end(); ++it)
614  {
615  int idx = *it;
616  if (idx < 0 || (size_t)idx > m_Tokens.size())
617  continue;
618 
619  const Token* the_token = at(idx);
620  if (!the_token)
621  continue;
622 
623  bool match1 = the_token->m_FileIdx == 0 || static_cast<int>(the_token->m_FileIdx) == fileIdx;
624  bool match2 = the_token->m_ImplFileIdx == 0 || static_cast<int>(the_token->m_ImplFileIdx) == fileIdx;
625  if (match1 && match2)
626  continue;
627  else
628  return false; // one child is belong to another file
629  }
630  return true; // no children should be reserved, so we can safely remove the token
631 }
632 
634 {
635  m_FreeTokens.clear();
636  for (int i = m_Tokens.size() - 1; i >= 0; --i)
637  {
638  if (!m_Tokens[i])
639  m_FreeTokens.push_back(i);
640  }
641 }
642 
644 {
645  if (!token)
646  return;
647  if (!(token->m_TokenKind & (tkClass | tkTypedef | tkEnum | tkNamespace)))
648  return;
649  if (token->m_AncestorsString.IsEmpty())
650  return;
651 
652  token->m_DirectAncestors.clear();
653  token->m_Ancestors.clear();
654 
655  wxStringTokenizer tkz(token->m_AncestorsString, _T(","));
656  TRACE(_T("RecalcInheritanceChain() : Token %s, Ancestors %s"), token->m_Name.wx_str(),
657  token->m_AncestorsString.wx_str());
658  TRACE(_T("RecalcInheritanceChain() : Removing ancestor string from %s"), token->m_Name.wx_str());
659  token->m_AncestorsString.Clear();
660 
661  while (tkz.HasMoreTokens())
662  {
663  wxString ancestor = tkz.GetNextToken();
664  if (ancestor.IsEmpty() || ancestor == token->m_Name)
665  continue;
666 
667  TRACE(_T("RecalcInheritanceChain() : Ancestor %s"), ancestor.wx_str());
668 
669  // ancestors might contain namespaces, e.g. NS::Ancestor
670  if (ancestor.Find(_T("::")) != wxNOT_FOUND)
671  {
672  Token* ancestorToken = 0;
673  wxStringTokenizer anctkz(ancestor, _T("::"));
674  while (anctkz.HasMoreTokens())
675  {
676  wxString ns = anctkz.GetNextToken();
677  if (!ns.IsEmpty())
678  {
679  int ancestorIdx = TokenExists(ns, ancestorToken ? ancestorToken->m_Index : -1,
681  ancestorToken = at(ancestorIdx);
682  if (!ancestorToken) // unresolved
683  break;
684  }
685  }
686  if ( ancestorToken
687  && ancestorToken != token
688  && (ancestorToken->m_TokenKind == tkClass || ancestorToken->m_TokenKind == tkNamespace) )
689  {
690  TRACE(_T("RecalcInheritanceChain() : Resolved to %s"), ancestorToken->m_Name.wx_str());
691  RecalcInheritanceChain(ancestorToken);
692  token->m_Ancestors.insert(ancestorToken->m_Index);
693  ancestorToken->m_Descendants.insert(token->m_Index);
694  TRACE(_T("RecalcInheritanceChain() : + '%s'"), ancestorToken->m_Name.wx_str());
695  }
696  else
697  {
698  TRACE(_T("RecalcInheritanceChain() : ! '%s' (unresolved)"), ancestor.wx_str());
699  }
700  }
701  else // no namespaces in ancestor
702  {
703  // accept multiple matches for inheritance
704  TokenIdxSet result;
705  FindMatches(ancestor, result, true, false);
706  for (TokenIdxSet::const_iterator it = result.begin(); it != result.end(); ++it)
707  {
708  Token* ancestorToken = at(*it);
709  // only classes take part in inheritance
710  if ( ancestorToken
711  && (ancestorToken != token)
712  && ( (ancestorToken->m_TokenKind == tkClass)
713  || (ancestorToken->m_TokenKind == tkEnum)
714  || (ancestorToken->m_TokenKind == tkTypedef)
715  || (ancestorToken->m_TokenKind == tkNamespace) ) )
716  {
717  RecalcInheritanceChain(ancestorToken);
718  token->m_Ancestors.insert(*it);
719  ancestorToken->m_Descendants.insert(token->m_Index);
720  TRACE(_T("RecalcInheritanceChain() : + '%s'"), ancestorToken->m_Name.wx_str());
721  }
722  }
723 #if defined(CC_TOKEN_DEBUG_OUTPUT)
724  #if CC_TOKEN_DEBUG_OUTPUT
725  if (result.empty())
726  TRACE(_T("RecalcInheritanceChain() : ! '%s' (unresolved)"), ancestor.wx_str());
727  #endif
728 #endif
729  }
730 
731  // Now, we have calc all the direct ancestors
732  token->m_DirectAncestors = token->m_Ancestors;
733  }
734 
735 #if defined(CC_TOKEN_DEBUG_OUTPUT)
736  #if CC_TOKEN_DEBUG_OUTPUT
737  wxStopWatch sw;
738  TRACE(_T("RecalcInheritanceChain() : First iteration took : %ld ms"), sw.Time());
739  sw.Start();
740  #endif
741 #endif
742 
743  // recalc
744  TokenIdxSet result;
745  for (TokenIdxSet::const_iterator it = token->m_Ancestors.begin(); it != token->m_Ancestors.end(); ++it)
746  RecalcFullInheritance(*it, result);
747 
748  // now, add the resulting set to ancestors set
749  for (TokenIdxSet::const_iterator it = result.begin(); it != result.end(); ++it)
750  {
751  Token* ancestor = at(*it);
752  if (ancestor)
753  {
754  token->m_Ancestors.insert(*it);
755  ancestor->m_Descendants.insert(token->m_Index);
756  }
757  }
758 
759 #if defined(CC_TOKEN_DEBUG_OUTPUT)
760  #if CC_TOKEN_DEBUG_OUTPUT
761  if (token)
762  {
763  // debug loop
764  TRACE(_T("RecalcInheritanceChain() : Ancestors for %s:"), token->m_Name.wx_str());
765  for (TokenIdxSet::const_iterator it = token->m_Ancestors.begin(); it != token->m_Ancestors.end(); ++it)
766  {
767  const Token* anc_token = at(*it);
768  if (anc_token)
769  TRACE(_T("RecalcInheritanceChain() : + %s"), anc_token->m_Name.wx_str());
770  else
771  TRACE(_T("RecalcInheritanceChain() : + NULL?!"));
772  }
773  }
774  #endif
775 #endif
776 
777 #if defined(CC_TOKEN_DEBUG_OUTPUT)
778  #if CC_TOKEN_DEBUG_OUTPUT
779  TRACE(_T("RecalcInheritanceChain() : Second iteration took : %ld ms"), sw.Time());
780  #endif
781 #endif
782 
783  TRACE(_T("RecalcInheritanceChain() : Full inheritance calculated."));
784 }
785 
786 // caches the inheritance info for each token (recursive function)
787 void TokenTree::RecalcFullInheritance(int parentIdx, TokenIdxSet& result)
788 {
789  // no parent token? no ancestors...
790  if (parentIdx == -1)
791  return;
792 
793  // no parent token? no ancestors...
794  const Token* ancestor = at(parentIdx);
795  if (!ancestor)
796  return;
797 
798  // only classes take part in inheritance
799  if ( !(ancestor->m_TokenKind & (tkClass | tkTypedef)) )
800  return;
801 
802  TRACE(_T("RecalcFullInheritance() : Anc: '%s'"), ancestor->m_Name.wx_str());
803 
804  // for all its ancestors
805  for (TokenIdxSet::const_iterator it = ancestor->m_Ancestors.begin(); it != ancestor->m_Ancestors.end(); ++it)
806  {
807  if (*it != -1 && // not global scope
808  *it != parentIdx && // not the same token (avoid infinite loop)
809  result.find(*it) == result.end()) // not already in the set (avoid infinite loop)
810  {
811  // add it to the set
812  result.insert(*it);
813  // and recurse for its ancestors
814  RecalcFullInheritance(*it, result);
815  }
816  }
817 }
818 
820 {
821  if (idx < 0 || (size_t)idx >= m_Tokens.size())
822  return 0;
823 
824  return m_Tokens[idx];
825 }
826 
827 const Token* TokenTree::GetTokenAt(int idx) const
828 {
829  if (idx < 0 || (size_t)idx >= m_Tokens.size())
830  return 0;
831 
832  return m_Tokens[idx];
833 }
834 
836 {
837  wxString f(filename); while (f.Replace(_T("\\"),_T("/"))) { ; }
838 
839  // Insert does not alter the tree if the filename is already found.
840  return m_FilenameMap.insert(f);
841 }
842 
843 size_t TokenTree::GetFileMatches(const wxString& filename, std::set<size_t>& result,
844  bool caseSensitive, bool is_prefix)
845 {
846  wxString f(filename); while (f.Replace(_T("\\"),_T("/"))) { ; }
847 
848  return m_FilenameMap.FindMatches(f, result, caseSensitive, is_prefix);
849 }
850 
851 size_t TokenTree::GetFileIndex(const wxString& filename)
852 {
853  wxString f(filename); while (f.Replace(_T("\\"),_T("/"))) { ; }
854 
855  return m_FilenameMap.GetItemNo(f);
856 }
857 
858 const wxString TokenTree::GetFilename(size_t fileIdx) const
859 {
860  return m_FilenameMap.GetString(fileIdx);
861 }
862 
863 bool TokenTree::IsFileParsed(const wxString& filename)
864 {
865  size_t fileIdx = InsertFileOrGetIndex(filename);
866 
867  bool parsed = ( m_FileMap.count(fileIdx)
868  && (m_FileStatusMap[fileIdx]!=fpsNotParsed)
869  && !m_FilesToBeReparsed.count(fileIdx) );
870 
871  return parsed;
872 }
873 
874 void TokenTree::MarkFileTokensAsLocal(const wxString& filename, bool local, void* userData)
875 {
876  MarkFileTokensAsLocal( InsertFileOrGetIndex(filename), local, userData );
877 }
878 
879 void TokenTree::MarkFileTokensAsLocal(size_t fileIdx, bool local, void* userData)
880 {
881  if (!fileIdx)
882  return;
883 
884  TokenIdxSet& tokens = m_FileMap[fileIdx];
885  for (TokenIdxSet::const_iterator it = tokens.begin(); it != tokens.end(); ++it)
886  {
887  Token* token = m_Tokens.at(*it);
888  if (token)
889  {
890  token->m_IsLocal = local; // only the tokens belong to project files are marked as local
891  token->m_UserData = userData; // a pointer to the c::b project
892  }
893  }
894 }
895 
896 size_t TokenTree::ReserveFileForParsing(const wxString& filename, bool preliminary)
897 {
898  const size_t fileIdx = InsertFileOrGetIndex(filename);
899  if ( m_FilesToBeReparsed.count(fileIdx)
900  && (!m_FileStatusMap.count(fileIdx) || m_FileStatusMap[fileIdx]==fpsDone) )
901  {
902  RemoveFile(filename);
903  m_FilesToBeReparsed.erase(fileIdx);
904  m_FileStatusMap[fileIdx]=fpsNotParsed;
905  }
906 
907  if (m_FileStatusMap.count(fileIdx))
908  {
909  FileParsingStatus status = m_FileStatusMap[fileIdx];
910  if (preliminary)
911  {
912  if (status >= fpsAssigned)
913  return 0; // Already assigned
914  }
915  else
916  {
917  if (status > fpsAssigned)
918  return 0; // No parsing needed
919  }
920  }
921  m_FilesToBeReparsed.erase(fileIdx);
922  m_FileStatusMap[fileIdx] = preliminary ? fpsAssigned : fpsBeingParsed; // Reserve file
923  return fileIdx;
924 }
925 
927 {
928  m_FilesToBeReparsed.insert( InsertFileOrGetIndex(filename) );
929 }
930 
932 {
934 }
935 
936 void TokenTree::AppendDocumentation(int tokenIdx, unsigned int fileIdx, const wxString& doc)
937 {
938  // fetch the Token pointer
939  Token* tk = GetTokenAt(tokenIdx);
940  if (!tk)
941  return;
942  if (tk->m_FileIdx == fileIdx) // in the same file index
943  {
944  wxString& newDoc = tk->m_Doc;
945  if (newDoc == doc) // Do not duplicate
946  return;
947  newDoc += doc; // document could happens before and after the Token, we combine them
948  newDoc.Shrink();
949  }
950  else if (tk->m_ImplFileIdx == fileIdx)
951  {
952  wxString& newDoc = tk->m_ImplDoc;
953  if (newDoc == doc) // Do not duplicate
954  return;
955  newDoc += doc; // document could happens before and after the Token, we combine them
956  newDoc.Shrink();
957  }
958 }
959 
961 {
962  // fetch the Token pointer
963  Token* tk = GetTokenAt(tokenIdx);
964  if (!tk)
965  return wxEmptyString;
966  return tk->m_Doc + tk->m_ImplDoc;
967 }
int TokenExists(const wxString &name, int parent, short int kindMask)
query tokens by names
Definition: tokentree.cpp:141
wxMutex s_TokenTreeMutex
Definition: tokentree.cpp:49
namespace
Definition: token.h:34
int m_ParentIndex
Parent Token index.
Definition: token.h:265
TokenSearchTree m_Tree
This is a string->TokenIndexSet map.
Definition: tokentree.h:345
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
Token * at(int idx)
Definition: tokentree.h:51
virtual void clear()
Gets the number of items stored.
Definition: searchtree.h:431
wxString m_BaseType
this is what the parser believes is the actual return value: e.g.
Definition: token.h:185
void clear()
Definition: tokentree.cpp:74
static CCLogger * Get()
Definition: cclogger.cpp:60
size_t GetItemNo(const wxString &s)
Gets the array position defined by s.
Definition: searchtree.cpp:742
wxString m_Name
Token&#39;s name, it can be searched in the TokenTree.
Definition: token.h:188
unsigned int m_ImplLine
function implementation line index
Definition: token.h:219
T & GetItemAtPos(size_t i)
Gets the item found at position i, the i is the item index.
Definition: searchtree.h:488
typedef, note typedefs are stored as classes inheriting from the typedef&#39;d type, this takes advantage...
Definition: token.h:45
int erase(int loc)
remove the Token specified by the index
Definition: tokentree.cpp:127
container like tokens, those tokens can have children tokens
Definition: token.h:70
const wxString GetFilename(size_t fileIdx) const
Definition: tokentree.cpp:858
virtual ~TokenTree()
Definition: tokentree.cpp:69
wxString m_BaseArgs
stripped arguments e.g.
Definition: token.h:197
void FlagFileAsParsed(const wxString &filename)
mark the file status as fpsDone, since parsing this file is done
Definition: tokentree.cpp:931
virtual void clear()
Gets the number of items stored.
Definition: searchtree.cpp:542
TokenList m_Tokens
Contains the pointers to all the Token instances, it is just a std::vector<Token*>, the suggest way to access a Token instance is by first get its index in the m_Tokens, then get its address by m_Tokens[index], the reason we have such indirect access is that there are many Tokens which can reference each other, it is much safe using index instead of raw pointers.
Definition: tokentree.h:353
TokenIdxSet m_Children
if it is a class kind token, then it contains all the member tokens
Definition: token.h:268
void * m_UserData
custom user-data (the classbrowser expects it to be a pointer to a cbProject), this field is used whe...
Definition: token.h:300
TokenFileMap m_FileMap
Map: file indices -> sets of TokenIndexes.
Definition: tokentree.h:372
long Time() const
TokenIdxSet m_Ancestors
all the ancestors in the inheritance hierarchy
Definition: token.h:271
#define _T(string)
size_t realsize()
some position of the std::vector<Token*> are not used, so the real size maybe a bit smaller than the ...
Definition: tokentree.cpp:103
TokenFileStatusMap m_FileStatusMap
Map: file indices -> status.
Definition: tokentree.h:375
unsigned int m_Line
Line index where the token was met, which is 1 based.
Definition: token.h:210
wxString GetNextToken()
size_t size()
total size of std::vector<Token*>
Definition: tokentree.cpp:98
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
size_t FindMatches(const wxString &s, std::set< size_t > &result, bool caseSensitive, bool is_prefix)
Finds items that match a given string.
Definition: searchtree.cpp:750
void AppendDocumentation(int tokenIdx, unsigned int fileIdx, const wxString &doc)
associate a document string with the token
Definition: tokentree.cpp:936
#define wxNOT_FOUND
wxString m_AncestorsString
all ancestors comma-separated list, e.g.
Definition: token.h:204
void RecalcFreeList()
collect the unused slots in the std::vector<Token*>
Definition: tokentree.cpp:633
void DebugLog(const wxString &msg)
Definition: cclogger.cpp:107
size_t AddItem(const wxString &s, T item, bool replaceexisting=false)
Adds an item to position defined by s and return the item number.
Definition: searchtree.h:474
void RecalcInheritanceChain(Token *token)
convert the Token&#39;s ancestor string to it&#39;s IDs this contains recursive calls, for example in such co...
Definition: tokentree.cpp:643
void RecalcFullInheritance(int parentIdx, TokenIdxSet &result)
Definition: tokentree.cpp:787
unsigned int m_FileIdx
File index in TokenTree.
Definition: token.h:207
wxString m_Doc
doxygen style comments
Definition: token.h:213
bool Shrink()
bool CheckChildRemove(const Token *token, int fileIdx)
Check all the children belong this token should be removed.
Definition: tokentree.cpp:609
void RemoveFile(const wxString &filename)
remove tokens belong to the file
Definition: tokentree.cpp:549
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
int AddTokenToList(Token *newToken, int forceidx=-1)
add the Token pointer to the vector<Token*>, mostly the default value forceidx = -1 is used which add...
Definition: tokentree.cpp:485
std::set< int, std::less< int > > TokenIdxSet
Definition: token.h:16
size_t GetFileIndex(const wxString &filename)
Definition: tokentree.cpp:851
size_t Replace(const wxString &strOld, const wxString &strNew, bool replaceAll=true)
#define TRACE(format, args...)
Definition: tokentree.cpp:45
size_t FindTokensInFile(const wxString &filename, TokenIdxSet &result, short int kindMask)
find tokens belong to a specified file
Definition: tokentree.cpp:298
void clear()
const wxStringCharType * wx_str() const
wxString wxEmptyString
void MarkFileTokensAsLocal(const wxString &filename, bool local=true, void *userData=0)
mark the tokens so that they are associated with a C::B project
Definition: tokentree.cpp:874
wxString m_Args
If it is a function Token, then this value is function arguments, e.g.
Definition: token.h:194
unsigned int m_ImplFileIdx
function implementation file index
Definition: token.h:216
wxString m_TemplateArgument
template argument list, comma separated list string
Definition: token.h:283
bool HasMoreTokens() const
undefined or just "all"
Definition: token.h:76
enum
Definition: token.h:40
TokenIdxSet m_Descendants
all the descendants in the inheritance hierarchy
Definition: token.h:277
bool IsEmpty() const
TokenTree * m_TokenTree
a pointer to TokenTree
Definition: token.h:305
void Clear()
size_t GetFileMatches(const wxString &filename, std::set< size_t > &result, bool caseSensitive, bool is_prefix)
Definition: tokentree.cpp:843
void Start(long milliseconds=0)
wxString GetDocumentation(int tokenIdx)
get the document string associated with the token
Definition: tokentree.cpp:960
TokenKind m_TokenKind
See TokenKind class.
Definition: token.h:234
Token * GetTokenAt(int idx)
Definition: tokentree.cpp:819
size_t insert(const wxString &s)
Clear items and tree.
Definition: searchtree.cpp:822
TokenIdxSet m_GlobalNameSpaces
any tokens belong to the global namespace
Definition: tokentree.h:366
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
void RemoveToken(int idx)
Definition: tokentree.cpp:396
int Find(wxUniChar ch, bool fromEnd=false) const
void RemoveTokenFromList(int idx)
Remove the Token specified by the idx in the vector<Token*>, note the Token instance is destroyed...
Definition: tokentree.cpp:536
TokenIdxSet m_TopNameSpaces
namespace tokens belongs to the global namespace
Definition: tokentree.h:363
TokenFileSet m_FilesToBeReparsed
Set: file indices.
Definition: tokentree.h:378
TokenFilenameMap m_FilenameMap
Map: file names -> file indices.
Definition: tokentree.h:369
size_t ReserveFileForParsing(const wxString &filename, bool preliminary=false)
mark a file to be parsed.
Definition: tokentree.cpp:896
wxString m_ImplDoc
doxygen style comments in the Impl file
Definition: token.h:228
int insert(Token *newToken)
add a new Token instance to the TokenTree
Definition: tokentree.cpp:111
FileParsingStatus
Definition: tokentree.h:18
const wxString GetString(size_t n) const
Gets the key string for item n.
Definition: searchtree.cpp:556
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
void FlagFileForReparsing(const wxString &filename)
mark the file as "need to be reparsed" status, usually happens that this file is saved(updated) so a ...
Definition: tokentree.cpp:926
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
TokenIdxList m_FreeTokens
List of all the deleted (and available) tokens.
Definition: tokentree.h:360
TokenIdxSet m_DirectAncestors
the nearest ancestors
Definition: token.h:274
int AddToken(Token *newToken, int forceidx=-1)
Definition: tokentree.cpp:364
TokenKind
Definition: token.h:29
bool HasItem(const wxString &s)
Tells if there is an item for string s.
Definition: searchtree.cpp:734