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 
6 #ifndef NATIVEPARSERBASE_H
7 #define NATIVEPARSERBASE_H
8 
9 #if wxCHECK_VERSION(3, 0, 0)
10 #include <wx/wxcrt.h> // wxIsalnum
11 #endif
12 #include <wx/string.h>
13 
14 #include <map>
15 #include <queue>
16 
17 #include "parser/token.h"
18 #include "parser/tokentree.h"
19 
20 /** debug only variable, used to print the AI match related log message */
21 extern bool s_DebugSmartSense;
22 
23 class NativeParserBase
24 {
25 public:
26     /** divide a statement to several pieces(parser component), each component has a type member */
27     enum ParserTokenType
28     {
29         pttUndefined = 0,
30         pttSearchText,
31         pttClass,
32         pttNamespace,
33         pttFunction
34     };
35 
36     /** the delimiter separating two Parser Component, See ParserComponent struct for more details */
37     enum OperatorType
38     {
39         otOperatorUndefined = 0,
40         otOperatorSquare,
41         otOperatorParentheses,
42         otOperatorPointer,
43         otOperatorStar
44     };
45 
46     /** @brief a long statement can be divided to a ParserComponent chain.
47      *
48      * e.g. for a statement like below:
49      * @code
50      * Ogre::Root::getSingleton().|
51      * @endcode
52      *
53      *  a chains of four ParserComponents will be generated and list below:
54      * @code
55      *  Ogre             [pttNamespace]
56      *  Root             [pttClass]
57      *  getSingleton     [pttFunction]
58      *  (empty space)    [pttSearchText]
59      * @endcode
60      *
61      * a ParserComponent is mainly an identifier, which we use this identifier name to query on the
62      * Symbol tree, and try to get the matched symbols.
63      * For this example, we first try to search the Symbol tree by the keyword "Ogre", this will
64      * match a symbol which has type "Namespace".
65      * The next step, we search the "Root" under the previous returned Symbols.
66      * In some special cases, such as "array[7]->b", we gives such result
67      * @code
68      *  array            [pttNamespace] (variable name?)
69      *  []               [pttFunction, which is operator[]]
70      *  b                [pttSearchText]
71      * @endcode
72      */
73     struct ParserComponent
74     {
75         wxString        component;          /// name
76         ParserTokenType tokenType;          /// type
77         OperatorType    tokenOperatorType;  /// operator type
78 
ParserComponentParserComponent79         ParserComponent() { Clear(); }
ClearParserComponent80         void Clear()
81         {
82             component         = wxEmptyString;
83             tokenType         = pttUndefined;
84             tokenOperatorType = otOperatorUndefined;
85         }
86     };
87 
88     /** Constructor */
89     NativeParserBase();
90 
91     /** Destructor */
92     virtual ~NativeParserBase();
93 
94 protected:
95 
96     /** Init cc search member variables */
97     void Reset();
98 
99     /**@brief Artificial Intelligence Matching
100     *
101     * All functions that call this recursive function, should already entered a critical section or
102     * a mutex to protect the TokenTree.
103     *
104     * match (consume) the ParserComponent queue from left to right,
105     * the output result becomes the search scope of the next match.
106     * finally, give the results which match the last ParserComponent.
107     * @param components input ParserComponent queue
108     * @param parentTokenIdx, initial search scope of the left most component, this is the direct
109     * parent of the current statement(expression)
110     * @param fullMatch the result should be a full text match or prefix match
111     * @return matching token number, it is the size of result
112     */
113     size_t FindAIMatches(TokenTree*                  tree,
114                          std::queue<ParserComponent> components,
115                          TokenIdxSet&                result,
116                          int                         parentTokenIdx = -1,
117                          bool                        isPrefix = false,
118                          bool                        caseSensitive = false,
119                          bool                        use_inheritance = true,
120                          short int                   kindMask = 0xFFFF,
121                          TokenIdxSet*                search_scope = 0);
122 
123     /** if the expression return the container tokens, which are the
124      * parent of the expression.
125      * @param[in] procResult input function index collection
126      * @param[out] scopeResult filtered output function index collection
127      * For example, if we have such code
128      * @code
129      * class A
130      * {
131      *      void f()
132      *      {
133      *         statement|<-----CC here
134      *      };
135      * }
136      * @endcode
137      * We try to locate the Tokens their scopes "Cover" the "statement"
138      */
139     void FindCurrentFunctionScope(TokenTree*         tree,
140                                   const TokenIdxSet& procResult,
141                                   TokenIdxSet&       scopeResult);
142 
143     /** remove all the container tokens in the token index set.
144      * @param searchScope The Tokens we need to remove from the tree
145      */
146     void CleanupSearchScope(TokenTree*  tree,
147                             TokenIdxSet* searchScope);
148 
149     /** Returns the start and end of the call-tip highlight region.
150      * For a function prototype "void MyNamespace::SomeClass::func(int a, float b)"
151      * if we have a function call statement "obj->f(x,y)", when we hover on the "y", we should
152      * high light the "float b" in the calltip
153      * @param[in] calltip is the calltip string
154      * @param[out] start the start index of the high light string
155      * @param[out] end the end index of the high light string
156      * @param[in] typedCommas e.g. "func(x, y)", in this case, we say we have typed one comma before
157      * the hovered "y", so we know we need to high light the second parameter, which is "float b"
158      */
159     void GetCallTipHighlight(const wxString& calltip,
160                              int*            start,
161                              int*            end,
162                              int             typedCommas);
163 
164     /** Finds the position of the opening parenthesis marking the beginning of the params.
165      * See GetCallTipHighlight() for more details
166      */
167     int FindFunctionOpenParenthesis(const wxString& calltip);
168 
169     /** helper function to split the statement
170      *
171      * @param line a statement string
172      * @param[out] tokenType the returned type of the string
173      * @param[out] tokenOperatorType if it is a function call token, specify which type of function call
174      * It contains a string on the following form:
175      * @code
176      *     char* mychar = SomeNamespace::m_SomeVar.SomeMeth
177      *                                                     ^----start from here
178      * @endcode
179      * Usually, the caret is located at the end of the line.
180      *
181      * first we locate the first non-space char starting from the *end*:
182      * @code
183      *     char* mychar = SomeNamespace::m_SomeVar.SomeMeth
184      *                    ^----stop here
185      * @endcode
186      * then we remove everything before it, so we get "SomeNamespace::m_SomeVar.SomeMeth"
187      *
188      * Now we cut the first component "SomeNamespace" and return it.
189      * The statement line becomes:
190      * @code
191      * m_SomeVar.SomeMeth
192      * @endcode
193      * so that if we call this function again with the (modified) line,
194      * we'll return "m_SomeVar" and modify line (again) to become:
195      * @code
196      *     SomeMeth
197      * @endcode
198      * and so on and so forth until we return an empty string...
199      * NOTE: if we find () args or [] arrays in our way, we skip them (done in GetNextCCToken)...
200      * todo: it looks like [] is not skipped, because we have to handle the operator[]
201      * also, if we see a aaa(), we always think it is a function call
202      */
203     wxString GetCCToken(wxString&        line,
204                         ParserTokenType& tokenType,
205                         OperatorType&    tokenOperatorType);
206 
207     /** helper function to split the statement
208      *  @code
209      *   "    SomeNameSpace::SomeClass.SomeMethod|"
210      *        ^  should stop here  <------------ ^ start from here, go backward(right to left)
211      *   "    f(SomeNameSpace::SomeClass.SomeMethod|"
212      *          ^ should stop here
213      *  @endcode
214      *  so, brace level should be considered
215      */
216     unsigned int FindCCTokenStart(const wxString& line);
217 
218     /** helper function to read the next CCToken, begin from the startAt, this point to a non-space
219      * character, and fetch the beginning identifier
220      * @param startAt this will be updated to the char after the identifier
221      * @param tokenOperatorType the type of the operator
222      * E.g.
223      * @code
224      *            SomeMethod()->
225      *            ^begin
226      * @endcode
227      * the returned wxString is "SomeMethod", the tokenOperatorType is pointer member access
228      */
229     wxString GetNextCCToken(const wxString& line,
230                             unsigned int&   startAt,
231                             OperatorType&   tokenOperatorType);
232 
233     /** Remove the last function's children, when doing codecompletion in a function body, the
234      *  function body up to the caret position was parsed, and the local variables defined in
235      *  the function were recorded as the function's children.
236      *  Note that these tokens are marked as temporary tokens, so if the edit caret moves to another
237      *  function body, these temporary tokens should be removed.
238      */
239     void RemoveLastFunctionChildren(TokenTree* tree, int& lastFuncTokenIdx);
240 
241     /** @brief break a statement to several ParserComponents, and store them in a queue.
242      * @param actual a statement string to be divided.
243      * @param components output variable containing the queue.
244      * @return number of ParserComponent
245      */
246     size_t BreakUpComponents(const wxString&              actual,
247                              std::queue<ParserComponent>& components);
248 
249     /** A statement(expression) is expressed by a ParserComponent queue
250      *  We do a match from the left of the queue one by one.
251      *
252      *
253      * Here is a simple description about the algorithm, suppose we have such code snippet
254      * @code
255      * namespace AAA
256      * {
257      *     class BBB
258      *     {
259      *     public:
260      *         int m_aaa;
261      *     }
262      *     class CCC
263      *     {
264      *     public:
265      *         BBB fun();
266      *     }
267      * }
268      * AAA::CCC obj;
269      * obj.fun().|-----we want to get code suggestion list here
270      * @endcode
271      * We first split the statement "obj.fun()." into 3 components:
272      * component name
273      * @code
274      * 1, obj
275      * 2, fun
276      * 3, empty
277      * @endcode
278      * We do three loops here, each loop, we consume one component. Also each loop's result will
279      * serve as the next loop's search scope.
280      *
281      * Loop 1
282      * We first search the tree by the text "obj", we find a matched variable token, which has the
283      * type string "AAA::CCC", then the text "AAA::CCC" is resolved to a class kind token "class CCC"
284      * Loop 2
285      * We search the tree by the text "fun". Here the search scope should be "CCC", it's the result
286      * from the previous loop, so we find that there is a function kind token under "class CCC",
287      * which is "function fun()" token. Then we need to see the return type of the fun() token,
288      * which is the name "BBB". Then we do another text search for "BBB" in the tree, and find a
289      * class kind token "class BBB"
290      * Loop 3
291      * Since the last search text is empty, we just return all the children of the "class BBB" token,
292      * so finally, we give the child variable kind token "m_aaa", then the code suggestion should
293      * prompt the string "m_aaa"
294      *
295      * @param tree the token tree pointer
296      * @param components expression structure expressed in std::queue<ParserComponent>
297      * @param searchScope search scope defined by TokenIdxSet
298      * @param[out] the final result token index
299      * @param caseSense case sensitive match
300      * @param isPrefix match type( full match or prefix match)
301      * @return result tokens count
302      */
303     size_t ResolveExpression(TokenTree*                  tree,
304                              std::queue<ParserComponent> components,
305                              const TokenIdxSet&          searchScope,
306                              TokenIdxSet&                result,
307                              bool                        caseSense = true,
308                              bool                        isPrefix = false);
309 
310     /** used to solve the overloaded operator functions return type
311      * @param tokenOperatorType overloaded operator type, could be [], (), ->
312      * @param tokens input tokens set
313      * @param tree Token tree pointer
314      * @param searchScope search scope
315      * @param result output result
316      */
317     void ResolveOperator(TokenTree*          tree,
318                          const OperatorType& tokenOperatorType,
319                          const TokenIdxSet&  tokens,
320                          const TokenIdxSet&  searchScope,
321                          TokenIdxSet&        result);
322 
323     /** Get the Type information of the searchText string
324      * @param searchText input search text
325      * @param searchScope search scope defined in TokenIdxSet format
326      * @param result result token specify the Type of searchText
327      */
328     size_t ResolveActualType(TokenTree*         tree,
329                              wxString           searchText,
330                              const TokenIdxSet& searchScope,
331                              TokenIdxSet&       result);
332 
333     /** resolve template map [formal parameter] to [actual parameter]
334      * @param searchStr input Search String
335      * @param actualtypeScope Token type(actual parameter)
336      * @param initialScope search scope
337      */
338     void ResolveTemplateMap(TokenTree*         tree,
339                             const wxString&    searchStr,
340                             const TokenIdxSet& actualTypeScope,
341                             TokenIdxSet&       initialScope);
342 
343     /** add template parameter, get the actual parameter from the formal parameter list
344      * @param id template token id
345      * @param actualTypeScope search scope
346      * @param initialScope resolved result
347      * @param tree Token tree pointer.
348      */
349     void AddTemplateAlias(TokenTree*         tree,
350                           const int&         id,
351                           const TokenIdxSet& actualTypeScope,
352                           TokenIdxSet&       initialScope);
353 
354     /** Generate the matching results under the Parent Token index set
355      *
356      * All functions that call this recursive function, should already entered a critical section.
357      *
358      * @param tree TokenTree pointer
359      * @param target Scope (defined in TokenIdxSet)
360      * @param result result token index set
361      * @param isPrefix whether a full match is used or only do a prefix match
362      * @param kindMask define the result tokens filter, such as only class type is OK
363      * @return result token set number
364      */
365     size_t GenerateResultSet(TokenTree*      tree,
366                              const wxString& target,
367                              int             parentIdx,
368                              TokenIdxSet&    result,
369                              bool            caseSens = true,
370                              bool            isPrefix = false,
371                              short int       kindMask = 0xFFFF);
372 
373     /** This function is just like the one above, especially that it use a single parent Token id,
374      *  not the parent id set in previous one.
375      *
376      * All functions that call this recursive function, should already entered a critical section.
377      *
378      */
379     size_t GenerateResultSet(TokenTree*         tree,
380                              const wxString&    target,
381                              const TokenIdxSet& ptrParentID,
382                              TokenIdxSet&       result,
383                              bool               caseSens = true,
384                              bool               isPrefix = false,
385                              short int          kindMask = 0xFFFF);
386 
387     /** Test if token with this id is allocator class.
388      *
389      * All functions that call this function, should already entered a critical section.
390      *
391      * @param tree TokenTree pointer
392      * @param id token idx
393      */
394     bool IsAllocator(TokenTree*   tree,
395                      const int&     id);
396 
397     /** Test if token with this id depends on allocator class.
398      * Currently, this function only identifies STL containers dependent on allocator.
399      *
400      * All functions that call this recursive function, should already entered a critical section.
401      *
402      * @param tree TokenTree pointer
403      * @param id token idx
404      */
405     bool DependsOnAllocator(TokenTree*    tree,
406                             const int&    id);
407 
408     /** Collect search scopes, add the searchScopes's parent scope
409      * @param searchScope input search scope
410      * @param actualTypeScope returned search scope
411      * @param tree TokenTree pointer
412      */
413     void CollectSearchScopes(const TokenIdxSet& searchScope,
414                              TokenIdxSet&       actualTypeScope,
415                              TokenTree*         tree);
416 
417     /** used to get the correct token index in current line, e.g.
418      * @code
419      * class A
420      * {
421      *    void test()
422      *    {               // start of the function body
423      *       |
424      *    };              // end of the function body
425      * };
426      * @endcode
427      * @param tokens all current file's function and class, which cover the current line
428      * @param curLine the line of the current caret position
429      * @param file editor file name
430      */
431     int GetTokenFromCurrentLine(TokenTree*         tree,
432                                 const TokenIdxSet& tokens,
433                                 size_t             curLine,
434                                 const wxString&    file);
435 
436     /** call tips are tips when you are entering some functions, such as you have a class definition
437      * @code
438      *  class A {
439      *  public:
440      *      void A() {};
441      *      void test() { };
442      *  };
443      *  when you are entering some text like
444      *  A(|    or  objA.test(|
445      * @endcode
446      * then there will be a tip window show the function prototype of the function
447      *
448      */
449     void ComputeCallTip(TokenTree*         tree,
450                         const TokenIdxSet& tokens,
451                         wxArrayString&     items);
452 
453     /** For ComputeCallTip()
454      * No critical section needed in this recursive function!
455      * All functions that call this recursive function, should already entered a critical section. */
456     bool PrettyPrintToken(TokenTree*   tree,
457                           const Token* token,
458                           wxString&    result,
459                           bool         isRoot = true);
460 
461     // convenient static funcs for fast access and improved readability
462 
463     // count commas in lineText (nesting parentheses)
CountCommas(const wxString & lineText,int start)464     static int CountCommas(const wxString& lineText, int start)
465     {
466         int commas = 0;
467         int nest = 0;
468         while (true)
469         {
470             wxChar c = lineText.GetChar(start++);
471             if (c == '\0')
472                 break;
473             else if (c == '(')
474                 ++nest;
475             else if (c == ')')
476                 --nest;
477             else if (c == ',' && nest == 1)
478                 ++commas;
479         }
480         return commas;
481     }
482 
483     /** check whether the line[startAt] point to the identifier
484      * @code
485      *  SomeMethod(arg1, arg2)->Method2()
486      *  ^^^^^^^^^^ those index will return true
487      * @endcode
488      */
InsideToken(int startAt,const wxString & line)489     static bool InsideToken(int startAt, const wxString& line)
490     {
491         return (   (startAt >= 0)
492                 && ((size_t)startAt < line.Len())
493                 && (   (wxIsalnum(line.GetChar(startAt)))
494                     || (line.GetChar(startAt) == '_') ) );
495     }
496 
497     /** go to the first character of the identifier, e.g
498      * @code
499      * "    f(SomeNameSpace::SomeClass.SomeMethod"
500      *                    return value^         ^begin
501      * @endcode
502      *   this is the index before the first character of the identifier
503      */
BeginOfToken(int startAt,const wxString & line)504     static int BeginOfToken(int startAt, const wxString& line)
505     {
506         while (   (startAt >= 0)
507                && ((size_t)startAt < line.Len())
508                && (   (wxIsalnum(line.GetChar(startAt)))
509                    || (line.GetChar(startAt) == '_') ) )
510             --startAt;
511         return startAt;
512     }
BeforeToken(int startAt,const wxString & line)513     static int BeforeToken(int startAt, const wxString& line)
514     {
515         if (   (startAt > 0)
516             && ((size_t)startAt < line.Len() + 1)
517             && (   (wxIsalnum(line.GetChar(startAt - 1)))
518                 || (line.GetChar(startAt - 1) == '_') ) )
519             --startAt;
520         return startAt;
521     }
522 
523     /** check startAt is at some character like:
524      * @code
525      *  SomeNameSpace::SomeClass
526      *                ^ here is a double colon
527      *  SomeObject->SomeMethod
528      *             ^ here is a pointer member access operator
529      * @endcode
530      */
IsOperatorEnd(int startAt,const wxString & line)531     static bool IsOperatorEnd(int startAt, const wxString& line)
532     {
533         return (   (startAt > 0)
534                 && ((size_t)startAt < line.Len())
535                 && (   (   (line.GetChar(startAt) == '>')
536                         && (line.GetChar(startAt - 1) == '-') )
537                     || (   (line.GetChar(startAt) == ':')
538                         && (line.GetChar(startAt - 1) == ':') ) ) );
539     }
IsOperatorPointer(int startAt,const wxString & line)540     static bool IsOperatorPointer(int startAt, const wxString& line)
541     {
542         return (   (startAt > 0)
543             && ((size_t)startAt < line.Len())
544             && (   (   (line.GetChar(startAt) == '>')
545                     && (line.GetChar(startAt - 1) == '-') )));
546     }
547 
548     /** check if startAt point to "->" or "::" operator */
549      // FIXME (ollydbg#1#): should be startAt+1 < line.Len()?
IsOperatorBegin(int startAt,const wxString & line)550     static bool IsOperatorBegin(int startAt, const wxString& line)
551     {
552         return (   (startAt >= 0)
553                 && ((size_t)startAt < line.Len())
554                 && (   (   (line.GetChar(startAt ) == '-')
555                         && (line.GetChar(startAt + 1) == '>') )
556                     || (   (line.GetChar(startAt) == ':')
557                         && (line.GetChar(startAt + 1) == ':') ) ) );
558     }
559 
560     /** check whether line[startAt] is a dot character */
IsOperatorDot(int startAt,const wxString & line)561     static bool IsOperatorDot(int startAt, const wxString& line)
562     {
563         return (   (startAt >= 0)
564                 && ((size_t)startAt < line.Len())
565                 && (line.GetChar(startAt) == '.') );
566     }
567 
568     /** move to the char before whitespace and tabs, e.g.
569      * @code
570      *  SomeNameSpace       ::  SomeClass
571      *              ^end   ^begin
572      * note if there some spaces in the beginning like below
573      *      "       f::"
574      *     ^end    ^begin
575      * @endcode
576      * the returned index is -1.
577      * @return the cursor after the operation
578      */
BeforeWhitespace(int startAt,const wxString & line)579     static int BeforeWhitespace(int startAt, const wxString& line)
580     {
581         while (   (startAt >= 0)
582                && ((size_t)startAt < line.Len())
583                && (   (line.GetChar(startAt) == ' ')
584                    || (line.GetChar(startAt) == '\t') ) )
585             --startAt;
586         return startAt;
587     }
588 
589     /** search from left to right, move the cursor to the first character after the space
590      * @code
591      *  "       ::   f"
592      *   ^begin ^end
593      * @endcode
594      * @param[in] startAt the begin of the cursor
595      * @param[in] line the string buffer
596      * @return the location of the cursor
597      */
AfterWhitespace(int startAt,const wxString & line)598     static int AfterWhitespace(int startAt, const wxString& line)
599     {
600         if (startAt < 0)
601             startAt = 0;
602         while (   ((size_t)startAt < line.Len())
603                && (   (line.GetChar(startAt) == ' ')
604                    || (line.GetChar(startAt) == '\t') ) )
605             ++startAt;
606         return startAt;
607     }
608 
609     /** Test whether the current character is a '(' or '['
610      * @param startAt the current cursor on the buffer
611      * @return true if test is OK
612      */
IsOpeningBracket(int startAt,const wxString & line)613     static bool IsOpeningBracket(int startAt, const wxString& line)
614     {
615         return (   ((size_t)startAt < line.Len())
616                 && (   (line.GetChar(startAt) == '(')
617                     || (line.GetChar(startAt) == '[') ) );
618     }
619 
620     /** check the current char (line[startAt]) is either ')' or ']'  */
IsClosingBracket(int startAt,const wxString & line)621     static bool IsClosingBracket(int startAt, const wxString& line)
622     {
623         return (   (startAt >= 0)
624                 && (   (line.GetChar(startAt) == ')')
625                     || (line.GetChar(startAt) == ']') ) );
626     }
627 
628 protected:
629 
630 private:
631     // Helper utilities called only by GenerateResultSet!
632     // No critical section needed! All functions that call these functions,
633     // should already entered a critical section.
634 
635     /** @brief collect child tokens of the specified token, the specified token must be unnamed.
636      *
637      * used for GenerateResultSet() function
638      * @param tree TokenTree pointer
639      * @param parent we need to collect the children of this token
640      * @param result collected tokens
641      * @return bool true if parent is an unnamed class or enum
642      */
AddChildrenOfUnnamed(TokenTree * tree,const Token * parent,TokenIdxSet & result)643     bool AddChildrenOfUnnamed(TokenTree* tree, const Token* parent, TokenIdxSet& result)
644     {
645         if (  ( (parent->m_TokenKind & (tkClass | tkEnum)) != 0 )
646             && parent->m_IsAnonymous == true )
647         {
648             // add all its children
649             for (TokenIdxSet::const_iterator it = parent->m_Children.begin();
650                                              it != parent->m_Children.end(); ++it)
651             {
652                 Token* tokenChild = tree->at(*it);
653                 if (    tokenChild
654                     && (parent->m_TokenKind == tkClass || tokenChild->m_Scope != tsPrivate) )
655                 {
656                     // NOTE: recurse (eg: class A contains struct contains union or enum)
657                     if ( !AddChildrenOfUnnamed(tree, tokenChild, result) )
658                     {
659                         result.insert(*it);
660                         AddChildrenOfEnum(tree, tokenChild, result);
661                     }
662                 }
663             }
664             return true;
665         }
666         return false;
667     }
668 
AddChildrenOfEnum(TokenTree * tree,const Token * parent,TokenIdxSet & result)669     bool AddChildrenOfEnum(TokenTree* tree, const Token* parent, TokenIdxSet& result)
670     {
671         if (parent->m_TokenKind == tkEnum)
672         {
673             // add all its children
674             for (TokenIdxSet::const_iterator it = parent->m_Children.begin();
675                                              it != parent->m_Children.end(); ++it)
676             {
677                 Token* tokenChild = tree->at(*it);
678                 if (tokenChild && tokenChild->m_Scope != tsPrivate)
679                     result.insert(*it);
680             }
681 
682             return true;
683         }
684         return false;
685     }
686 
687     /** @brief check to see if the token is an unnamed class or enum under the parent token
688      *
689      * This function will internally recursive call itself.
690      * @param tree pointer to the TokenTree
691      * @param targetIdx the checked token index
692      * @param parentIdx the search scope
693      * @return bool true if success
694      */
IsChildOfUnnamedOrEnum(TokenTree * tree,const int targetIdx,const int parentIdx)695     bool IsChildOfUnnamedOrEnum(TokenTree* tree, const int targetIdx, const int parentIdx)
696     {
697         if (targetIdx == parentIdx)
698             return true;
699         if (parentIdx == -1)
700             return false;
701 
702         Token* parent = tree->at(parentIdx);
703         if (parent && (parent->m_TokenKind & tkClass))
704         {
705             // loop all children of the parent token
706             for (TokenIdxSet::const_iterator it = parent->m_Children.begin();
707                                              it != parent->m_Children.end(); ++it)
708             {
709                 Token* token = tree->at(*it);
710                 // an unnamed class is much similar like the enum
711                 if (token && (((token->m_TokenKind & tkClass)
712                                 && (token->m_IsAnonymous == true))
713                              || (token->m_TokenKind & tkEnum)))
714                 {
715                     // if target token matches on child, we can return success
716                     // other wise, we try to see the target token matches child's child.
717                     if ((targetIdx == (*it)) || IsChildOfUnnamedOrEnum(tree, targetIdx, (*it)))
718                         return true;
719                 }
720             }
721         }
722         return false;
723     }
724 
725 
726     /**  loop on the input Token index set (source), add all its public constructors to output Token index set (dest) */
727     void AddConstructors(TokenTree *tree, const TokenIdxSet& source, TokenIdxSet& dest);
728 
729     // for GenerateResultSet()
MatchText(const wxString & text,const wxString & target,bool caseSens,bool isPrefix)730     bool MatchText(const wxString& text, const wxString& target, bool caseSens, bool isPrefix)
731     {
732         if (isPrefix && target.IsEmpty())
733             return true;
734         if (!isPrefix)
735             return text.CompareTo(target.wx_str(), caseSens ? wxString::exact : wxString::ignoreCase) == 0;
736         // isPrefix == true
737         if (caseSens)
738             return text.StartsWith(target);
739         return text.Upper().StartsWith(target.Upper());
740     }
741 
742     // for GenerateResultSet()
MatchType(TokenKind kind,short int kindMask)743     bool MatchType(TokenKind kind, short int kindMask)
744     {
745         return kind & kindMask;
746     }
747 
748 private:
749     ParserComponent              m_LastComponent;
750     std::map<wxString, wxString> m_TemplateMap;
751 };
752 
753 #endif // NATIVEPARSERBASE_H
754