News:

Accounts with zero posts and zero activity during the last months will be deleted periodically to fight SPAM!

Main Menu

Patch 3407: correctly parse c++98 enums

Started by oBFusCATed, January 20, 2013, 11:02:31 PM

Previous topic - Next topic

ollydbg

Quote from: p2rkw on January 21, 2013, 10:16:14 PM
How about this:
Index: src/plugins/codecompletion/parser/parserthread.cpp
===================================================================
--- src/plugins/codecompletion/parser/parserthread.cpp (wersja 8785)
+++ src/plugins/codecompletion/parser/parserthread.cpp (kopia robocza)
@@ -2263,10 +2282,13 @@
     // enums have the following rough definition:
     // enum [xxx] { type1 name1 [= 1][, [type2 name2 [= 2]]] };
     bool isUnnamed = false;
+    bool isEnumClass = false;
     int lineNr = m_Tokenizer.GetLineNumber();
     wxString token = m_Tokenizer.GetToken();
-    if (token == ParserConsts::kw_class)
+    if (token == ParserConsts::kw_class){
         token = m_Tokenizer.GetToken();
+        isEnumClass = true;
+    }
     if (token.IsEmpty())
         return;

@@ -2357,7 +2379,8 @@
             {
                 Token* lastParent = m_LastParent;
                 m_LastParent = newEnum;
-                DoAddToken(tkEnumerator, token, m_Tokenizer.GetLineNumber());
+                Token* enumerator = DoAddToken(tkEnumerator, token, m_Tokenizer.GetLineNumber());
+                enumerator->m_Scope = isEnumClass ? tsPrivate : tsPublic;
                 m_LastParent = lastParent;
             }
             if (peek==ParserConsts::colon)
Index: src/plugins/codecompletion/nativeparser_base.h
===================================================================
--- src/plugins/codecompletion/nativeparser_base.h (wersja 8785)
+++ src/plugins/codecompletion/nativeparser_base.h (kopia robocza)
@@ -396,14 +396,16 @@
     // for GenerateResultSet()
     bool AddChildrenOfUnnamed(TokenTree* tree, const Token* parent, TokenIdxSet& result)
     {
-        if (parent->m_TokenKind == tkClass && parent->m_Name.StartsWith(g_UnnamedSymbol))
+        if (((parent->m_TokenKind & (tkClass | tkEnum)) != 0)
+            && parent->m_Name.StartsWith(g_UnnamedSymbol))
         {
             // add all its children
             for (TokenIdxSet::const_iterator it = parent->m_Children.begin();
                                              it != parent->m_Children.end(); ++it)
             {
                 Token* tokenChild = tree->at(*it);
-                if (tokenChild)
+                if (tokenChild &&
+                    (parent->m_TokenKind == tkClass || tokenChild->m_Scope != tsPrivate))
                     result.insert(*it);
             }

@@ -411,7 +413,25 @@
         }
         return false;
     }
+   
+    bool AddChildrenOfEnum(TokenTree* tree, const Token* parent, TokenIdxSet& result)
+    {
+        if (parent->m_TokenKind == tkEnum)
+        {
+            // add all its children
+            for (TokenIdxSet::const_iterator it = parent->m_Children.begin();
+                                             it != parent->m_Children.end(); ++it)
+            {
+                Token* tokenChild = tree->at(*it);
+                if (tokenChild && tokenChild->m_Scope != tsPrivate)
+                    result.insert(*it);
+            }

+            return true;
+        }
+        return false;
+    }
+
     // for GenerateResultSet()
     bool MatchText(const wxString& text, const wxString& target, bool caseSens, bool isPrefix)
     {
Index: src/plugins/codecompletion/nativeparser_base.cpp
===================================================================
--- src/plugins/codecompletion/nativeparser_base.cpp (wersja 8785)
+++ src/plugins/codecompletion/nativeparser_base.cpp (kopia robocza)
@@ -1318,7 +1318,11 @@
                 if (!token)
                     continue;
                 if ( !AddChildrenOfUnnamed(tree, token, result) )
+                {
                     result.insert(*it);
+                    AddChildrenOfEnum(tree, token, result);
+                }
+                   
             }

             tree->RecalcInheritanceChain(parent);
@@ -1334,7 +1338,10 @@
                     if (!token)
                         continue;
                     if ( !AddChildrenOfUnnamed(tree, token, result) )
+                    {
                         result.insert(*it2);
+                        AddChildrenOfEnum(tree, token, result);
+                    }
                 }
             }
         }



Here is my test result of this patch:
Using the test file: trunk\src\plugins\codecompletion\testing\structs_typedefs_enums.cpp (rev 8811)


