Hi, all, I personally agree with jaxon.
I have debug the code whole day
, and finally find that this is a bug in the code below:
bool NativeParser::ParseLocalBlock(cbEditor* ed, int caretPos)
{
if (!ed)
return false;
Parser* parser = FindParserFromEditor(ed);
if (!parser)
return false;
if (!parser->Done())
return false;
if (s_DebugSmartSense)
Manager::Get()->GetLogManager()->DebugLog(_T("Parse local block"));
int blockStart = FindCurrentFunctionStart(ed, 0, 0, caretPos);
if (blockStart != -1)
{
++blockStart; // skip {
int blockEnd = caretPos == -1 ? ed->GetControl()->GetCurrentPos() : caretPos;
if (blockEnd < 0 || blockEnd > ed->GetControl()->GetLength())
return false;
if (blockStart >= blockEnd)
blockStart = blockEnd;
wxString buffer = ed->GetControl()->GetTextRange(blockStart, blockEnd);
buffer.Trim();
if (!buffer.IsEmpty() && !parser->ParseBuffer(buffer, false, false, true))
{
if (s_DebugSmartSense)
Manager::Get()->GetLogManager()->DebugLog(_T("ERROR parsing block:\n") + buffer);
}
else
{
if (s_DebugSmartSense)
{
#if wxCHECK_VERSION(2, 9, 0)
Manager::Get()->GetLogManager()->DebugLog(F(_T("Block:\n%s"), buffer.wx_str()));
#else
Manager::Get()->GetLogManager()->DebugLog(F(_T("Block:\n%s"), buffer.c_str()));
#endif
Manager::Get()->GetLogManager()->DebugLog(_T("Local tokens:"));
for (size_t i = 0; i < parser->GetTokens()->size(); ++i)
{
Token* t = parser->GetTokens()->at(i);
if (t && t->m_IsTemp)
Manager::Get()->GetLogManager()->DebugLog(_T(" + ") + t->DisplayName());
}
}
return true;
}
}
else
{
if (s_DebugSmartSense)
Manager::Get()->GetLogManager()->DebugLog(_T("Could not determine current block start..."));
}
return false;
}
for example, at this time( see my example code), the LocalBlock is the function body of main to the current caret:
int variableA;
variableA = 1;
After parsing the buffer, the parser mistakenly added the local variableA to the global namespace.. I think the correct way should be :
set the the local variableA's parent as Token "main" (not the global namespace).
Also, there is another issue in these code:
nativeparser.cpp line 1597:
// always add scope -1 (i.e. global namespace)
search_scope->insert(-1);
// find all other matches
std::queue<ParserComponent> components;
BreakUpComponents(parser, actual, components);
m_LastAISearchWasGlobal = components.size() <= 1;
if (!components.empty())
m_LastAIGlobalSearch = components.front().component;
// actually find all matches in selected namespaces
for (TokenIdxSet::iterator it = search_scope->begin(); it != search_scope->end(); ++it)
{
if (s_DebugSmartSense)
{
Token* scopeToken = tree->at(*it);
#if wxCHECK_VERSION(2, 9, 0)
Manager::Get()->GetLogManager()->DebugLog(F(_T("Parent scope: '%s' (%d)"), scopeToken ? scopeToken->m_Name.wx_str() : _T("Global namespace"), *it));
#else
Manager::Get()->GetLogManager()->DebugLog(F(_T("Parent scope: '%s' (%d)"), scopeToken ? scopeToken->m_Name.c_str() : _T("Global namespace"), *it));
#endif
}
FindAIMatches(parser, components, result, *it, noPartialMatch, caseSensitive, true, 0xffff, search_scope);
}
cached_editor = editor;
if (result.size() || (m_EditorEndWord - m_EditorStartWord))
cached_editor_start_word = m_EditorStartWord;
cached_search = actual;
cached_results_count = result.size();
return result.size();
}
In the code above, the "global namespace" is added by default. I don't think is is necessary, I personally use this method
1, check the result.size() at the end of AI()
2, if the result.size is zero, we should add the global namespace, and do the FindAIMatches() in the global namespace.
In this way, if the token is already found in the local context or matches as a class members, we don't need to use global namespace search.
By the way, the AI() function( and the related functions to do the show the tips) code is really hard to read!!!, that's irradiated me so much!!!
, I think we should refactor it, especially change the variable names.