Menu

#793 Code completion stop working with enum defined inside function body

Undefined
open
nobody
Bug_Report
2019-02-24
2019-01-26
No

Some times codecompletion stops working, see the video on the link and the attached project.
Looks like the issue only happens when the struct

    struct _READ_DATA {
        uint32_t addr;
        uint32_t size;
    } read_data, *pread_data;

is declared inside the function, if I move the declaration outside the function the issue doesn't happen.
It also seems to only affect autocompletion inside the function there the previous struct was declared,
if I move to other function autocompletion is working.
Reparsing the project makes autocompletion work again but read_data and pread_data are never shown in the list.

https://drive.google.com/open?id=1hNgStc4F1fWPXsv8k0hvWhmanfPaiuyM

I'm running C::B svn build rev 11558, SDK version 1.37.0, scintilla version 3.7.5, wx3.0.4 on Debian testing 64bits.

1 Attachments

Discussion

  • ollydbg

    ollydbg - 2019-01-27
    • labels: --> CodeCompletion
    • Type: Undefined --> Bug_Report
     
  • ollydbg

    ollydbg - 2019-01-27

    Thanks for the report.
    I will take some time to debug it.
    BTW: The screen shot application is quite good. Can you tell me which one do you use, thanks.

     
  • ollydbg

    ollydbg - 2019-01-27

    I debugged a while, for simplicity, I use such testing code:

    struct OUT {
        uint32_t addr;
        uint32_t size;
    };
    
    int main()
    {
        struct IN {
            uint32_t addr;
            uint32_t size;
        } read_data, *pread_data;
        int test_x, test_y;
    
        struct OUT read_data2;
        struct OUT *pread_data2;
    
        read_data.
    
        return 0;
    }
    

    When I hit the dot key after the " read_data", I see the call stack:

    [debug]>>>>>>cb_gdb:
    
    At D:\code\cb\cb_sf_git\clean-trunk-for-commit\src\plugins\codecompletion\nativeparser.cpp:1838
    
    [debug]> bt 30
    [debug]#0  NativeParser::ParseLocalBlock (this=0x72b38e0, searchData=0x28ec88, search_scope=std::set with 0 elements, caretPos=258) at D:\code\cb\cb_sf_git\clean-trunk-for-commit\src\plugins\codecompletion\nativeparser.cpp:1838
    [debug]#1  0x087b1f63 in NativeParser::MarkItemsByAI (this=0x72b38e0, searchData=0x28ec88, result=std::set with 0 elements, reallyUseAI=true, isPrefix=true, caseSensitive=true, caretPos=258) at D:\code\cb\cb_sf_git\clean-trunk-for-commit\src\plugins\codecompletion\nativeparser.cpp:841
    [debug]#2  0x087b272b in NativeParser::MarkItemsByAI (this=0x72b38e0, result=std::set with 0 elements, reallyUseAI=true, isPrefix=true, caseSensitive=true, caretPos=258) at D:\code\cb\cb_sf_git\clean-trunk-for-commit\src\plugins\codecompletion\nativeparser.cpp:881
    [debug]#3  0x0878d197 in CodeCompletion::DoCodeComplete (this=0x72b3888, caretPos=258, ed=0x10513398, tokens=std::vector of length 0, capacity 0, preprocessorOnly=false) at D:\code\cb\cb_sf_git\clean-trunk-for-commit\src\plugins\codecompletion\codecompletion.cpp:953
    [debug]#4  0x0878d08b in CodeCompletion::GetAutocompList (this=0x72b3888, isAuto=true, ed=0x10513398, tknStart=@0x28f55c: 258, tknEnd=@0x28f560: 258) at D:\code\cb\cb_sf_git\clean-trunk-for-commit\src\plugins\codecompletion\codecompletion.cpp:943
    [debug]#5  0x694b9e40 in CCManager::OnCompleteCode (this=0x104129d8, event=...) at D:\code\cb\cb_sf_git\clean-trunk-for-commit\src\sdk\ccmanager.cpp:528
    [debug]#6  0x6971481c in cbEventFunctor<CCManager, CodeBlocksEvent>::Call (this=0x1042bcd8, event=...) at D:\code\cb\cb_sf_git\clean-trunk-for-commit\src\include\cbfunctor.h:49
    [debug]#7  0x695384a1 in Manager::ProcessEvent (this=0x3d29668, event=...) at D:\code\cb\cb_sf_git\clean-trunk-for-commit\src\sdk\manager.cpp:260
    [debug]#8  0x694bd4a0 in CCManager::OnTimer (this=0x104129d8, event=...) at D:\code\cb\cb_sf_git\clean-trunk-for-commit\src\sdk\ccmanager.cpp:1161
    [debug]#9  0x66482d92 in wxAppConsoleBase::HandleEvent(wxEvtHandler*, void (wxEvtHandler::*)(wxEvent&), wxEvent&) const () from D:\code\wxWidgets-3.1.2\lib\gcc_dll\wxmsw312u_gcc_cb.dll
    [debug]#10 0x66483267 in wxAppConsoleBase::CallEventHandler(wxEvtHandler*, wxEventFunctor&, wxEvent&) const () from D:\code\wxWidgets-3.1.2\lib\gcc_dll\wxmsw312u_gcc_cb.dll
    [debug]#11 0x665d9bde in wxEvtHandler::ProcessEventIfMatchesId(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) () from D:\code\wxWidgets-3.1.2\lib\gcc_dll\wxmsw312u_gcc_cb.dll
    [debug]#12 0x665da135 in wxEvtHandler::SearchDynamicEventTable(wxEvent&) () from D:\code\wxWidgets-3.1.2\lib\gcc_dll\wxmsw312u_gcc_cb.dll
    [debug]#13 0x665da415 in wxEvtHandler::TryHereOnly(wxEvent&) () from D:\code\wxWidgets-3.1.2\lib\gcc_dll\wxmsw312u_gcc_cb.dll
    [debug]#14 0x665da49a in wxEvtHandler::ProcessEventLocally(wxEvent&) () from D:\code\wxWidgets-3.1.2\lib\gcc_dll\wxmsw312u_gcc_cb.dll
    [debug]#15 0x665da4f3 in wxEvtHandler::ProcessEvent(wxEvent&) () from D:\code\wxWidgets-3.1.2\lib\gcc_dll\wxmsw312u_gcc_cb.dll
    [debug]#16 0x665dc1c2 in wxEvtHandler::SafelyProcessEvent(wxEvent&) () from D:\code\wxWidgets-3.1.2\lib\gcc_dll\wxmsw312u_gcc_cb.dll
    [debug]#17 0x66547c2e in wxTimerImpl::SendEvent() () from D:\code\wxWidgets-3.1.2\lib\gcc_dll\wxmsw312u_gcc_cb.dll
    [debug]#18 0x665bc300 in wxTimerWndProc(HWND__*, unsigned int, unsigned int, long)@16 () from D:\code\wxWidgets-3.1.2\lib\gcc_dll\wxmsw312u_gcc_cb.dll
    [debug]#19 0x763a62fa in gapfnScSendMessage () from C:\windows\syswow64\user32.dll
    [debug]#20 0x00010a88 in ?? ()
    [debug]#21 0x763a6d3a in USER32!GetThreadDesktop () from C:\windows\syswow64\user32.dll
    [debug]#22 0x665bc260 in wxProcessTimer(wxMSWTimerImpl&) () from D:\code\wxWidgets-3.1.2\lib\gcc_dll\wxmsw312u_gcc_cb.dll
    [debug]#23 0x00000113 in ?? ()
    [debug]#24 0x00000256 in ?? ()
    [debug]#25 0x00000000 in ?? ()
    [debug]>>>>>>cb_gdb:
    
    > p buffer
    
    [debug]> p buffer
    [debug]$1 = L"\n    struct IN {\n\n\n} read_data, *pread_data;\n    int test_x, test_y;\n\n    struct OUT read_data2;\n    struct OUT *pread_data2;\n\n    read_data."
    [debug]>>>>>>cb_gdb:
    
    $1 = L"\n    struct IN {\n\n\n} read_data, *pread_data;\n    int test_x, test_y;\n\n    struct OUT read_data2;\n    struct OUT *pread_data2;\n\n    read_data."
    

    You see, the "struct IN" is simplified to the buffer, thus all the contents of the struct IN is lost.

    struct IN {\n\n\n} read_data, *pread_data;
    

    I think the function call m_Parser->ParseBuffer() will parse the simplified buffer.

    buffer.Trim();
    
    ParseBufferForUsingNamespace(buffer, search_scope, false);
    
    if (   !buffer.IsEmpty()
        && !m_Parser->ParseBuffer(buffer, false, false, true, searchData->file, m_LastFuncTokenIdx, initLine) )
    {
        if (s_DebugSmartSense)
            CCLogger::Get()->DebugLog(_T("ParseLocalBlock() ERROR parsing block:\n") + buffer);
    }
    

    So, the solution here is: we don't need such simplification of the buffer, right?

    The simplification is just try to remove the nested { xxx xxx xxx }.

     
  • Fabián Inostroza

    Seems like the issue is somewhere else, I've modified the code to not remove the struct definition

    Index: src/plugins/codecompletion/nativeparser.cpp
    ===================================================================
    --- src/plugins/codecompletion/nativeparser.cpp (revisión: 11575)
    +++ src/plugins/codecompletion/nativeparser.cpp (copia de trabajo)
    @@ -1789,9 +1789,12 @@
                 const int scopeStart = stc->BraceMatch(curPos);
                 if (scopeStart < blockStart)
                     break;
    -            buffer.Prepend(stc->GetTextRange(curPos, scanPos));
                 int startLn = stc->LineFromPosition(scopeStart);
    +            if (stc->GetLine(startLn).Find(_T("struct")) != wxNOT_FOUND) {
    +                continue;
    +            }
                 int endLn   = stc->LineFromPosition(curPos);
    +            buffer.Prepend(stc->GetTextRange(curPos, scanPos));
                 if (startLn < endLn) // maintain correct line numbers for parsed tokens
                     buffer.Prepend( wxString(wxT('\n'), endLn - startLn) );
                 scanPos = scopeStart + 1;
    

    It doesn't remove (or prevent not adding) the definition from buffer but it is still not suggesting read_data or pread_data.

     
  • ollydbg

    ollydbg - 2019-02-19

    OK, I apply your changes, and do some further test. I enabled the "Debug SmartSense" (set the s_DebugSmartSense variable to true), and have the following result in the C::B's Debug log.

    MarkItemsByAI_1()
    ParseUsingNamespace() Parse file scope for "using namespace"
    ParseFunctionArguments() Parse function arguments
    FindCurrentFunctionStart() Looking for tokens in 'E:\code\cb\sf-793\test\main.c'
    FindCurrentFunctionStart() Found 2 results
    FindCurrentFunctionStart() Current function: 'int main()' (at line 8)
    FindCurrentFunctionStart() Namespace='', proc='main' (returning 68)
    GenerateResultSet() search 'main', parent='Global namespace (id:0, type:(null)), isPrefix=0'
    ParseFunctionArguments() + Function match: main
    ParseLocalBlock() Parse local block
    FindCurrentFunctionStart() Looking for tokens in 'E:\code\cb\sf-793\test\main.c'
    FindCurrentFunctionStart() Found 2 results
    FindCurrentFunctionStart() Current function: 'int main()' (at line 8)
    FindCurrentFunctionStart() Namespace='', proc='main' (returning 68)
    ParseLocalBlock() Block:
    
        struct IN {
            uint32_t addr;
            uint32_t size;
        } read_data, *pread_data;
        int test_x, test_y;
    
        struct OUT read_data2;
        struct OUT *pread_data2;
    
        read_data.
    ParseLocalBlock() Local tokens:
     + int main::test_y (383); Parent = main (392)
     + OUT* main::pread_data2 (384); Parent = main (392)
     + OUT main::read_data2 (385); Parent = main (392)
     + int main::test_x (388); Parent = main (392)
     + uint32_t main::size (389); Parent = main (392)
     + uint32_t main::addr (390); Parent = main (392)
     + class IN {...} (391)
    AI() =========================================================
    AI() Doing AI for '    read_data.':
    FindCurrentFunctionStart() Looking for tokens in 'E:\code\cb\sf-793\test\main.c'
    FindCurrentFunctionStart() Found 3 results
    FindCurrentFunctionStart() Current function: 'class IN {...}' (at line 10)
    FindCurrentFunctionStart() Namespace='', proc='IN' (returning 70)
    GenerateResultSet() search 'IN', parent='Global namespace (id:0, type:(null)), isPrefix=0'
    AI() Adding search namespace: Global namespace
    BreakUpComponents() Breaking up '    read_data.'
    BreakUpComponents() Found component: 'read_data' (Class)
    BreakUpComponents() Adding component: 'read_data'.
    BreakUpComponents() Found component: '' (SearchText)
    BreakUpComponents() Adding component: ''.
    ResolveExpression() Search scope with 2 result:
    - Search scope: -1
    - Search scope: 391
    ResolveExpression() Looping 0 result.
    AI() AI leave, returned 0 results
    0 results
    

    It looks like the IN is not parsed correctly.

     
  • ollydbg

    ollydbg - 2019-02-19

    I think I find the reason. It is located in the in plugins\codecompletion\parser\parserthread.cpp, around the line 1584, in the function body Token* ParserThread::DoAddToken()

            newToken = new Token(newname, m_FileIdx, line, ++m_TokenTree->m_TokenTicketCount);
            TRACE(_T("DoAddToken() : Created token='%s', file_idx=%u, line=%d, ticket=%lu"), newname.wx_str(),
                  m_FileIdx, line, static_cast<unsigned long>(m_TokenTree->m_TokenTicketCount));
    
            Token* finalParent = localParent ? localParent : m_LastParent;
            if (kind == tkVariable && m_Options.parentIdxOfBuffer != -1)
                finalParent = m_TokenTree->at(m_Options.parentIdxOfBuffer);
    
            newToken->m_ParentIndex = finalParent ? finalParent->m_Index : -1;
            newToken->m_TokenKind   = kind;
            newToken->m_Scope       = m_LastScope;
            newToken->m_BaseArgs    = baseArgs;
    

    You look at the line:

    if (kind == tkVariable && m_Options.parentIdxOfBuffer != -1)
                finalParent = m_TokenTree->at(m_Options.parentIdxOfBuffer);
    

    When parsing the function body, it looks like "m_Options.parentIdxOfBuffer != -1" is true. So, the function Token is set as the finalParent of the new created Token.

    Thus:

    struct IN {
            uint32_t addr;
            uint32_t size;
            ...
    

    when we add the "addr" as a new Token, the parent should be the "struct IN", not the function "main".

    But with the above code, the function "main" is set as the parent, which is not correct.

    We can simply remove this condition check, but I'm not sure this cause any other issue.

     
  • ollydbg

    ollydbg - 2019-02-19

    With the above changes, It still get failed.

    MarkItemsByAI_1()
    ParseUsingNamespace() Parse file scope for "using namespace"
    ParseFunctionArguments() Parse function arguments
    FindCurrentFunctionStart() Looking for tokens in 'E:\code\cb\sf-793\test\main.c'
    FindCurrentFunctionStart() Found 2 results
    FindCurrentFunctionStart() Current function: 'int main()' (at line 8)
    FindCurrentFunctionStart() Namespace='', proc='main' (returning 68)
    GenerateResultSet() search 'main', parent='Global namespace (id:0, type:(null)), isPrefix=0'
    ParseFunctionArguments() + Function match: main
    ParseLocalBlock() Parse local block
    FindCurrentFunctionStart() Looking for tokens in 'E:\code\cb\sf-793\test\main.c'
    FindCurrentFunctionStart() Found 2 results
    FindCurrentFunctionStart() Current function: 'int main()' (at line 8)
    FindCurrentFunctionStart() Namespace='', proc='main' (returning 68)
    ParseLocalBlock() Block:
    
        struct IN {
            uint32_t addr;
            uint32_t size;
        } read_data, *pread_data;
        int test_x, test_y;
    
        struct OUT read_data2;
        struct OUT *pread_data2;
    
        read_data.
    ParseLocalBlock() Local tokens:
     + OUT* pread_data2 (383)
     + OUT read_data2 (384)
     + int test_y (385)
     + int test_x (386)
     + class IN {...} (387)
     + uint32_t IN::size (388); Parent = IN (387)
     + uint32_t IN::addr (389); Parent = IN (387)
    AI() =========================================================
    AI() Doing AI for '    read_data.':
    FindCurrentFunctionStart() Looking for tokens in 'E:\code\cb\sf-793\test\main.c'
    FindCurrentFunctionStart() Found 3 results
    FindCurrentFunctionStart() Current function: 'class IN {...}' (at line 10)
    FindCurrentFunctionStart() Namespace='', proc='IN' (returning 70)
    GenerateResultSet() search 'IN', parent='Global namespace (id:0, type:(null)), isPrefix=0'
    AI() Adding search namespace: Global namespace
    BreakUpComponents() Breaking up '    read_data.'
    BreakUpComponents() Found component: 'read_data' (Class)
    BreakUpComponents() Adding component: 'read_data'.
    BreakUpComponents() Found component: '' (SearchText)
    BreakUpComponents() Adding component: ''.
    ResolveExpression() Search scope with 2 result:
    - Search scope: -1
    - Search scope: 387
    ResolveExpression() Looping 0 result.
    AI() AI leave, returned 0 results
    0 results
    

    It looks like this is wrong?

    FindCurrentFunctionStart() Namespace='', proc='IN' (returning 70)
    

    Surely IN is not a scope containing the current carret (code completion) position.

     
  • ollydbg

    ollydbg - 2019-02-20
    • summary: Code completion stop working --> Code completion stop working with enum defined inside function body
     
  • ollydbg

    ollydbg - 2019-02-20

    If the two line

    if (kind == tkVariable && m_Options.parentIdxOfBuffer != -1)
                finalParent = m_TokenTree->at(m_Options.parentIdxOfBuffer);
    

    were removed, there are extra errors.
    This is cause by the member variable "m_LastParent". When we start parsing the function body of the main(), we should set the m_LastParent as the Token "main". While we enter into the enum IN's body, the m_LastParent should be Token "IN".

    Some sample code of handling this is like below:

                    Token*     lastParent = m_LastParent; // save status, will restore after DoParse()
                    TokenScope lastScope  = m_LastScope;
    
                    m_LastParent = newToken;
                    // default scope is: public for namespaces (actually no, but emulate it)
                    m_LastScope   = tsPublic;
    
                    DoParse();
    
                    m_LastParent = lastParent;
                    m_LastScope   = lastScope;
    
     

    Last edit: ollydbg 2019-02-20
  • ollydbg

    ollydbg - 2019-02-20

    Now, with this patch:

     src/plugins/codecompletion/parser/parserthread.cpp | 8 ++++++--
     1 file changed, 6 insertions(+), 2 deletions(-)
    
    diff --git a/src/plugins/codecompletion/parser/parserthread.cpp b/src/plugins/codecompletion/parser/parserthread.cpp
    index 57e3cddb..b1135acb 100644
    --- a/src/plugins/codecompletion/parser/parserthread.cpp
    +++ b/src/plugins/codecompletion/parser/parserthread.cpp
    @@ -517,6 +517,10 @@ bool ParserThread::Parse()
         bool result      = false;
         m_ParsingTypedef = false;
    
    +    // if we are parsing the function body, we set the m_LastParent as the function token
    +    if (m_Options.parentIdxOfBuffer != -1)
    +        m_LastParent = m_TokenTree->at(m_Options.parentIdxOfBuffer);
    +
         do
         {
             if (!m_TokenTree || !m_Tokenizer.IsOK())
    @@ -1581,8 +1585,8 @@ Token* ParserThread::DoAddToken(TokenKind       kind,
                   m_FileIdx, line, static_cast<unsigned long>(m_TokenTree->m_TokenTicketCount));
    
             Token* finalParent = localParent ? localParent : m_LastParent;
    -        if (kind == tkVariable && m_Options.parentIdxOfBuffer != -1)
    -            finalParent = m_TokenTree->at(m_Options.parentIdxOfBuffer);
    +//        if (kind == tkVariable && m_Options.parentIdxOfBuffer != -1)
    +//            finalParent = m_TokenTree->at(m_Options.parentIdxOfBuffer);
    
             newToken->m_ParentIndex = finalParent ? finalParent->m_Index : -1;
             newToken->m_TokenKind   = kind;
    

    I have such log:

    MarkItemsByAI_1()
    ParseUsingNamespace() Parse file scope for "using namespace"
    ParseFunctionArguments() Parse function arguments
    FindCurrentFunctionStart() Looking for tokens in 'E:\code\cb\sf-793\test\main.c'
    FindCurrentFunctionStart() Found 2 results
    FindCurrentFunctionStart() Current function: 'int main()' (at line 8)
    FindCurrentFunctionStart() Namespace='', proc='main' (returning 68)
    GenerateResultSet() search 'main', parent='Global namespace (id:0, type:(null)), isPrefix=0'
    ParseFunctionArguments() + Function match: main
    ParseLocalBlock() Parse local block
    FindCurrentFunctionStart() Looking for tokens in 'E:\code\cb\sf-793\test\main.c'
    FindCurrentFunctionStart() Found 2 results
    FindCurrentFunctionStart() Current function: 'int main()' (at line 8)
    FindCurrentFunctionStart() Namespace='', proc='main' (returning 68)
    ParseLocalBlock() Block:
    
        struct IN {
            uint32_t addr;
            uint32_t size;
        } read_data, *pread_data;
        int test_x, test_y;
    
        struct OUT read_data2;
        struct OUT *pread_data2;
    
        read_data.;
    ParseLocalBlock() Local tokens:
     + class IN {...} (387); Parent = main (386)
     + uint32_t main::IN::size (388); Parent = IN (387)
     + uint32_t main::IN::addr (389); Parent = IN (387)
     + int test_x (390)
     + int test_y (391)
     + OUT read_data2 (392)
     + OUT* pread_data2 (393)
    AI() =========================================================
    AI() Doing AI for '    read_data.':
    FindCurrentFunctionStart() Looking for tokens in 'E:\code\cb\sf-793\test\main.c'
    FindCurrentFunctionStart() Found 3 results
    FindCurrentFunctionStart() Current function: 'int main()' (at line 8)
    FindCurrentFunctionStart() Namespace='', proc='main' (returning 68)
    GenerateResultSet() search 'main', parent='Global namespace (id:0, type:(null)), isPrefix=0'
    AI() Adding search namespace: Global namespace
    BreakUpComponents() Breaking up '    read_data.'
    BreakUpComponents() Found component: 'read_data' (Class)
    BreakUpComponents() Adding component: 'read_data'.
    BreakUpComponents() Found component: '' (SearchText)
    BreakUpComponents() Adding component: ''.
    ResolveExpression() Search scope with 2 result:
    - Search scope: -1
    - Search scope: 386
    ResolveExpression() Looping 0 result.
    AI() AI leave, returned 0 results
    0 results
    

    But I'm not sure why the result is 0.
    I think search "read_data" under "386" (The main Token) should return at least one match.
    But it looks like "read_data" is not parsed correctly.

     
  • ollydbg

    ollydbg - 2019-02-20

    With the above changes, this sample code works OK

    struct OUT {
        uint32_t addr;
        uint32_t size;
    };
    
    int main()
    {
        struct IN {
            uint32_t addr;
            uint32_t size;
        };
        IN read_data;//, *pread_data;
        int test_x, test_y;
    
        struct OUT read_data2;
        struct OUT *pread_data2;
    
        read_data.;
    
        return 0;
    }
    

    But:

     + int test_x (390)
     + int test_y (391)
     + OUT read_data2 (392)
     + OUT* pread_data2 (393)
    

    They should have Parent as "main", but now they are empty parent(the global token), which is wrong.

     

    Last edit: ollydbg 2019-02-20
    • Fabián Inostroza

      Hi ollydbg, I haven't tried your changes yet but I found this comment on src/plugins/codecompletion/parser/parserthread.cpp:624

      // the only time we get to find a } is when recursively called by e.g. HandleClass
      // we have to return now...
      

      And that happens at the end of parsing the IN struct definition but the function doesn't return, is that behavior correct?

      As the method DoParse doesn't return upon finding the struct closing '}' it continues to parse the read_data and *pread_data declarations but it fails at line 1231 because m_Str is empty

       
    • Fabián Inostroza

      I just removed the if condition I mentioned before (I don't know if the condition or the comment is wrong), applied your changes and now it works better, this is the log

      ParseLocalBlock() Block:
      
          struct IN {
              uint32_t addr;
              uint32_t size;
          } read_data, *pread_data;
      
          int test_x, test_y;
      
          struct OUT read_data2;
          struct OUT *pread_data2;
      
          rea
      ParseLocalBlock() Local tokens:
       + int main::test_x (387); Parent = main (397)
       + OUT* main::pread_data2 (388); Parent = main (397)
       + int main::test_y (389); Parent = main (397)
       + IN* main::pread_data (391); Parent = main (397)
       + IN main::read_data (392); Parent = main (397)
       + uint32_t main::IN::size (393); Parent = IN (395)
       + uint32_t main::IN::addr (394); Parent = IN (395)
       + class IN {...} (395); Parent = main (397)
      AI() =========================================================
      AI() Doing AI for '    rea':
      FindCurrentFunctionStart() Looking for tokens in '/tmp/find_references/main.c'
      FindCurrentFunctionStart() Found 3 results
      FindCurrentFunctionStart() Current function: 'int main()' (at line 6)
      FindCurrentFunctionStart() Namespace='', proc='main' (returning 66)
      GenerateResultSet() search 'main', parent='Global namespace (id:0, type:(null)), isPrefix=0'
      AI() Adding search namespace: Global namespace
      BreakUpComponents() Breaking up '    rea'
      BreakUpComponents() Found component: 'rea' (SearchText)
      BreakUpComponents() Adding component: 'rea'.
      ResolveExpression() Search scope with 2 result:
      - Search scope: -1
      - Search scope: 397
      ResolveExpression() Looping 1 result.
      ResolvExpression() Match:'read_data(ID=392) : type='IN'
      AI() AI leave, returned 1 results
      1 results
      

      But as you can see it doesn't parse the read_data2 declaration.

      EDIT: I also applied your changes.

       

      Last edit: Fabián Inostroza 2019-02-24
  • ollydbg

    ollydbg - 2019-02-24

    Idealy, the body of the main should parse like below, I have add the comments there

                                     // DoParse Enter(we try to parse the body of main() function)
        struct IN                    // 
        {                            // DoParse Enter(we try to parse the body of IN)
            uint32_t addr;           // 
            uint32_t size;           // 
        }                            // DoParse Exit(exit the body of IN)
        read_data, *pread_data;      // 
                                     // 
        int test_x, test_y;          // 
                                     // 
        struct OUT read_data2;       // 
        struct OUT *pread_data2;     // 
                                     // 
        read_data.                   // DoParse Exit(we stop at the current caret)
    

    From your log message:

    ParseLocalBlock() Local tokens:
     + int main::test_x (387); Parent = main (397)
     + OUT* main::pread_data2 (388); Parent = main (397)
     + int main::test_y (389); Parent = main (397)
     + IN* main::pread_data (391); Parent = main (397)
     + IN main::read_data (392); Parent = main (397)
     + uint32_t main::IN::size (393); Parent = IN (395)
     + uint32_t main::IN::addr (394); Parent = IN (395)
     + class IN {...} (395); Parent = main (397)
    

    Yes, I think the variableread_data2 is lost, so there are some parsing issue.

     
  • ollydbg

    ollydbg - 2019-02-24

    I think this code is wrong here as you already found:

                case ParserConsts::clbrace_chr:
                    {
                        m_LastParent = 0L;
                        m_LastScope = tsUndefined;
                        m_Str.Clear();
                        // the only time we get to find a } is when recursively called by e.g. HandleClass
                        // we have to return now...
                        if (!m_Options.useBuffer || m_Options.bufferSkipBlocks)
                        {
                            m_Tokenizer.SetState(oldState); // This uses the top-level oldState (renamed shadowed versions below)
                            return;
                        }
                    }
                    break;
    

    Especially the if condition here:

    if (!m_Options.useBuffer || m_Options.bufferSkipBlocks)
    

    Even in parsing the function body, we may have recursive call of DoParse, so we should return here.

    I think the if condition used here are for simplicity, because a user may write some { } in side the function body, for simplicity, we don't handle those {} in the function body. This will make our parser failed to handle the struct defined inside the function body as your test code.

     
  • ollydbg

    ollydbg - 2019-02-24
            {
                // might be instantiation, see the following
                // e.g. struct HiddenStruct { int val; }; struct HiddenStruct yy;
                if (m_ParsingTypedef)
                {
                    m_Tokenizer.UngetToken();
                    break;
                }
                if (TokenExists(current, m_LastParent, tkClass))
                {
                    if (!TokenExists(next, m_LastParent, tkVariable))
                    {
                        wxString farnext;
    
                        m_Tokenizer.GetToken(); // go ahead of identifier
                        farnext = m_Tokenizer.PeekToken();
                        //  struct Point p1, p2;
                        //  current="Point", next="p1"
                        if (farnext == ParserConsts::semicolon || farnext == ParserConsts::comma)
                        {
                            while (m_Options.handleVars
                                   &&  (   farnext == ParserConsts::semicolon
                                        || farnext == ParserConsts::comma ))
                            {
                                if (m_Str.IsEmpty())
                                    m_Str = current;
                                DoAddToken(tkVariable, next, m_Tokenizer.GetLineNumber());
    
                                if (farnext == ParserConsts::comma)
                                {
                                    m_Tokenizer.GetToken(); // eat the ","
                                    next = m_Tokenizer.GetToken(); // next = "p2"
                                    farnext = m_Tokenizer.PeekToken(); // farnext = "," or the final ";"
                                    continue;
                                }
                                else // we meet a ";", so break the loop
                                {
                                    m_Str.Clear();
                                    break;
                                }
                            }
    
                            m_Tokenizer.GetToken(); // eat semi-colon
                            break;
                        }
                        else
                            m_Tokenizer.UngetToken(); // restore the identifier
                    }
                }
            }
            lastCurrent = current;
        }
    

    Now, for this code, there is a check:

    if (TokenExists(current, m_LastParent, tkClass))
    

    But in your test code, the "OUT" is not defined in the main, but in global scope, so it get failed.

    I simple solution is we can remove such check. I don't have much time to debug it.

    The interesting is "struct OUT * p;" such patter works.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.