Hi,
This code has had, and still has some problems with CC, more specifically with the 'find declaration' :
#include <iostream>
class ITest
{
public:
virtual int Method1(int Arg) = 0;
};
class Test : public ITest
{
public:
int Method1(int Arg);
};
int Test::Method1(int Arg)
{
return Arg;
}
int main()
{
Test Hello;
std::cout << Hello.Method1(5);
return 0;
}
Scenario :
1) right click Method1 in the call 'Hello.Method1(5)' and choose "find implementation' --> works nicely :-)
2) right click Method1 in the call 'Hello.Method1(5)' and choose "find declaration' --> gives me a choice :
* the ITest declaration
* the Test declaration
I think since the parser should now that Hello is a Test variable, it should not allow me any choice, and automatically select the Test declaration one.
Is this something that can be fixed with the improved CC, or are we still missing something in our parsing/tokens list ?
Dear killerbot:
I dont think it is easy to do this.
For current parser.It will parse your test codes as this.
ITest
|- Method1
Test
|-Method1
And for a faster seach,the parser just get the matched items from the tokenstree.so you can two items from your test codes.
It make no sense if you try to solve the expression,since Test is inherited from ITest.you still will get two items.One in ITest,the other in Test.
killerbot:if you get any idea about this.share it here,please. :D
I think it will be more harder for parse these codes:
ITest* pHello = new Test();
Even the codecompletion can not work correctly,not mention to others.
BTW:it is amazing that I can write so much English now. :lol: :lol: :lol:
Cool!!! That's something I was waiting for a while now... :D
The other thing is to parse #ifdef statements and parse only the relevant code, but this one I know is a though one... ;-)
Ok, I will help if I have time.
By the way, these days, Loaden has implementing a mechanism to handle #if #ifdef like statement. He has release his code in
http://topic.csdn.net/u/20100412/21/b39c50b9-caeb-406f-a12e-023e088c78c9.html It is a Chinese programming site.
He has not finished it yet, because he has failed parsing the statement like below:
#if (2 - 1) + !((3 - 2) ^ 1)
Resolving the expression is not quite easy.
Doing "find implementation" is some thing much like to the autoCompletion.
For example:
When
, you would like to find the implementation of Reset().
This is just like doing the autoCompletion when you are entering, the vertical slash stands for the caret position.
The only difference is: Doing autoCompletion will list all the members with the prefix string "Reset", so there will be a list like:
Reset()
ResetXXX
ResetYYYY
.....
But doing "find implementation" will only do a full match of the "Reset", and only the function members will be matched.
@mac
Searching for the whole object as suggested makes this impossible. I can live very well with being presented a lot of "Reset" functions (it's the same for me with methods called "Init" and "ReInit"). I benefit from seeing all matches and would disagree if I see only one or less in the end.
Not fully understand these sentence. Does it means all the function in the class inheritance hierarchy should be displayed. I just agree with daniloz that all the other functions should be removed from the list.
@Ceniza (http://forums.codeblocks.org/index.php?action=profile;u=307)
firstly, thanks for the hint, the calculation of expression value in your CCPP code is still a bit hard for me, so you can see, in CC_BRANCH, we still use another way. (CC_branch has a way to calculate the #if XXX kind of conditional preprocessor value now).
I have some time to test your CCPP project. I'm using it under MinGW.
To build the lib, we need to do a modification in the file:
include\stdstring.h
Under Windows, the function sprintf is not under std namespace, instead, you need to add the #include <cstdio>
/**
\brief Creates a new STDString from an \c int value.
\param value Value to convert.
\return New STDString containing the string representation of
\p value.
*/
static STDString fromInt(int value) { char buffer[24]; std::sprintf(buffer, "%d", value); return STDString(buffer); }
Also, I have find a bug, When I'm running your test-debug target, I set the argument like this:
../../tests/file_line.cpp
So, the file_line.cpp will be parsed.
Here is the log output:
const char * fGetFILE ( ) {
return "bwehehe.h" ;
}
int fGetLINE ( ) {
return 58 ;
}
# define getLINE ( ) 201 int main ( ) {
int line0 = 206 ;
int line1 = getLINE ( ) ;
const char * file1 = "src/test/../../tests/file_line.cpp" ;
int line2 = fGetLINE ( ) ;
const char * file2 = fGetFILE ( ) ;
const char * today = "Jul 04 2010" ;
const char * now = "20:52:31" ;
int cpp = 199711L ;
}
Process returned 0 (0x0) execution time : 0.047 s
Press any key to continue.
See the log :
int line1 = getLINE ( ) ;
But in the file_line.cpp, the getLine() is defined by a macro.
file_line.cpp
#line 200
#include "file_line.h"
#define getLINE() __LINE__
int main()
{
#if __LINE__ == 205
int line0 = __LINE__;
#endif
int line1 = getLINE();
const char *file1 = getFILE();
int line2 = fGetLINE();
const char *file2 = fGetFILE();
const char *today = __DATE__;
const char *now = __TIME__;
int cpp = __cplusplus;
}
So, it should output the current line number instead of getLINE().
BTW: it seems the CCPP project was currently develop freeze, would like to improve it or you just abandon it?
Thanks.
@killerbot and all.
See this function:
void CodeCompletion::OnValueTooltip(CodeBlocksEvent& event)
{
event.Skip();
if (IsAttached() && m_InitDone)
{
if (!Manager::Get()->GetConfigManager(_T("code_completion"))->ReadBool(_T("eval_tooltip"), true))
return;
EditorBase* base = event.GetEditor();
cbEditor* ed = base && base->IsBuiltinEditor() ? static_cast<cbEditor*>(base) : 0;
if (!ed || ed->IsContextMenuOpened())
return;
if (ed->GetControl()->CallTipActive())
ed->GetControl()->CallTipCancel();
// Manager::Get()->GetLogManager()->DebugLog(F(_T("CodeCompletion::OnValueTooltip: %p"), ed));
/* NOTE: The following 2 lines of codes can fix [Bug #11785].
* The solution may not the best one and it requires the editor
* to have the focus (even if C::B has the focus) in order to pop-up the tooltip. */
if (wxWindow::FindFocus() != static_cast<wxWindow*>(ed->GetControl()))
return;
// ignore comments, strings, preprocesor, etc
int style = event.GetInt();
if ( (style != wxSCI_C_DEFAULT)
&& (style != wxSCI_C_OPERATOR)
&& (style != wxSCI_C_IDENTIFIER) )
return;
int pos = ed->GetControl()->PositionFromPointClose(event.GetX(), event.GetY());
if (pos < 0 || pos >= ed->GetControl()->GetLength())
return;
Parser* parser = m_NativeParser.GetParserPtr();
if (parser)
{
TokenIdxSet result;
int endOfWord = ed->GetControl()->WordEndPosition(pos, true);
if (m_NativeParser.MarkItemsByAI(result, true, true, true, endOfWord))
{
wxString msg;
int count = 0;
for (TokenIdxSet::iterator it = result.begin(); it != result.end(); ++it)
{
Token* token = parser->GetTokens()->at(*it);
if (token)
{
msg << token->DisplayName() << _T("\n");
++count;
if (count > 32) // allow max 32 matches (else something is definitely wrong)
{
msg.Clear();
break;
}
}
}
if (!msg.IsEmpty())
{
msg.RemoveLast(); // last \n
ed->GetControl()->CallTipShow(pos, msg);
// Manager::Get()->GetLogManager()->DebugLog(F(msg));
}
}
}
}
}
and the function call:
m_NativeParser.MarkItemsByAI(result, true, true, true, endOfWord)
after this function call, the result will contains the "Token" you suggests. :D, because MarkItemsByAI do consider the "scopes" of the current word.
so it looks we are ably to solve the problem, are you taking this change into account in your CC refactorings ?
partially Yes.
Your problem about "virtual function" still has some bug. But I have create another sample code, and can show how it works:
int Method1(int arg);
class Other
{
public:
int Method1(int Arg);
};
class ITest
{
public:
virtual int Method1(int Arg) = 0;
};
class Test : public ITest
{
public:
int Method1(int Arg);
};
int Test::Method1(int Arg)
{
return Arg;
}
int main()
{
Test Hello;
std::cout << Hello.Method1(5);
return 0;
}
In this example, I add Two "function" named "Method1". Now, if I right click on the "Hello.Method1(5)", and select "goto declaration", you will still show the:
* the ITest declaration
* the Test declaration
But pay attention:
We don't have the "global function Method1" and the "Other::Method1" included.
Here is the modified code:
void CodeCompletion::OnGotoDeclaration(wxCommandEvent& event)
{
EditorManager* edMan = Manager::Get()->GetEditorManager();
// killerbot : the menu and right click pop up menu ensured there is a name under the cursor
// BUT it seems the shortcut keys are not disabled although there menu counter part is
// ---> so check is needed and gracefully shut up when the Name under the cursor is empty
bool MoveOn = false;
wxString NameUnderCursor;
bool IsInclude = false;
if (EditorHasNameUnderCursor(NameUnderCursor, IsInclude))
{
if (!IsInclude)
{ // alright move on
MoveOn = true;
}
}
if (!MoveOn)
return;
Parser* parser = m_NativeParser.GetParserPtr();
if (!parser)
return;
// prepare a boolean filter for declaration/implementation
bool isDecl = event.GetId() == idGotoDeclaration || event.GetId() == idMenuGotoDeclaration;
bool isImpl = event.GetId() == idGotoImplementation || event.GetId() == idMenuGotoImplementation;
// get the matching set
Token* token = 0;
TokenIdxSet result;
//parser->GetTokens()->FindMatches(NameUnderCursor, result, true, false);
//Added by Asmwarrior
// ignore comments, strings, preprocesor, etc
int style = event.GetInt();
if ( (style != wxSCI_C_DEFAULT)
&& (style != wxSCI_C_OPERATOR)
&& (style != wxSCI_C_IDENTIFIER) )
return;
cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
if (!ed)
return;
const int pos = ed->GetControl()->GetCurrentPos();
int endOfWord = ed->GetControl()->WordEndPosition(pos, true);
m_NativeParser.MarkItemsByAI(result, true, true, true, endOfWord);
//cbMessageBox(wxString::Format(_("TEST: %s %d"), NameUnderCursor.c_str(), result.size()), _("Warning"), wxICON_WARNING);
// one match
if (result.size() == 1)
{
Token* sel = parser->GetTokens()->at(*(result.begin()));
if ((isImpl && !sel->GetImplFilename().IsEmpty()) ||
(isDecl && !sel->GetFilename().IsEmpty()))
{
token = sel;
}
}
// if more than one match, display a selection dialog
else if (result.size() > 1)
{
// TODO: we could parse the line containing the text so
// if namespaces were included, we could limit the results (and be more accurate)
wxArrayString selections;
wxArrayInt int_selections;
for (TokenIdxSet::iterator it = result.begin(); it != result.end(); ++it)
{
Token* sel = parser->GetTokens()->at(*it);
if (sel)
{
// only match tokens that have filename info
if ( (isImpl && !sel->GetImplFilename().IsEmpty())
|| (isDecl && !sel->GetFilename().IsEmpty()) )
{
selections.Add(sel->DisplayName());
int_selections.Add(*it);
}
}
}
if (selections.GetCount() > 1)
{
int sel = wxGetSingleChoiceIndex(_("Please make a selection:"), _("Multiple matches"), selections);
if (sel == wxNOT_FOUND)
return;
token = parser->GetTokens()->at(int_selections[sel]);
}
else if (selections.GetCount() == 1)
{ // number of selections can be < result.size() due to the if tests, so in case we fall
// back on 1 entry no need to show a selection
token = parser->GetTokens()->at(int_selections[0]);
}
}
// do we have a token?
if (token)
{
if (isImpl)
{
if (cbEditor* ed = edMan->Open(token->GetImplFilename()))
{
ed->GotoLine(token->m_ImplLine - 1);
}
else
{
cbMessageBox(wxString::Format(_("Implementation not found: %s"), NameUnderCursor.c_str()), _("Warning"), wxICON_WARNING);
}
}
else
{
if (cbEditor* ed = edMan->Open(token->GetFilename()))
{
ed->GotoLine(token->m_Line - 1);
}
else
{
cbMessageBox(wxString::Format(_("Declaration not found: %s"), NameUnderCursor.c_str()), _("Warning"), wxICON_WARNING);
}
}
}
else
{
cbMessageBox(wxString::Format(_("Not found: %s"), NameUnderCursor.c_str()), _("Warning"), wxICON_WARNING);
}
}
To your problem:
We should loop of the result TokenIdxSet, then strip out the redundant virtual function declarations, but sometimes as Morten said, this is not a good idea. :D