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: 11509 $
6 * $Id: nativeparser_base.cpp 11509 2018-11-04 02:49:39Z ollydbg $
7 * $HeadURL: svn://svn.code.sf.net/p/codeblocks/code/branches/release-20.xx/src/plugins/codecompletion/nativeparser_base.cpp $
8 */
9
10 #include <sdk.h>
11
12 #ifndef CB_PRECOMP
13 #endif
14
15 #include "nativeparser_base.h"
16 #include "parser/tokenizer.h"
17
18 #include "parser/cclogger.h"
19
20 #define CC_NATIVEPARSERBASE_DEBUG_OUTPUT 0
21
22 #if defined(CC_GLOBAL_DEBUG_OUTPUT)
23 #if CC_GLOBAL_DEBUG_OUTPUT == 1
24 #undef CC_NATIVEPARSERBASE_DEBUG_OUTPUT
25 #define CC_NATIVEPARSERBASE_DEBUG_OUTPUT 1
26 #elif CC_GLOBAL_DEBUG_OUTPUT == 2
27 #undef CC_NATIVEPARSERBASE_DEBUG_OUTPUT
28 #define CC_NATIVEPARSERBASE_DEBUG_OUTPUT 2
29 #endif
30 #endif
31
32 #ifdef CC_PARSER_TEST
33 #define ADDTOKEN(format, args...) \
34 CCLogger::Get()->AddToken(F(format, ##args))
35 #define TRACE(format, args...) \
36 CCLogger::Get()->DebugLog(F(format, ##args))
37 #define TRACE2(format, args...) \
38 CCLogger::Get()->DebugLog(F(format, ##args))
39 #else
40 #if CC_NATIVEPARSERBASE_DEBUG_OUTPUT == 1
41 #define ADDTOKEN(format, args...) \
42 CCLogger::Get()->AddToken(F(format, ##args))
43 #define TRACE(format, args...) \
44 CCLogger::Get()->DebugLog(F(format, ##args))
45 #define TRACE2(format, args...)
46 #elif CC_NATIVEPARSERBASE_DEBUG_OUTPUT == 2
47 #define ADDTOKEN(format, args...) \
48 CCLogger::Get()->AddToken(F(format, ##args))
49 #define TRACE(format, args...) \
50 do \
51 { \
52 if (g_EnableDebugTrace) \
53 CCLogger::Get()->DebugLog(F(format, ##args)); \
54 } \
55 while (false)
56 #define TRACE2(format, args...) \
57 CCLogger::Get()->DebugLog(F(format, ##args))
58 #else
59 #define ADDTOKEN(format, args...)
60 #define TRACE(format, args...)
61 #define TRACE2(format, args...)
62 #endif
63 #endif
64
NativeParserBase()65 NativeParserBase::NativeParserBase()
66 {
67 }
68
~NativeParserBase()69 NativeParserBase::~NativeParserBase()
70 {
71 }
72
Reset()73 void NativeParserBase::Reset()
74 {
75 m_LastComponent.Clear();
76 }
77
78 // Here's the meat of code-completion :)
79 // This function decides most of what gets included in the auto-completion
80 // list presented to the user.
81 // It's called recursively for each component of the std::queue argument.
82 // for example: objA.objB.function()
83 // The queue is like: 'objA' 'objB' 'function'. We deal with objA first.
84 //
85 // No critical section needed in this recursive function!
86 // All functions that call this recursive function, should already entered a critical section.
FindAIMatches(TokenTree * tree,std::queue<ParserComponent> components,TokenIdxSet & result,int parentTokenIdx,bool isPrefix,bool caseSensitive,bool use_inheritance,short int kindMask,TokenIdxSet * search_scope)87 size_t NativeParserBase::FindAIMatches(TokenTree* tree,
88 std::queue<ParserComponent> components,
89 TokenIdxSet& result,
90 int parentTokenIdx,
91 bool isPrefix,
92 bool caseSensitive,
93 bool use_inheritance,
94 short int kindMask,
95 TokenIdxSet* search_scope)
96 {
97 if (components.empty())
98 return 0;
99
100 if (s_DebugSmartSense)
101 CCLogger::Get()->DebugLog(_T("FindAIMatches() ----- FindAIMatches - enter -----"));
102
103 TRACE(_T("NativeParser::FindAIMatches()"));
104
105 // pop top component
106 ParserComponent parser_component = components.front();
107 components.pop();
108
109 // handle the special keyword "this".
110 if ((parentTokenIdx != -1) && (parser_component.component == _T("this")))
111 {
112 // this will make the AI behave like it's the previous scope (or the current if no previous scope)
113
114 // move on please, nothing to see here...
115 // All functions that call the recursive FindAIMatches should already entered a critical section.
116 return FindAIMatches(tree, components, result, parentTokenIdx,
117 isPrefix, caseSensitive, use_inheritance,
118 kindMask, search_scope);
119 }
120
121 // we 'll only add tokens in the result set if we get matches for the last token
122 bool isLastComponent = components.empty();
123 wxString searchtext = parser_component.component;
124
125 if (s_DebugSmartSense)
126 CCLogger::Get()->DebugLog(F(_T("FindAIMatches() Search for %s, isLast = %d"),
127 searchtext.wx_str(), isLastComponent?1:0));
128
129 // get a set of matches for the current token
130 TokenIdxSet local_result;
131 // All functions that call the recursive GenerateResultSet should already entered a critical section.
132 GenerateResultSet(tree, searchtext, parentTokenIdx, local_result,
133 (caseSensitive || !isLastComponent),
134 (isLastComponent && !isPrefix), kindMask);
135
136 if (s_DebugSmartSense)
137 CCLogger::Get()->DebugLog(F(_T("FindAIMatches() Looping %lu results"),
138 static_cast<unsigned long>(local_result.size())));
139
140 // loop all matches, and recurse
141 for (TokenIdxSet::const_iterator it = local_result.begin(); it != local_result.end(); it++)
142 {
143 int id = *it;
144 const Token* token = tree->at(id);
145
146 // sanity check
147 if (!token)
148 {
149 if (s_DebugSmartSense)
150 CCLogger::Get()->DebugLog(_T("FindAIMatches() Token is NULL?!"));
151 continue;
152 }
153
154 // ignore operators
155 if (token->m_IsOperator)
156 continue;
157
158 // enums children (enumerators), are added by default
159 if (token->m_TokenKind == tkEnum)
160 {
161 // insert enum type
162 result.insert(id);
163
164 // insert enumerators
165 for (TokenIdxSet::const_iterator tis_it = token->m_Children.begin();
166 tis_it != token->m_Children.end();
167 tis_it++)
168 result.insert(*tis_it);
169
170 continue; // done with this token
171 }
172
173 if (s_DebugSmartSense)
174 CCLogger::Get()->DebugLog(F(_T("FindAIMatches() Match: '%s' (ID='%d') : type='%s'"),
175 token->m_Name.wx_str(), id, token->m_BaseType.wx_str()));
176
177
178 // is the token a function or variable (i.e. is not a type)
179 if ( !searchtext.IsEmpty()
180 && (parser_component.tokenType != pttSearchText)
181 && !token->m_BaseType.IsEmpty() )
182 {
183 // the token is not a type
184 // find its type's ID and use this as parent instead of (*it)
185 TokenIdxSet type_result;
186 std::queue<ParserComponent> type_components;
187 wxString actual = token->m_BaseType;
188
189 // TODO: ignore builtin types (void, int, etc)
190 BreakUpComponents(actual, type_components);
191 // the parent to search under is a bit troubling, because of namespaces
192 // what we 'll do is search under current parent and traverse up the parentship
193 // until we find a result, or reach -1...
194
195 if (s_DebugSmartSense)
196 CCLogger::Get()->DebugLog(F(_T("FindAIMatches() Looking for type: '%s' (%lu components)"),
197 actual.wx_str(),
198 static_cast<unsigned long>(type_components.size())));
199
200 // search under all search-scope namespaces too
201 TokenIdxSet temp_search_scope;
202 if (search_scope)
203 temp_search_scope = *search_scope;
204
205 // add grand-parent as search scope (if none defined)
206 // this helps with namespaces when the token's type doesn't contain
207 // namespace info. In that case (with the code here) we 're searching in
208 // the parent's namespace too
209 if (parentTokenIdx != -1)
210 {
211 const Token* parentToken = tree->at(parentTokenIdx);
212 if (parentToken)
213 {
214 const Token* parent = tree->at(parentToken->m_ParentIndex);
215 if (parent)
216 {
217 temp_search_scope.insert(parent->m_Index);
218 if (s_DebugSmartSense)
219 CCLogger::Get()->DebugLog(_T("FindAIMatches() Implicit search scope added:") + parent->m_Name);
220 }
221 }
222 }
223
224 TokenIdxSet::const_iterator itsearch;
225 itsearch = temp_search_scope.begin();
226 while (!search_scope || itsearch != temp_search_scope.end())
227 {
228 const Token* parent = tree->at(*itsearch);
229
230 if (s_DebugSmartSense)
231 CCLogger::Get()->DebugLog(F(_T("FindAIMatches() Now looking under '%s'"),
232 parent ? parent->m_Name.wx_str() : wxString(_("Global namespace")).wx_str()));
233
234 do
235 {
236 // types are searched as whole words, case sensitive and only classes/namespaces
237 // All functions that call the recursive FindAIMatches should already entered a critical section.
238 if (FindAIMatches(tree,
239 type_components,
240 type_result,
241 parent ? parent->m_Index : -1,
242 true,
243 false,
244 false,
245 tkClass | tkNamespace | tkTypedef | tkEnum,
246 &temp_search_scope) != 0)
247 break;
248 if (!parent)
249 break;
250 parent = tree->at(parent->m_ParentIndex);
251 } while (true);
252 ++itsearch;
253 }
254
255 // we got all possible types (hopefully should be just one)
256 if (!type_result.empty())
257 {
258 // this is the first result
259 id = *(type_result.begin());
260 if (type_result.size() > 1)
261 {
262 // if we have more than one result, recurse for all of them
263 TokenIdxSet::const_iterator tis_it = type_result.begin();
264 ++tis_it;
265 while (tis_it != type_result.end())
266 {
267 std::queue<ParserComponent> lcomp = components;
268 // All functions that call the recursive FindAIMatches should already entered a critical section.
269 FindAIMatches(tree, lcomp, result, *tis_it, isPrefix,
270 caseSensitive, use_inheritance,
271 kindMask, search_scope);
272 ++tis_it;
273 }
274 }
275
276 if (s_DebugSmartSense)
277 {
278 CCLogger::Get()->DebugLog(F(_T("FindAIMatches() Type: '%s' (%d)"), tree->at(id)->m_Name.wx_str(), id));
279 if (type_result.size() > 1)
280 CCLogger::Get()->DebugLog(F(_T("FindAIMatches() Multiple types matched for '%s': %lu results"),
281 token->m_BaseType.wx_str(),
282 static_cast<unsigned long>(type_result.size())));
283 }
284 }
285 else if (s_DebugSmartSense)
286 CCLogger::Get()->DebugLog(F(_T("FindAIMatches() No types matched '%s'."), token->m_BaseType.wx_str()));
287 }
288
289 // if no more components, add to result set
290 if (isLastComponent)
291 result.insert(id);
292 // else recurse this function using id as a parent
293 else
294 // All functions that call the recursive FindAIMatches should already entered a critical section.
295 FindAIMatches(tree, components, result, id, isPrefix,
296 caseSensitive, use_inheritance, kindMask,
297 search_scope);
298 }
299
300 if (s_DebugSmartSense)
301 CCLogger::Get()->DebugLog(_T("FindAIMatches() ----- FindAIMatches - leave -----"));
302
303 return result.size();
304 }
305
FindCurrentFunctionScope(TokenTree * tree,const TokenIdxSet & procResult,TokenIdxSet & scopeResult)306 void NativeParserBase::FindCurrentFunctionScope(TokenTree* tree,
307 const TokenIdxSet& procResult,
308 TokenIdxSet& scopeResult)
309 {
310 CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
311 // loop on the input parameter procResult, and only record some container tokens, such as
312 // class token, function token.
313 for (TokenIdxSet::const_iterator it = procResult.begin(); it != procResult.end(); ++it)
314 {
315 const Token* token = tree->at(*it);
316 if (!token)
317 continue;
318
319 if (token->m_TokenKind == tkClass)
320 scopeResult.insert(*it);
321 else
322 {
323 if (token->m_TokenKind & tkAnyFunction && token->HasChildren()) // for local variable
324 scopeResult.insert(*it);
325 scopeResult.insert(token->m_ParentIndex);
326 }
327
328 if (s_DebugSmartSense)
329 {
330 const Token* parent = tree->at(token->m_ParentIndex);
331 CCLogger::Get()->DebugLog(_T("AI() Adding search namespace: ") +
332 (parent ? parent->m_Name : _T("Global namespace")));
333 }
334 }
335
336 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
337 }
338
CleanupSearchScope(TokenTree * tree,TokenIdxSet * searchScope)339 void NativeParserBase::CleanupSearchScope(TokenTree* tree,
340 TokenIdxSet* searchScope)
341 {
342 CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
343 // remove all the container tokens in the token index set
344 for (TokenIdxSet::const_iterator it = searchScope->begin(); it != searchScope->end();)
345 {
346 const Token* token = tree->at(*it);
347 if (!token || !(token->m_TokenKind & (tkNamespace | tkClass | tkTypedef | tkAnyFunction)))
348 searchScope->erase(it++);
349 else
350 ++it;
351 }
352
353 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
354
355 // ...but always search the global scope.
356 searchScope->insert(-1);
357 }
358
359 // Set start and end for the calltip highlight region.
GetCallTipHighlight(const wxString & calltip,int * start,int * end,int typedCommas)360 void NativeParserBase::GetCallTipHighlight(const wxString& calltip,
361 int* start,
362 int* end,
363 int typedCommas)
364 {
365 TRACE(_T("NativeParserBase::GetCallTipHighlight()"));
366
367 int pos = 0;
368 int paramsCloseBracket = calltip.length() - 1;
369 int nest = 0;
370 int commas = 0;
371 *start = FindFunctionOpenParenthesis(calltip) + 1;
372 *end = 0;
373
374 // for a function call tip string like below
375 // void f(int a, map<int, float>b)
376 // we have to take care the <> pair
377 while (true)
378 {
379 wxChar c = calltip.GetChar(pos++);
380 if (c == '\0')
381 break;
382 else if (c == '(')
383 ++nest;
384 else if (c == ')')
385 {
386 --nest;
387 if (nest == 0)
388 paramsCloseBracket = pos - 1;
389 }
390 else if (c == ',' && nest == 1)
391 {
392 ++commas;
393 if (commas == typedCommas + 1)
394 {
395 *end = pos - 1;
396 return;
397 }
398 *start = pos;
399 }
400 else if (c =='<')
401 ++nest;
402 else if (c == '>')
403 --nest;
404 }
405 if (*end == 0)
406 *end = paramsCloseBracket;
407 }
408
FindFunctionOpenParenthesis(const wxString & calltip)409 int NativeParserBase::FindFunctionOpenParenthesis(const wxString& calltip)
410 {
411 int nest = 0;
412 for (size_t i = calltip.length(); i > 0; --i)
413 {
414 wxChar c = calltip[i - 1];
415 if (c == wxT('('))
416 {
417 --nest;
418 if (nest == 0)
419 return i - 1;
420 }
421 else if (c == wxT(')'))
422 ++nest;
423 }
424 return -1;
425 }
426
GetCCToken(wxString & line,ParserTokenType & tokenType,OperatorType & tokenOperatorType)427 wxString NativeParserBase::GetCCToken(wxString& line,
428 ParserTokenType& tokenType,
429 OperatorType& tokenOperatorType)
430 {
431 tokenType = pttSearchText;
432 tokenOperatorType = otOperatorUndefined;
433 if (line.IsEmpty())
434 return wxEmptyString;
435
436 tokenOperatorType = otOperatorUndefined;
437 unsigned int startAt = FindCCTokenStart(line);
438 wxString res = GetNextCCToken(line, startAt, tokenOperatorType);
439
440 TRACE(_T("GetCCToken() : FindCCTokenStart returned %u \"%s\""), startAt, line.wx_str());
441 TRACE(_T("GetCCToken() : GetNextCCToken returned %u \"%s\""), startAt, res.wx_str());
442
443
444 if (startAt == line.Len())
445 line.Clear();
446 else
447 {
448 // skip whitespace
449 startAt = AfterWhitespace(startAt, line);
450
451 // Check for [Class]. ('.' pressed)
452 if (IsOperatorDot(startAt, line))
453 {
454 tokenType = pttClass;
455 line.Remove(0, startAt + 1);
456 }
457 // Check for
458 // (1) "AAA->" ('>' pressed)
459 // (2) "AAA::" (':' pressed)
460 // If (1) and tokenOperatorType == otOperatorSquare, then we have
461 // special case "AAA[]->" and should not change tokenOperatorType.
462 else if (IsOperatorEnd(startAt, line))
463 {
464 if ( IsOperatorPointer(startAt, line)
465 && !res.IsEmpty()
466 && tokenOperatorType != otOperatorSquare)
467 tokenOperatorType = otOperatorPointer;
468 if (line.GetChar(startAt) == ':')
469 tokenType = pttNamespace;
470 else
471 tokenType = pttClass;
472 line.Remove(0, startAt + 1);
473 }
474 else
475 line.Clear();
476 }
477
478 TRACE(_T("GetCCToken() : Left \"%s\""), line.wx_str());
479
480 if (tokenOperatorType == otOperatorParentheses)
481 tokenType = pttFunction;
482
483 return res;
484 }
485
486 // skip nest braces in the expression, e.g.
487 // SomeObject->SomeMethod(arg1, arg2)->Method2()
488 // ^end ^begin
489 // note we skip the nest brace (arg1, arg2).
FindCCTokenStart(const wxString & line)490 unsigned int NativeParserBase::FindCCTokenStart(const wxString& line)
491 {
492 // Careful: startAt can become negative, so it's defined as integer here!
493 int startAt = line.Len() - 1;
494 int nest = 0;
495
496 bool repeat = true;
497 while (repeat)
498 {
499 repeat = false;
500 // Go back to the beginning of the function/variable (token)
501 startAt = BeginOfToken(startAt, line);
502
503 // Check for [Class]. ('.' pressed)
504 if (IsOperatorDot(startAt, line))
505 {
506 --startAt;
507 repeat = true; // yes -> repeat.
508 }
509 // Check for [Class]-> ('>' pressed)
510 // Check for [Class]:: (':' pressed)
511 else if (IsOperatorEnd(startAt, line))
512 {
513 startAt -= 2;
514 repeat = true; // yes -> repeat.
515 }
516
517 if (repeat)
518 {
519 // now we're just before the "." or "->" or "::"
520 // skip any whitespace
521 startAt = BeforeWhitespace(startAt, line);
522
523 // check for function/array/cast ()
524 if (IsClosingBracket(startAt, line))
525 {
526 ++nest;
527 while ( (--startAt >= 0)
528 && (nest != 0) )
529 {
530 #if wxCHECK_VERSION(3, 0, 0)
531 switch (line.GetChar(startAt).GetValue())
532 #else
533 switch (line.GetChar(startAt))
534 #endif
535 {
536 case ']':
537 case ')': ++nest; --startAt; break;
538
539 case '[':
540 case '(': --nest; --startAt; break;
541 default:
542 break;
543 }
544
545 startAt = BeforeWhitespace(startAt, line);
546
547 if (IsClosingBracket(startAt, line))
548 ++nest;
549 if (IsOpeningBracket(startAt, line))
550 --nest;
551 }
552
553 startAt = BeforeToken(startAt, line);
554 }
555 }
556 }
557 ++startAt;
558
559 startAt = AfterWhitespace(startAt, line);
560
561 TRACE(_T("FindCCTokenStart() : Starting at %u \"%s\""), startAt, line.Mid(startAt).wx_str());
562
563 return startAt;
564 }
565
GetNextCCToken(const wxString & line,unsigned int & startAt,OperatorType & tokenOperatorType)566 wxString NativeParserBase::GetNextCCToken(const wxString& line,
567 unsigned int& startAt,
568 OperatorType& tokenOperatorType)
569 {
570 wxString res;
571 int nest = 0;
572
573 if ( (startAt < line.Len())
574 && (line.GetChar(startAt) == '(') )
575 {
576 while ( (startAt < line.Len())
577 && ( (line.GetChar(startAt) == '*')
578 || (line.GetChar(startAt) == '&')
579 || (line.GetChar(startAt) == '(') ) )
580 {
581 if (line.GetChar(startAt) == '(')
582 ++nest;
583 if (line.GetChar(startAt) == _T('*'))
584 tokenOperatorType = otOperatorStar;
585 ++startAt;
586 }
587 }
588
589 TRACE(_T("GetNextCCToken() : at %u (%c): res=%s"), startAt, line.GetChar(startAt), res.wx_str());
590
591 while (InsideToken(startAt, line))
592 {
593 res << line.GetChar(startAt);
594 ++startAt;
595 }
596 while ( (nest > 0)
597 && (startAt < line.Len()) )
598 {
599 // TODO: handle nested scope resolution (A::getC()).|
600 if (line.GetChar(startAt) == '(')
601 ++nest;
602 else if (line.GetChar(startAt) == ')')
603 --nest;
604 ++startAt;
605 }
606
607 TRACE(_T("GetNextCCToken() : Done nest: at %u (%c): res=%s"), startAt, line.GetChar(startAt), res.wx_str());
608
609 startAt = AfterWhitespace(startAt, line);
610 if (IsOpeningBracket(startAt, line))
611 {
612 if (line.GetChar(startAt) == _T('('))
613 tokenOperatorType = otOperatorParentheses;
614 else if (line.GetChar(startAt) == _T('['))
615 tokenOperatorType = otOperatorSquare;
616 ++nest;
617 while ( (startAt < line.Len()-1)
618 && (nest != 0) )
619 {
620 ++startAt;
621 #if wxCHECK_VERSION(3, 0, 0)
622 switch (line.GetChar(startAt).GetValue())
623 #else
624 switch (line.GetChar(startAt))
625 #endif
626 {
627 case ']':
628 case ')': --nest; ++startAt; break;
629
630 case '[':tokenOperatorType = otOperatorSquare;
631 case '(': ++nest; ++startAt; break;
632 default:
633 break;
634 }
635
636 startAt = AfterWhitespace(startAt, line);
637
638 if (IsOpeningBracket(startAt, line))
639 ++nest;
640 //NOTE: do not skip successive closing brackets. Eg,
641 // "GetConfigManager(_T("code_completion"))->ReadBool"
642 // ^
643 if (IsClosingBracket(startAt, line))
644 {
645 --nest;
646 if (nest == 0)
647 ++startAt;
648 }
649 }
650 }
651 if (IsOperatorBegin(startAt, line))
652 ++startAt;
653
654 TRACE(_T("GetNextCCToken() : Return at %u (%c): res=%s"), startAt, line.GetChar(startAt), res.wx_str());
655
656 return res;
657 }
658
RemoveLastFunctionChildren(TokenTree * tree,int & lastFuncTokenIdx)659 void NativeParserBase::RemoveLastFunctionChildren(TokenTree* tree,
660 int& lastFuncTokenIdx)
661 {
662 CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
663
664 Token* token = tree->at(lastFuncTokenIdx);
665 if (token)
666 {
667 lastFuncTokenIdx = -1;
668 if (token->m_TokenKind & tkAnyFunction)
669 token->DeleteAllChildren();
670 }
671
672 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
673 }
674
675 // Breaks up the phrase for code-completion.
676 // Suppose the user has invoked code-completion in this piece of code:
677 //
678 // Ogre::Root::getSingleton().|
679 //
680 // This function will break this up into an std::queue (FIFO) containing
681 // the following items (top is first-out):
682 //
683 // Ogre [pttNamespace]
684 // Root [pttClass]
685 // getSingleton [pttFunction]
686 // (empty space) [pttSearchText]
687 //
688 // It also classifies each component as a pttClass, pttNamespace, pttFunction, pttSearchText
BreakUpComponents(const wxString & actual,std::queue<ParserComponent> & components)689 size_t NativeParserBase::BreakUpComponents(const wxString& actual,
690 std::queue<ParserComponent>& components)
691 {
692 ParserTokenType tokenType;
693 wxString statement = actual;
694 OperatorType tokenOperatorType;
695 // break up components of phrase
696 if (s_DebugSmartSense)
697 CCLogger::Get()->DebugLog(F(_T("BreakUpComponents() Breaking up '%s'"), statement.wx_str()));
698 TRACE(_T("NativeParserBase::BreakUpComponents()"));
699
700 while (true)
701 {
702 wxString tok = GetCCToken(statement, tokenType, tokenOperatorType);
703
704 ParserComponent pc;
705 pc.component = tok;
706 pc.tokenType = tokenType;
707 pc.tokenOperatorType = tokenOperatorType;
708 // Debug smart sense: output the component's name and type.
709 if (s_DebugSmartSense)
710 {
711 wxString tokenTypeString;
712 switch (tokenType)
713 {
714 case (pttFunction):
715 { tokenTypeString = _T("Function"); break; }
716 case (pttClass):
717 { tokenTypeString = _T("Class"); break; }
718 case (pttNamespace):
719 { tokenTypeString = _T("Namespace"); break; }
720 case (pttSearchText):
721 { tokenTypeString = _T("SearchText"); break; }
722 case (pttUndefined):
723 default:
724 { tokenTypeString = _T("Undefined"); }
725 }
726 CCLogger::Get()->DebugLog(F(_T("BreakUpComponents() Found component: '%s' (%s)"),
727 tok.wx_str(), tokenTypeString.wx_str()));
728 }
729
730 // Support global namespace like ::MessageBoxA
731 // Break up into "", type is pttNameSpace and "MessageBoxA", type is pttSearchText.
732 // for pttNameSpace type, if its text (tok) is empty -> ignore this component.
733 // for pttSearchText type, don't do this because for ss:: we need this, too.
734 if (!tok.IsEmpty() || (tokenType == pttSearchText && !components.empty()))
735 {
736 if (s_DebugSmartSense)
737 CCLogger::Get()->DebugLog(F(_T("BreakUpComponents() Adding component: '%s'."), tok.wx_str()));
738 components.push(pc);
739 }
740
741 if (tokenType == pttSearchText)
742 break;
743 }
744
745 return 0;
746 }
747
ResolveExpression(TokenTree * tree,std::queue<ParserComponent> components,const TokenIdxSet & searchScope,TokenIdxSet & result,bool caseSense,bool isPrefix)748 size_t NativeParserBase::ResolveExpression(TokenTree* tree,
749 std::queue<ParserComponent> components,
750 const TokenIdxSet& searchScope,
751 TokenIdxSet& result,
752 bool caseSense,
753 bool isPrefix)
754 {
755 m_TemplateMap.clear();
756 if (components.empty())
757 return 0;
758
759 TokenIdxSet initialScope;
760 if (!searchScope.empty())
761 initialScope = searchScope;
762 else
763 initialScope.insert(-1);
764
765 while (!components.empty())
766 {
767 TokenIdxSet initialResult;
768 ParserComponent subComponent = components.front();
769 components.pop();
770 wxString searchText = subComponent.component;
771 if (searchText == _T("this"))
772 {
773 initialScope.erase(-1);
774 TokenIdxSet tempInitialScope = initialScope;
775
776 CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
777
778 for (TokenIdxSet::const_iterator it = tempInitialScope.begin();
779 it != tempInitialScope.end(); ++it)
780 {
781 const Token* token = tree->at(*it);
782 if (token && (token->m_TokenKind != tkClass))
783 initialScope.erase(*it);
784 }
785
786 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
787
788 if (!initialScope.empty())
789 continue;
790 else
791 {
792 CCLogger::Get()->DebugLog(F(_T("ResolveExpression() Error to find initial search scope.")));
793 break; // error happened.
794 }
795 }
796
797 if (s_DebugSmartSense)
798 {
799 CCLogger::Get()->DebugLog(F(_T("ResolveExpression() Search scope with %lu result:"),
800 static_cast<unsigned long>(initialScope.size())));
801 for (TokenIdxSet::const_iterator tt = initialScope.begin(); tt != initialScope.end(); ++tt)
802 CCLogger::Get()->DebugLog(F(_T("- Search scope: %d"), (*tt)));
803 }
804
805 CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
806
807 // All functions that call the recursive GenerateResultSet should already entered a critical section.
808
809 // e.g. A.BB.CCC.DDDD|
810 if (components.empty()) // is the last component (DDDD)
811 GenerateResultSet(tree, searchText, initialScope, initialResult, caseSense, isPrefix);
812 else // case sensitive and full-match always (A / BB / CCC)
813 GenerateResultSet(tree, searchText, initialScope, initialResult, true, false);
814
815 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
816
817 // now we should clear the initialScope.
818 initialScope.clear();
819
820 //-------------------------------------
821
822 if (s_DebugSmartSense)
823 CCLogger::Get()->DebugLog(F(_T("ResolveExpression() Looping %lu result."),
824 static_cast<unsigned long>(initialResult.size())));
825
826 //------------------------------------
827 if (!initialResult.empty())
828 {
829 bool locked = false;
830
831 // loop all matches.
832 for (TokenIdxSet::const_iterator it = initialResult.begin(); it != initialResult.end(); ++it)
833 {
834 const size_t id = (*it);
835 wxString actualTypeStr;
836 int parentIndex = -1;
837 bool isFuncOrVar = false;
838
839 if (locked)
840 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
841 CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
842 locked = true;
843
844 const Token* token = tree->at(id);
845 if (!token)
846 {
847 if (s_DebugSmartSense)
848 CCLogger::Get()->DebugLog(F(_T("ResolveExpression() token is NULL?!")));
849 continue;
850 }
851
852 // TODO: we should deal with operators carefully.
853 // it should work for class::/namespace::
854 if (token->m_IsOperator && (m_LastComponent.tokenType != pttNamespace))
855 continue;
856
857 if (s_DebugSmartSense)
858 CCLogger::Get()->DebugLog(F(_T("ResolvExpression() Match:'%s(ID=%lu) : type='%s'"),
859 token->m_Name.wx_str(),
860 static_cast<unsigned long>(id),
861 token->m_BaseType.wx_str()));
862
863 // recond the template map message here. hope it will work.
864 // wxString tkname = token->m_Name;
865 // wxArrayString tks = token->m_TemplateType;
866 if (!token->m_TemplateMap.empty())
867 m_TemplateMap = token->m_TemplateMap;
868
869 // if the token is a function/variable(i.e. is not a type)
870 isFuncOrVar = !searchText.IsEmpty()
871 && (subComponent.tokenType != pttSearchText)
872 && !token->m_BaseType.IsEmpty();
873 if (isFuncOrVar)
874 {
875 actualTypeStr = token->m_BaseType;
876 parentIndex = token->m_Index;
877 }
878
879 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
880 locked = false;
881
882 // handle it if the token is a function/variable(i.e. is not a type)
883 if (isFuncOrVar)
884 {
885 TokenIdxSet actualTypeScope;
886 if (searchScope.empty())
887 actualTypeScope.insert(-1);
888 else
889 {
890 // now collect the search scope for actual type of function/variable.
891 CollectSearchScopes(searchScope, actualTypeScope, tree);
892
893 CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
894
895 // now add the current token's parent scope;
896 const Token* currentTokenParent = tree->at(parentIndex);
897 while (true)
898 {
899 if (!currentTokenParent)
900 break;
901 actualTypeScope.insert(currentTokenParent->m_Index);
902 currentTokenParent = tree->at(currentTokenParent->m_ParentIndex);
903 }
904
905 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
906 }
907
908 // now get the tokens of variable/function.
909 TokenIdxSet actualTypeResult;
910 ResolveActualType(tree, actualTypeStr, actualTypeScope, actualTypeResult);
911 if (!actualTypeResult.empty())
912 {
913 for (TokenIdxSet::const_iterator it2 = actualTypeResult.begin();
914 it2 != actualTypeResult.end();
915 ++it2)
916 {
917 initialScope.insert(*it2);
918
919 CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
920
921 const Token* typeToken = tree->at(*it2);
922 if (typeToken && !typeToken->m_TemplateMap.empty())
923 m_TemplateMap = typeToken->m_TemplateMap;
924
925 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
926
927 // and we need to add the template argument alias too.
928 AddTemplateAlias(tree, *it2, actualTypeScope, initialScope);
929 }
930 }
931 else // ok ,we search template container to check if type is template formal.
932 ResolveTemplateMap(tree, actualTypeStr, actualTypeScope, initialScope);
933
934 continue;
935 }
936
937 initialScope.insert(id);
938 }// for
939
940 if (locked)
941 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
942 }
943 else
944 {
945 initialScope.clear();
946 break;
947 }
948
949 if (subComponent.tokenOperatorType != otOperatorUndefined)
950 {
951 TokenIdxSet operatorResult;
952 ResolveOperator(tree, subComponent.tokenOperatorType, initialScope, searchScope, operatorResult);
953 if (!operatorResult.empty())
954 initialScope = operatorResult;
955 }
956 if (subComponent.tokenType != pttSearchText)
957 m_LastComponent = subComponent;
958 }// while
959
960 // initialScope contains all the matching tokens after the cascade matching algorithm
961 if (!initialScope.empty())
962 {
963 // normally, tokens have hierarchies. E.g. a constructor token is a child of a class token.
964 // but here we promote (expose) the constructor tokens to the user. if a Token in initialScope
965 // is a class, we add all its public constructors to the results, this give us a chance to let
966 // CC jump to the declaration of a constructor, see
967 // http://forums.codeblocks.org/index.php/topic,13753.msg92654.html#msg92654
968 AddConstructors(tree, initialScope, result);
969 }
970
971 return result.size();
972 }
973
AddConstructors(TokenTree * tree,const TokenIdxSet & source,TokenIdxSet & dest)974 void NativeParserBase::AddConstructors(TokenTree *tree, const TokenIdxSet& source, TokenIdxSet& dest)
975 {
976 for (TokenIdxSet::iterator It = source.begin(); It != source.end(); ++It)
977 {
978 const Token* token = tree->at(*It);
979 if (!token)
980 continue;
981 dest.insert(*It);
982
983 // add constructors of the class type token
984 if (token->m_TokenKind == tkClass)
985 {
986 // loop on its children, add its public constructors
987 for (TokenIdxSet::iterator chIt = token->m_Children.begin();
988 chIt != token->m_Children.end();
989 ++chIt)
990 {
991 const Token* tk = tree->at(*chIt);
992 if ( tk && ( tk->m_TokenKind == tkConstructor
993 || (tk->m_IsOperator && tk->m_Name.EndsWith(wxT("()"))) )
994 && (tk->m_Scope == tsPublic || tk->m_Scope == tsUndefined) )
995 {
996 dest.insert(*chIt);
997 }
998 }
999 }
1000 }
1001 }
1002
ResolveOperator(TokenTree * tree,const OperatorType & tokenOperatorType,const TokenIdxSet & tokens,const TokenIdxSet & searchScope,TokenIdxSet & result)1003 void NativeParserBase::ResolveOperator(TokenTree* tree,
1004 const OperatorType& tokenOperatorType,
1005 const TokenIdxSet& tokens,
1006 const TokenIdxSet& searchScope,
1007 TokenIdxSet& result)
1008 {
1009 if (!tree || searchScope.empty())
1010 return;
1011
1012 CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
1013
1014 // first,we need to eliminate the tokens which are not tokens.
1015 TokenIdxSet opInitialScope;
1016 for (TokenIdxSet::const_iterator it=tokens.begin(); it!=tokens.end(); ++it)
1017 {
1018 int id = (*it);
1019 const Token* token = tree->at(id);
1020 if (token && (token->m_TokenKind == tkClass || token->m_TokenKind == tkTypedef))
1021 opInitialScope.insert(id);
1022 }
1023
1024 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
1025
1026 // if we get nothing, just return.
1027 if (opInitialScope.empty())
1028 return;
1029
1030 wxString operatorStr;
1031 switch(tokenOperatorType)
1032 {
1033 case otOperatorParentheses:
1034 operatorStr = _T("operator()"); break;
1035 case otOperatorSquare:
1036 operatorStr = _T("operator[]"); break;
1037 case otOperatorPointer:
1038 operatorStr = _T("operator->"); break;
1039 case otOperatorStar:
1040 operatorStr = _T("operator*"); break;
1041 case otOperatorUndefined:
1042 default:
1043 break;
1044 }
1045 if (operatorStr.IsEmpty())
1046 return;
1047
1048 //s tart to parse the operator overload actual type.
1049 TokenIdxSet opInitialResult;
1050
1051 CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
1052
1053 // All functions that call the recursive GenerateResultSet should already entered a critical section.
1054 GenerateResultSet(tree, operatorStr, opInitialScope, opInitialResult);
1055
1056 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
1057
1058 CollectSearchScopes(searchScope, opInitialScope, tree);
1059
1060 if (opInitialResult.empty())
1061 return;
1062
1063 for (TokenIdxSet::const_iterator it=opInitialResult.begin(); it!=opInitialResult.end(); ++it)
1064 {
1065 CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
1066
1067 wxString type;
1068 const Token* token = tree->at((*it));
1069 if (token)
1070 type = token->m_BaseType;
1071
1072 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
1073
1074 if (type.IsEmpty())
1075 continue;
1076
1077 TokenIdxSet typeResult;
1078 ResolveActualType(tree, type, opInitialScope, typeResult);
1079 if (!typeResult.empty())
1080 {
1081 for (TokenIdxSet::const_iterator pTypeResult = typeResult.begin();
1082 pTypeResult!=typeResult.end();
1083 ++pTypeResult)
1084 {
1085 result.insert(*pTypeResult);
1086 AddTemplateAlias(tree, *pTypeResult, opInitialScope, result);
1087 }
1088 }
1089 else
1090 ResolveTemplateMap(tree, type, opInitialScope, result);
1091 }
1092 }
1093
ResolveActualType(TokenTree * tree,wxString searchText,const TokenIdxSet & searchScope,TokenIdxSet & result)1094 size_t NativeParserBase::ResolveActualType(TokenTree* tree,
1095 wxString searchText,
1096 const TokenIdxSet& searchScope,
1097 TokenIdxSet& result)
1098 {
1099 // break up the search text for next analysis.
1100 std::queue<ParserComponent> typeComponents;
1101 BreakUpComponents(searchText, typeComponents);
1102 if (!typeComponents.empty())
1103 {
1104 TokenIdxSet initialScope;
1105 if (!searchScope.empty())
1106 initialScope = searchScope;
1107 else
1108 initialScope.insert(-1);
1109
1110 CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
1111
1112 while (!typeComponents.empty())
1113 {
1114 TokenIdxSet initialResult;
1115 ParserComponent component = typeComponents.front();
1116 typeComponents.pop();
1117 wxString actualTypeStr = component.component;
1118
1119 // All functions that call the recursive GenerateResultSet should already entered a critical section.
1120 GenerateResultSet(tree, actualTypeStr, initialScope, initialResult, true, false, 0xFFFF);
1121
1122 if (!initialResult.empty())
1123 {
1124 initialScope.clear();
1125 for (TokenIdxSet::const_iterator it = initialResult.begin(); it != initialResult.end(); ++it)
1126 // TODO (Morten#1#): eliminate the variable/function
1127 initialScope.insert(*it);
1128 }
1129 else
1130 {
1131 initialScope.clear();
1132 break;
1133 }
1134 }
1135
1136 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
1137
1138 if (!initialScope.empty())
1139 result = initialScope;
1140 }
1141
1142 return result.size();
1143 }
1144
ResolveTemplateMap(TokenTree * tree,const wxString & searchStr,const TokenIdxSet & actualTypeScope,TokenIdxSet & initialScope)1145 void NativeParserBase::ResolveTemplateMap(TokenTree* tree,
1146 const wxString& searchStr,
1147 const TokenIdxSet& actualTypeScope,
1148 TokenIdxSet& initialScope)
1149 {
1150 if (actualTypeScope.empty())
1151 return;
1152
1153 wxString actualTypeStr = searchStr;
1154 std::map<wxString, wxString>::const_iterator it = m_TemplateMap.find(actualTypeStr);
1155 if (it != m_TemplateMap.end())
1156 {
1157 actualTypeStr = it->second;
1158 TokenIdxSet actualTypeResult;
1159 ResolveActualType(tree, actualTypeStr, actualTypeScope, actualTypeResult);
1160 if (!actualTypeResult.empty())
1161 {
1162 for (TokenIdxSet::const_iterator it2=actualTypeResult.begin(); it2!=actualTypeResult.end(); ++it2)
1163 initialScope.insert(*it2);
1164 }
1165 }
1166 }
1167
AddTemplateAlias(TokenTree * tree,const int & id,const TokenIdxSet & actualTypeScope,TokenIdxSet & initialScope)1168 void NativeParserBase::AddTemplateAlias(TokenTree* tree,
1169 const int& id,
1170 const TokenIdxSet& actualTypeScope,
1171 TokenIdxSet& initialScope)
1172 {
1173 if (!tree || actualTypeScope.empty())
1174 return;
1175
1176 // and we need to add the template argument alias too.
1177 wxString actualTypeStr;
1178
1179 CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
1180
1181 const Token* typeToken = tree->at(id);
1182 if (typeToken && typeToken->m_TokenKind == tkTypedef
1183 && !typeToken->m_TemplateAlias.IsEmpty() )
1184 actualTypeStr = typeToken->m_TemplateAlias;
1185
1186 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
1187
1188 std::map<wxString, wxString>::const_iterator it = m_TemplateMap.find(actualTypeStr);
1189 if (it != m_TemplateMap.end())
1190 {
1191 actualTypeStr = it->second;
1192
1193 if (actualTypeStr.Last() == _T('&') || actualTypeStr.Last() == _T('*'))
1194 actualTypeStr.RemoveLast();
1195
1196 TokenIdxSet actualTypeResult;
1197 ResolveActualType(tree, actualTypeStr, actualTypeScope, actualTypeResult);
1198 if (!actualTypeResult.empty())
1199 {
1200 for (TokenIdxSet::const_iterator it2 = actualTypeResult.begin(); it2 != actualTypeResult.end(); ++it2)
1201 initialScope.insert(*it2);
1202 }
1203 }
1204 }
1205
1206 // No critical section needed in this recursive function!
1207 // All functions that call this recursive function, should already entered a critical section.
1208 //
1209 // Here are sample algorithm, if we have code snippet
1210 //
1211 // class AAA { public: void f1(); int m_aaa;};
1212 // class BBB : public AAA {public: void f2(); int m_bbb;};
1213 // BBB obj;
1214 // obj.f|-------CC Here, we expect "f1" and "f2" be prompt
1215 //
1216 // Here, we do a search with the following states:
1217 // the search text target = "f", and isPrefix = true
1218 // parentIdx points to the class type Token "BBB"
1219 // caseSens could be true, kindMask could be to list any function kind tokens.
1220 //
1221 // First, we first list the children of BBB, there are two "f1", and "m_aaa", and text match should
1222 // only find one "f1".
1223 // Second, we try to calculate all the ancestors of BBB, which we see a class type Token "AAA"
1224 // list the children of AAA, and do a text match, we find "f2"
1225 // Last, we return a Token set which contains two elements ["f1", "f2"]
1226 //
1227 // Note that parentIdx could be the global namespace
1228 // Some kinds of Token types, such as Enum or Namespaces could be handled specially
GenerateResultSet(TokenTree * tree,const wxString & target,int parentIdx,TokenIdxSet & result,bool caseSens,bool isPrefix,short int kindMask)1229 size_t NativeParserBase::GenerateResultSet(TokenTree* tree,
1230 const wxString& target,
1231 int parentIdx,
1232 TokenIdxSet& result,
1233 bool caseSens,
1234 bool isPrefix,
1235 short int kindMask)
1236 {
1237 TRACE(_T("NativeParserBase::GenerateResultSet_1()"));
1238
1239 Token* parent = tree->at(parentIdx);
1240 if (s_DebugSmartSense)
1241 CCLogger::Get()->DebugLog(F(_("GenerateResultSet() search '%s', parent='%s (id:%d, type:%s), isPrefix=%d'"),
1242 target.wx_str(),
1243 parent ? parent->m_Name.wx_str() : wxString(_T("Global namespace")).wx_str(),
1244 parent ? parent->m_Index : 0,
1245 parent ? parent->GetTokenKindString().wx_str() : 0,
1246 isPrefix ? 1 : 0));
1247
1248 // parent == null means we are searching in the global scope
1249 if (parent)
1250 {
1251 // we got a parent; add its children
1252 for (TokenIdxSet::const_iterator it = parent->m_Children.begin(); it != parent->m_Children.end(); ++it)
1253 {
1254 const Token* token = tree->at(*it);
1255 if (token && MatchType(token->m_TokenKind, kindMask))
1256 {
1257 if (MatchText(token->m_Name, target, caseSens, isPrefix))
1258 result.insert(*it);
1259 else if (token && token->m_TokenKind == tkNamespace && token->m_Aliases.size()) // handle namespace aliases
1260 {
1261 for (size_t i = 0; i < token->m_Aliases.size(); ++i)
1262 {
1263 if (MatchText(token->m_Aliases[i], target, caseSens, isPrefix))
1264 {
1265 result.insert(*it);
1266 // break; ?
1267 }
1268 }
1269 }
1270 else if (token && token->m_TokenKind == tkEnum) // check enumerators for match too
1271 // All functions that call the recursive GenerateResultSet should already entered a critical section.
1272 GenerateResultSet(tree, target, *it, result, caseSens, isPrefix, kindMask);
1273 }
1274 }
1275 // now go up the inheritance chain and add all ancestors' children too
1276 tree->RecalcInheritanceChain(parent);
1277 for (TokenIdxSet::const_iterator it = parent->m_Ancestors.begin(); it != parent->m_Ancestors.end(); ++it)
1278 {
1279 const Token* ancestor = tree->at(*it);
1280 if (!ancestor)
1281 continue;
1282 for (TokenIdxSet::const_iterator it2 = ancestor->m_Children.begin(); it2 != ancestor->m_Children.end(); ++it2)
1283 {
1284 const Token* token = tree->at(*it2);
1285 if (token && MatchType(token->m_TokenKind, kindMask))
1286 {
1287 if (MatchText(token->m_Name, target, caseSens, isPrefix))
1288 result.insert(*it2);
1289 else if (token && token->m_TokenKind == tkNamespace && token->m_Aliases.size()) // handle namespace aliases
1290 {
1291 for (size_t i = 0; i < token->m_Aliases.size(); ++i)
1292 {
1293 if (MatchText(token->m_Aliases[i], target, caseSens, isPrefix))
1294 {
1295 result.insert(*it2);
1296 // break; ?
1297 }
1298 }
1299 }
1300 else if (token && token->m_TokenKind == tkEnum) // check enumerators for match too
1301 // All functions that call the recursive GenerateResultSet should already entered a critical section.
1302 GenerateResultSet(tree, target, *it2, result, caseSens, isPrefix, kindMask);
1303 }
1304 }
1305 }
1306 }
1307 else
1308 {
1309 // all global tokens
1310 const TokenList* tl = tree->GetTokens();
1311 for (TokenList::const_iterator it = tl->begin(); it != tl->end(); ++it)
1312 {
1313 const Token* token = *it;
1314 if (token && token->m_ParentIndex == -1)
1315 {
1316 if (token && MatchType(token->m_TokenKind, kindMask))
1317 {
1318 if (MatchText(token->m_Name, target, caseSens, isPrefix))
1319 result.insert(token->m_Index);
1320 else if (token && token->m_TokenKind == tkNamespace && token->m_Aliases.size()) // handle namespace aliases
1321 {
1322 for (size_t i = 0; i < token->m_Aliases.size(); ++i)
1323 {
1324 if (MatchText(token->m_Aliases[i], target, caseSens, isPrefix))
1325 {
1326 result.insert(token->m_Index);
1327 // break; ?
1328 }
1329 }
1330 }
1331 else if (token && token->m_TokenKind == tkEnum) // check enumerators for match too
1332 // All functions that call the recursive GenerateResultSet should already entered a critical section.
1333 GenerateResultSet(tree, target, token->m_Index, result, caseSens, isPrefix, kindMask);
1334 }
1335 }
1336 }
1337 }
1338
1339 // done
1340 return result.size();
1341 }
1342
1343 // No critical section needed in this recursive function!
1344 // All functions that call this recursive function, should already entered a critical section.
1345 /** detailed description
1346 * we have special handling of the c++ stl container with some template related code:
1347 * example:
1348 *
1349 * vector<string> AAA;
1350 * AAA.back(). // should display tokens of string members
1351 *
1352 * Cause of problem:
1353 *
1354 * The root of the problem is that CC can't parse some pieces of the C++ library. STL containers have
1355 * return types like "const_reference", which users of the library can treat as typedef aliases of
1356 * their template arguments.
1357 *
1358 * E.g. "back()" returns "const_reference", which we can assume to
1359 * be a typedef alias of "const string&"
1360 *
1361 * However, these return types are actually defined through a complicated chain of typedefs,
1362 * templates, and inheritance. For example, the C++ library defines "const_reference" in vector
1363 * as a typedef alias of "_Alloc_traits::const_reference", which is a typedef alias of
1364 * "__gnu_cxx::_alloc_traits<_Tp_alloc_type>::const_reference". This chain actually continues, but
1365 * it would be too much to list here. The main thing to understand is that CC will not be able to
1366 * figure out what "const_reference" is supposed to be.
1367 *
1368 * Solution:
1369 *
1370 * Trying get CC to understand this chain would have made the template code even more complicated
1371 * and error-prone, so I used a trick. STL containers are based on the allocator class. And the
1372 * allocator class contains all the simple typedefs we need. For example, in the allocator class we
1373 * find the definition of const_reference:
1374 *
1375 * typedef const _Tp& const_reference
1376 *
1377 * Where _Tp is a template parameter. Here's another trick - because most STL containers use the
1378 * name "_Tp" for their template parameter, the above definition can be directly applied to these
1379 * containers.
1380 *
1381 * E.g. vector is defined as:
1382 * template <typename _Tp>
1383 * vector { ... }
1384 * So AAA's template map will connect "_Tp" to "string".
1385 *
1386 * So we can look up "const_reference" in allocator, see that it returns "_Tp", look up "_Tp" in
1387 * the template map and add its actual value to the search scope.
1388 *
1389 * Walking through the example:
1390 *
1391 * [in NativeParserBase::GenerateResultSet()]
1392 * CC sees that back() returns const_reference. It searches the TokenTree for const_reference and
1393 * finds the typedef belonging to allocator:
1394 *
1395 * "typedef const _Tp& const_reference"
1396 *
1397 * CC then checks that back()'s parent, AAA, is an STL container which relies on allocator. Since it
1398 * is, this typedef is added to the search scope.
1399 *
1400 * [in NativeParserBase::AddTemplateAlias()]
1401 * CC sees the typedef in the search scope. It searches AAA's template map for the actual type of
1402 * "_Tp" and finds "string". So "string" is added to the scope.
1403 *
1404 * That's the big picture. The negative of this patch is that it relies on how the C++ STL library
1405 * is written. If the library is ever changed significantly, then this patch will need to be updated.
1406 * It was an ok sacrifice to make for cleaner, maintainable code.
1407 */
GenerateResultSet(TokenTree * tree,const wxString & target,const TokenIdxSet & parentSet,TokenIdxSet & result,bool caseSens,bool isPrefix,cb_unused short int kindMask)1408 size_t NativeParserBase::GenerateResultSet(TokenTree* tree,
1409 const wxString& target,
1410 const TokenIdxSet& parentSet,
1411 TokenIdxSet& result,
1412 bool caseSens,
1413 bool isPrefix,
1414 cb_unused short int kindMask)
1415 {
1416 if (!tree) return 0;
1417
1418 TRACE(_T("NativeParserBase::GenerateResultSet_2()"));
1419
1420 if (target.IsEmpty())
1421 {
1422 for (TokenIdxSet::const_iterator ptr = parentSet.begin(); ptr != parentSet.end(); ++ptr)
1423 {
1424 size_t parentIdx = (*ptr);
1425 Token* parent = tree->at(parentIdx);
1426 if (!parent)
1427 continue;
1428
1429 for (TokenIdxSet::const_iterator it = parent->m_Children.begin();
1430 it != parent->m_Children.end();
1431 ++it)
1432 {
1433 const Token* token = tree->at(*it);
1434 if (!token)
1435 continue;
1436 if ( !AddChildrenOfUnnamed(tree, token, result) )
1437 {
1438 result.insert(*it);
1439 AddChildrenOfEnum(tree, token, result);
1440 }
1441 }
1442
1443 tree->RecalcInheritanceChain(parent);
1444
1445 for (TokenIdxSet::const_iterator it = parent->m_Ancestors.begin();
1446 it != parent->m_Ancestors.end();
1447 ++it)
1448 {
1449 const Token* ancestor = tree->at(*it);
1450 if (!ancestor)
1451 continue;
1452 for (TokenIdxSet::const_iterator it2 = ancestor->m_Children.begin();
1453 it2 != ancestor->m_Children.end();
1454 ++it2)
1455 {
1456 const Token* token = tree->at(*it2);
1457 if (!token)
1458 continue;
1459 if ( !AddChildrenOfUnnamed(tree, token, result) )
1460 {
1461 result.insert(*it2);
1462 AddChildrenOfEnum(tree, token, result);
1463 }
1464 }
1465 }
1466 }
1467 }
1468 else
1469 {
1470 // we use FindMatches to get the items from tree directly and eliminate the
1471 // items which are not under the search scope.
1472 TokenIdxSet textMatchSet, tmpMatches;
1473 if (tree->FindMatches(target, tmpMatches, caseSens, isPrefix))
1474 {
1475 TokenIdxSet::const_iterator it;
1476 for (it = tmpMatches.begin(); it != tmpMatches.end(); ++it)
1477 {
1478 const Token* token = tree->at(*it);
1479 if (token)
1480 textMatchSet.insert(*it);
1481 }
1482 }
1483 // eliminate the tokens.
1484 if (!textMatchSet.empty())
1485 {
1486 TRACE(_T("Find %lu valid text matched tokens from the tree."),
1487 static_cast<unsigned long>(textMatchSet.size()));
1488
1489 // get the tokens under the search scope. Note: tokens can have the same names, but we are
1490 // only interests those under the search scope, here the search scope is the parentSet,
1491 // So, the outer loop is the parentSet, which is the search scope
1492 for (TokenIdxSet::const_iterator parentIterator = parentSet.begin();
1493 parentIterator != parentSet.end();
1494 ++parentIterator)
1495 {
1496 // to make it clear, parentIdx stands for search scope. (Token Idx)
1497 // (*it) stand for matched item id.
1498 int parentIdx = (*parentIterator);
1499
1500 // The inner loop is the textMatchSet
1501 for (TokenIdxSet::const_iterator it = textMatchSet.begin();
1502 it != textMatchSet.end();
1503 ++it)
1504 {
1505 const Token* token = tree->at(*it);
1506 // check whether its under the parentIdx
1507 // NOTE: check for unnamed or enum inside class.
1508 // eg, 'ParserCommon::ParserState::ptCreateParser' should be accessed as
1509 // 'ParserCommon::ptCreateParser'.
1510 // Here, token is ptCreateParser and parentIdx is ParserCommon, so
1511 // 'token->m_ParentIndex == parentIdx' is false. Now, we iterate over the
1512 // children of parentIdx and check if any of them is unnamed or enum
1513 // and match with token->m_ParentIndex. Thus if we confirm that 'token' is a
1514 // child of unnamed or enum(i.e., m_ParentIndex), we add the token to result.
1515 if (token && ((token->m_ParentIndex == parentIdx)
1516 || IsChildOfUnnamedOrEnum(tree, token->m_ParentIndex, parentIdx)))
1517 result.insert(*it);
1518
1519 // "result" will become the search scope for the next loop, so
1520 // if the parentIdx has ancestors, we need to add them too.
1521 if (parentIdx != -1) //global namespace does not have ancestors
1522 {
1523 Token* tokenParent = tree->at(parentIdx);
1524 if (tokenParent)
1525 {
1526 // Here, we are going to calculate all tk's ancestors
1527 // Finally we will add them in the "result".
1528 tree->RecalcInheritanceChain(tokenParent);
1529
1530 // This is somewhat tricky, for example, we have one tk, which has the
1531 // tk->m_AncestorsString == wxNavigationEnabled<wxWindow>
1532 // Normally, the wxNavigationEnabled will be added, but if we have:
1533 // template <class W>
1534 // class wxNavigationEnabled : public W
1535 // Shall we add the "W" as tk's ancestors? W is a formalTemplateArgument
1536
1537 // Add tk's ancestors
1538 for ( TokenIdxSet::const_iterator ancestorIterator = tokenParent->m_Ancestors.begin();
1539 ancestorIterator != tokenParent->m_Ancestors.end();
1540 ++ancestorIterator )
1541 {
1542 // NOTE: check for unnamed or enum inside class (see note above).
1543 if (token && ((token->m_ParentIndex == (*ancestorIterator)) //matched
1544 || IsChildOfUnnamedOrEnum(tree, token->m_ParentIndex, (*ancestorIterator))))
1545 result.insert(*it);
1546 }
1547 }
1548 }
1549 else if (-1 == parentIdx)
1550 {
1551 //if the search scope is global,and the token's parent token kind is tkEnum ,we add them too.
1552 const Token* parentToken = tree->at(token->m_ParentIndex);
1553 if (parentToken && parentToken->m_TokenKind == tkEnum)
1554 result.insert(*it);
1555 }
1556
1557 // Check if allocator class tokens should be added to the search scope.
1558 // allocator holds the typedefs that CC needs to handle STL containers.
1559 // An allocator token will be added if parentIdx is a child of an allocator dependent class.
1560 // Most STL containers are dependent on allocator.
1561 //
1562 // For example, suppose we are completing:
1563 // vector<string> AAA;
1564 // AAA.back().
1565 //
1566 // Here, parentIdx == "back()", which is a child of the allocator dependent class, vector.
1567 // So we add (*it) to the search scope if it is an allocator token.
1568 if (token && IsAllocator(tree, token->m_ParentIndex)
1569 && DependsOnAllocator(tree, parentIdx))
1570 result.insert(*it);
1571 }
1572 }
1573 }
1574 else
1575 {
1576 // We need to handle namespace aliases too. I hope we can find a good way to do this.
1577 // TODO: Handle template class here.
1578 if (parentSet.count(-1))
1579 {
1580 const TokenList* tl = tree->GetTokens();
1581 for (TokenList::const_iterator it = tl->begin(); it != tl->end(); ++it)
1582 {
1583 const Token* token = (*it);
1584 if (token && token->m_TokenKind == tkNamespace && token->m_Aliases.size())
1585 {
1586 for (size_t i = 0; i < token->m_Aliases.size(); ++i)
1587 {
1588 if (token->m_Aliases[i] == target)
1589 {
1590 result.insert(token->m_Index);
1591 // break; ?
1592 }
1593 }
1594 }
1595 }
1596 }
1597 }
1598 }
1599
1600 return result.size();
1601 }
1602
1603 // No critical section needed in this function!
1604 // All functions that call this function, should already entered a critical section.
IsAllocator(TokenTree * tree,const int & id)1605 bool NativeParserBase::IsAllocator(TokenTree* tree,
1606 const int& id)
1607 {
1608 if (!tree)
1609 return false;
1610
1611 const Token* token = tree->at(id);
1612 return (token && token->m_Name.IsSameAs(_T("allocator")));
1613 }
1614
1615 // No critical section needed in this recursive function!
1616 // All functions that call this recursive function, should already entered a critical section.
1617 //
1618 // Currently, this function only identifies STL containers dependent on allocator.
DependsOnAllocator(TokenTree * tree,const int & id)1619 bool NativeParserBase::DependsOnAllocator(TokenTree* tree,
1620 const int& id)
1621 {
1622 if (!tree)
1623 return false;
1624
1625 const Token* token = tree->at(id);
1626 if (!token)
1627 return false;
1628
1629 // If the STL class depends on allocator, it will have the form:
1630 // template <typename T, typename _Alloc = std::allocator<T> > class AAA { ... };
1631 if (token->m_TemplateArgument.Find(_T("_Alloc")) != wxNOT_FOUND)
1632 return true;
1633
1634 // The STL class could also be a container adapter:
1635 // template <typename T, typename _Sequence = AAA<T> > class BBB { ... };
1636 // where AAA depends on allocator.
1637 if (token->m_TemplateArgument.Find(_T("_Sequence")) != wxNOT_FOUND)
1638 return true;
1639
1640 return DependsOnAllocator(tree, token->m_ParentIndex);
1641 }
1642
CollectSearchScopes(const TokenIdxSet & searchScope,TokenIdxSet & actualTypeScope,TokenTree * tree)1643 void NativeParserBase::CollectSearchScopes(const TokenIdxSet& searchScope,
1644 TokenIdxSet& actualTypeScope,
1645 TokenTree* tree)
1646 {
1647 CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
1648
1649 for (TokenIdxSet::const_iterator pScope=searchScope.begin(); pScope!=searchScope.end(); ++pScope)
1650 {
1651 actualTypeScope.insert(*pScope);
1652 // we need to pScope's parent scope too.
1653 if ((*pScope) != -1)
1654 {
1655 const Token* token = tree->at(*pScope);
1656 if (!token)
1657 continue;
1658 const Token* parent = tree->at(token->m_ParentIndex);
1659 while (true)
1660 {
1661 if (!parent)
1662 break;
1663 actualTypeScope.insert(parent->m_Index);
1664 parent = tree->at(parent->m_ParentIndex);
1665 }
1666 }
1667 }
1668
1669 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
1670 }
1671
1672 // No critical section needed in this recursive function!
1673 // All functions that call this function, should already entered a critical section.
GetTokenFromCurrentLine(TokenTree * tree,const TokenIdxSet & tokens,size_t curLine,const wxString & file)1674 int NativeParserBase::GetTokenFromCurrentLine(TokenTree* tree,
1675 const TokenIdxSet& tokens,
1676 size_t curLine,
1677 const wxString& file)
1678 {
1679 TRACE(_T("NativeParserBase::GetTokenFromCurrentLine()"));
1680
1681 int result = -1;
1682 bool found = false;
1683 if (!tree)
1684 return result;
1685
1686 const size_t fileIdx = tree->InsertFileOrGetIndex(file);
1687 const Token* classToken = nullptr;
1688 for (TokenIdxSet::const_iterator it = tokens.begin(); it != tokens.end(); ++it)
1689 {
1690 const Token* token = tree->at(*it);
1691 if (!token)
1692 continue;
1693
1694 TRACE(_T("GetTokenFromCurrentLine() Iterating: tN='%s', tF='%s', tStart=%u, tEnd=%u"),
1695 token->DisplayName().wx_str(), token->GetFilename().wx_str(),
1696 token->m_ImplLineStart, token->m_ImplLineEnd);
1697
1698 if ( token->m_TokenKind & tkAnyFunction
1699 && token->m_ImplFileIdx == fileIdx
1700 && token->m_ImplLine <= curLine
1701 && token->m_ImplLineEnd >= curLine)
1702 {
1703 TRACE(_T("GetTokenFromCurrentLine() tkAnyFunction : tN='%s', tF='%s', tStart=%u, tEnd=%u"),
1704 token->DisplayName().wx_str(), token->GetFilename().wx_str(),
1705 token->m_ImplLineStart, token->m_ImplLineEnd);
1706 result = token->m_Index;
1707 found = true;
1708 }
1709 else if ( token->m_TokenKind == tkConstructor
1710 && token->m_ImplFileIdx == fileIdx
1711 && token->m_ImplLine <= curLine
1712 && token->m_ImplLineStart >= curLine)
1713 {
1714 TRACE(_T("GetTokenFromCurrentLine() tkConstructor : tN='%s', tF='%s', tStart=%u, tEnd=%u"),
1715 token->DisplayName().wx_str(), token->GetFilename().wx_str(),
1716 token->m_ImplLineStart, token->m_ImplLineEnd);
1717 result = token->m_Index;
1718 found = true;
1719 }
1720 else if ( token->m_TokenKind == tkClass
1721 && token->m_ImplLineStart <= curLine
1722 && token->m_ImplLineEnd >= curLine)
1723 {
1724 TRACE(_T("GetTokenFromCurrentLine() tkClass : tN='%s', tF='%s', tStart=%u, tEnd=%u"),
1725 token->DisplayName().wx_str(), token->GetFilename().wx_str(),
1726 token->m_ImplLineStart, token->m_ImplLineEnd);
1727 classToken = token;
1728 continue;
1729 }
1730
1731 if (found) break; // exit for-loop
1732
1733 TRACE(_T("GetTokenFromCurrentLine() Function out of bounds: tN='%s', tF='%s', tStart=%u, ")
1734 _T("tEnd=%u, line=%lu (size_t)line=%lu"), token->DisplayName().wx_str(),
1735 token->GetFilename().wx_str(), token->m_ImplLineStart, token->m_ImplLineEnd,
1736 static_cast<unsigned long>(curLine), static_cast<unsigned long>(curLine));
1737 }
1738
1739 if (classToken)
1740 result = classToken->m_Index;
1741
1742 return result;
1743 }
1744
ComputeCallTip(TokenTree * tree,const TokenIdxSet & tokens,wxArrayString & items)1745 void NativeParserBase::ComputeCallTip(TokenTree* tree,
1746 const TokenIdxSet& tokens,
1747 wxArrayString& items)
1748 {
1749 CC_LOCKER_TRACK_TT_MTX_LOCK(s_TokenTreeMutex)
1750
1751 for (TokenIdxSet::const_iterator it = tokens.begin(); it != tokens.end(); ++it)
1752 {
1753 const Token* token = tree->at(*it);
1754 if (!token)
1755 continue;
1756
1757 // support constructor call tips
1758 if (token->m_TokenKind == tkVariable)
1759 {
1760 TokenIdxSet classes;
1761 tree->FindMatches(token->m_BaseType, classes, true, false, tkClass);
1762 for (TokenIdxSet::const_iterator clIt = classes.begin(); clIt != classes.end(); ++clIt)
1763 {
1764 const Token* tk = tree->at(*clIt);
1765 if (tk)
1766 {
1767 token = tk;
1768 break;
1769 }
1770 }
1771 }
1772 if (token->m_TokenKind == tkClass)
1773 {
1774 for (TokenIdxSet::iterator chIt = token->m_Children.begin();
1775 chIt != token->m_Children.end();
1776 ++chIt)
1777 {
1778 const Token* tk = tree->at(*chIt);
1779 if ( tk && ( tk->m_TokenKind == tkConstructor
1780 || (tk->m_IsOperator && tk->m_Name.EndsWith(wxT("()"))) )
1781 && (tk->m_Scope == tsPublic || tk->m_Scope == tsUndefined) )
1782 {
1783 wxString tkTip;
1784 if (PrettyPrintToken(tree, tk, tkTip))
1785 items.Add(tkTip);
1786 }
1787 }
1788 continue;
1789 }
1790
1791 // support macro call tips
1792 // NOTE: improved to support more advanced cases: preprocessor token mapped to
1793 // function / macro name or variable name (for typedef'd function ptr). Eg,
1794 // #define __MINGW_NAME_AW(func) func##A
1795 // #define MessageBox __MINGW_NAME_AW(MessageBox)
1796 // MessageBox( // --> Use calltip for MessageBoxA().
1797 // see details in
1798 // http://forums.codeblocks.org/index.php/topic,19278.msg133989.html#msg133989
1799
1800 // only handle variable like macro definitions
1801 if (token->m_TokenKind == tkMacroDef && token->m_Args.empty())
1802 {
1803 // NOTE: we use m_FullType for our search so that we accept function / macro NAMES only,
1804 // any actual calls will be rejected (i.e., allow "#define MessageBox MessageBoxA", but
1805 // not "#define MessageBox MessageBoxA(...)"
1806 const Token* tk = tree->at(tree->TokenExists(token->m_FullType, -1,
1807 tkFunction|tkMacroDef|tkVariable));
1808
1809 // either a function or a variable, but it is OK if a macro with not empty m_Args.
1810 if (tk && ((tk->m_TokenKind ^ tkMacroDef) || !tk->m_Args.empty()))
1811 token = tk; // tkVariable could be a typedef'd function ptr (checked in PrettyPrintToken())
1812 else
1813 {
1814 // a variable like macro, this token don't have m_Args(call tip information), but
1815 // if we try to expand the token, and finally find some one who do have m_Args, then
1816 // the expanded token's m_Args can used as call tips.
1817 Tokenizer smallTokenizer(tree);
1818 smallTokenizer.InitFromBuffer(token->m_FullType + _T('\n'));
1819 tk = tree->at(tree->TokenExists(smallTokenizer.GetToken(), -1, tkFunction|tkMacroDef|tkVariable));
1820 // only if the expanded result is a single token
1821 if (tk && smallTokenizer.PeekToken().empty())
1822 token = tk;
1823 }
1824 }
1825
1826 wxString tkTip;
1827 if ( !PrettyPrintToken(tree, token, tkTip) )
1828 tkTip = wxT("Error while pretty printing token!");
1829 items.Add(tkTip);
1830
1831 }// for
1832
1833 CC_LOCKER_TRACK_TT_MTX_UNLOCK(s_TokenTreeMutex)
1834 }
1835
PrettyPrintToken(TokenTree * tree,const Token * token,wxString & result,bool isRoot)1836 bool NativeParserBase::PrettyPrintToken(TokenTree* tree,
1837 const Token* token,
1838 wxString& result,
1839 bool isRoot)
1840 {
1841 wxString name = token->m_Name;
1842 // a variable basically don't have call tips, but if it's type is a typedef'd function
1843 // pointer, we can still have call tips (which is the typedef function's arguments)
1844 if (token->m_TokenKind == tkVariable)
1845 {
1846 const Token* tk = tree->at(tree->TokenExists(token->m_BaseType, token->m_ParentIndex, tkTypedef));
1847 if (!tk && token->m_ParentIndex != -1)
1848 tk = tree->at(tree->TokenExists(token->m_BaseType, -1, tkTypedef));
1849 if (tk && !tk->m_Args.empty()) // typedef'd function pointer
1850 {
1851 name = token->m_Name;
1852 token = tk;
1853 }
1854 }
1855
1856 // if the token has parents and the token is a container or a function,
1857 // then pretty print the parent of the token->
1858 if ( (token->m_ParentIndex != -1)
1859 && (token->m_TokenKind & (tkAnyContainer | tkAnyFunction)) )
1860 {
1861 const Token* parentToken = tree->at(token->m_ParentIndex);
1862 if (!parentToken || !PrettyPrintToken(tree, parentToken, result, false))
1863 return false;
1864 }
1865
1866 switch (token->m_TokenKind)
1867 {
1868 case tkConstructor:
1869 result = result + token->m_Name + token->GetFormattedArgs();
1870 return true;
1871
1872 case tkFunction:
1873 result = token->m_FullType + wxT(" ") + result + token->m_Name + token->GetFormattedArgs();
1874 if (token->m_IsConst)
1875 result += wxT(" const");
1876 if (token->m_IsNoExcept)
1877 result += wxT(" noexcept");
1878 return true;
1879
1880 case tkClass:
1881 case tkNamespace:
1882 if (isRoot)
1883 result += token->m_Name;
1884 else
1885 result += token->m_Name + wxT("::");
1886 return true;
1887
1888 case tkMacroDef:
1889 if (!token->GetFormattedArgs().IsEmpty())
1890 result = wxT("#define ") + token->m_Name + token->GetFormattedArgs();
1891 return true;
1892
1893 case tkTypedef:
1894 result = token->m_BaseType + wxT(" ") + result + name + token->GetFormattedArgs();
1895 return true;
1896
1897 case tkEnum:
1898 case tkDestructor:
1899 case tkVariable:
1900 case tkEnumerator:
1901 case tkMacroUse:
1902 case tkAnyContainer:
1903 case tkAnyFunction:
1904 case tkUndefined:
1905 default:
1906 break;
1907 }
1908 return true;
1909 }
1910