//    SEnum:: OK
//    SEnum::ELocal:: OK
//    SEnum::eEnumClassLocal:: Fail

If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

ollydbg

Quote from: ollydbg on January 22, 2013, 02:25:38 PM
//    SEnum::eEnumClassLocal:: Fail
It looks like this is the expect behavior. I see the code:

    while (IS_ALIVE)
    {
        // process enumerators
        token = m_Tokenizer.GetToken();
        wxString peek = m_Tokenizer.PeekToken();
        if (token.IsEmpty() || peek.IsEmpty())
            return; //eof
        if (token==ParserConsts::clbrace && level == m_Tokenizer.GetNestingLevel())
            break;
        // assignments (=xxx) are ignored by the tokenizer,
        // so we don't have to worry about them here ;)
        if (peek==ParserConsts::comma || peek==ParserConsts::clbrace || peek==ParserConsts::colon)
        {
            // this "if", avoids non-valid enumerators
            // like a comma (if no enumerators follow)
            if (   wxIsalpha(token.GetChar(0))
                || (token.GetChar(0) == ParserConsts::underscore_chr) )
            {
                Token* lastParent = m_LastParent;
                m_LastParent = newEnum;
                Token* enumerator = DoAddToken(tkEnumerator, token, m_Tokenizer.GetLineNumber());
                enumerator->m_Scope = isEnumClass ? tsPrivate : tsPublic;
                m_LastParent = lastParent;
            }
            if (peek==ParserConsts::colon)
            {
                // bit specifier (eg, xxx:1)
                // -> walk to , or }
                SkipToOneOfChars(ParserConsts::commaclbrace);
            }
        }
    }


Here:

enumerator->m_Scope = isEnumClass ? tsPrivate : tsPublic;


The added enumerator is "private".

But it looks like the private members are not added to codecompletion suggestion list.

    bool AddChildrenOfEnum(TokenTree* tree, const Token* parent, TokenIdxSet& result)
    {
        if (parent->m_TokenKind == tkEnum)
        {
            // add all its children
            for (TokenIdxSet::const_iterator it = parent->m_Children.begin();
                                             it != parent->m_Children.end(); ++it)
            {
                Token* tokenChild = tree->at(*it);
                if (tokenChild && tokenChild->m_Scope != tsPrivate)
                    result.insert(*it);
            }

            return true;
        }
        return false;
    }


Here, only members those are "Not private" are added to the result.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

p2rkw

@ollydbg:
replace
SEnum::eEnumClassLocal::
with
SEnum::EEnumClassLocal::

ollydbg

#18
Quote from: p2rkw on January 22, 2013, 02:47:22 PM
@ollydbg:
replace
SEnum::eEnumClassLocal::
with
SEnum::EEnumClassLocal::
Yes, I also see this typo, after change this, I see it list three members.
But I'm using the code:

   bool AddChildrenOfEnum(TokenTree* tree, const Token* parent, TokenIdxSet& result)
   {
       if (parent->m_TokenKind == tkEnum)
       {
           // add all its children
           for (TokenIdxSet::const_iterator it = parent->m_Children.begin();
                                            it != parent->m_Children.end(); ++it)
           {
               Token* tokenChild = tree->at(*it);
               if (tokenChild )//&& tokenChild->m_Scope != tsPrivate)
                   result.insert(*it);
           }

           return true;
       }
       return false;
   }


I will test your patch again.

EDIT: your patch works fine, all three tests were OK.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

MortenMacFly

Quote from: ollydbg on January 22, 2013, 02:50:52 PM
EDIT: your patch works fine, all three tests were OK.
Keep in mind that there are way more enums defined in this test file than only 3. These 3 commented cases are just for convenience (and because I was too lazy to type them all). But all enums should pass.
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: [url="https://www.codeblocks.org/docs/main_codeblocks_en.html"]https://www.codeblocks.org/docs/main_codeblocks_en.html[/url]
C::B FAQ: [url="https://wiki.codeblocks.org/index.php?title=FAQ"]https://wiki.codeblocks.org/index.php?title=FAQ[/url]

oBFusCATed

Any problems encountered? If no, I'll commit in the next couple of days.
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

ollydbg

Quote from: oBFusCATed on January 29, 2013, 10:33:42 PM
Any problems encountered? If no, I'll commit in the next couple of days.
I'm OK with this patch. All enum testes work fine

//    EGlobalCommented::
//    EGlobal::
//    EGlobalAssign::
//    EEnumClassGlobal::
//    SEnum::
//    SEnum::ELocal::
//    SEnum::EEnumClassLocal::

If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.