Developer forums (C::B DEVELOPMENT STRICTLY!) > CodeCompletion redesign
Refectoring of the Token class
ollydbg:
Hi, guys, here is the draft, can you give some comments?
--- Code: ---// the base class
class Token
{
friend class TokenTree;
public:
Token(const wxString& name, unsigned int file, unsigned int line, size_t ticket);
virtual ~Token();
virtual wxString DisplayName() const {return wxEmptyString};
virtual TokenKind GetTokenKind() const {return tkUndefined};
virtual wxString GetTokenKindString() const {return wxEmptyString};
virtual wxString GetNamespace() const {return wxEmptyString};
wxString GetAccessorKindString() const;
wxString GetFilename() const;
size_t GetTicket() const { return m_Ticket; }
bool MatchesFiles(const TokenFileSet& files);
TokenTree* GetTree() const { return m_TokenTree; }
TokenKind m_TokenKind;// See TokenKind class
wxString m_Name; // Token's name, it can be searched in the TokenTree
unsigned int m_FileIdx; // File index in TokenTree
unsigned int m_Line; // Line index where the token was met, which is 0/1 based
TokenScope m_AccessKind; // public? private? protected?
bool m_IsLocal; // found in a local source file, otherwise in wxString buffer
bool m_IsTemp; // local (automatic) variable
bool m_IsConst; // the member method is const (yes/no)
int m_Index; // current Token index in the tree
int m_ParentIndex; // Parent Token index
void* m_UserData; // custom user-data (the classbrowser expects it to be a pointer to a cbProject)
protected:
TokenTree* m_TokenTree; // a pointer to TokenTree
size_t m_Ticket; // This is used in classbrowser to avoid duplication
};
// a ScopeToken can have children, also some inherent information, such as class, a function
class ScopeToken: public Token
{
ScopeToken(const wxString& name, unsigned int file, unsigned int line, size_t ticket);
virtual ~ScopeToken();
bool AddChild(int childIdx);
bool DeleteAllChildren();
bool HasChildren() const { return !m_Children.empty(); }
bool InheritsFrom(int idx) const;
bool IsValidAncestor(const wxString& ancestor);
TokenIdxSet m_Children; // if it is a class kind token, then it contains all the member tokens
wxString m_AncestorsString; // all ancestors comma-separated list
TokenIdxSet m_Ancestors; // all the ancestors in the inheritance hierarchy
TokenIdxSet m_DirectAncestors; //the nearest ancestors
TokenIdxSet m_Descendants; // all the descendants in the inheritance hierarchy
};
class VariableToken: public Token
{
friend class TokenTree;
public:
VariableToken(const wxString& name, unsigned int file, unsigned int line, size_t ticket);
virtual ~VariableToken();
virtual wxString DisplayName() const;
virtual TokenKind GetTokenKind() const {return tkVariable};
virtual wxString GetTokenKindString() const {return _T("variable");};
// some public functions
wxString m_FullType; // this is the full return value (if any): e.g. const wxString&
wxString m_BaseType; // this is what the parser believes is the actual return value: e.g. wxString
};
class FunctionToken: public ScopeToken
{
friend class TokenTree;
public:
FunctionToken(const wxString& name, unsigned int file, unsigned int line, size_t ticket);
virtual ~FunctionToken();
virtual wxString DisplayName() const;
virtual TokenKind GetTokenKind() const {return tkFunction};
virtual wxString GetTokenKindString() const {return _T("function");};
// some public functions
wxString GetFormattedArgs() const; // remove all '\n'
wxString GetStrippedArgs() const; // remove all default value
wxString m_FullType; // this is the full return value (if any): e.g. const wxString&
wxString m_BaseType; // this is what the parser believes is the actual return value: e.g. wxString
wxString m_Args; // If it is a function Token, then this value is function arguments
// e.g. (int arg1 = 10, float arg2 = 9.0)
// If it is an enumerator, then this is the assigned (inferred) value
wxString m_BaseArgs; // stripped arguments e.g. (int arg1, float arg2)
unsigned int m_ImplFileIdx; // function implementation file index
unsigned int m_ImplLine; // function implementation line index
unsigned int m_ImplLineStart; // if token is impl, opening brace line
unsigned int m_ImplLineEnd; // if token is impl, closing brace line
// To do: make them as enum, since they are exclusive
bool m_IsOperator; // is operator overload function?
bool m_IsConstructor; // class constructor
bool m_IsDestructor; // class destructor
};
class ClassToken: public ScopeToken
{
friend class TokenTree;
public:
ClassToken(const wxString& name, unsigned int file, unsigned int line, size_t ticket);
virtual ~ClassToken();
virtual wxString DisplayName() const;
virtual TokenKind GetTokenKind() const {return tkClass};
virtual wxString GetTokenKindString() const {return _T("class");};
// some public functions
wxString GetImplFilename() const;
unsigned int m_ImplLineStart; // if token is impl, opening brace line
unsigned int m_ImplLineEnd; // if token is impl, closing brace line
bool m_IsAnonymous; // Is anonymous token? (e.g. unnamed struct or union)
};
class TypeDefineToken: public Token
{
friend class TokenTree;
public:
TypeDefineToken(const wxString& name, unsigned int file, unsigned int line, size_t ticket);
virtual ~TypeDefineToken();
virtual wxString DisplayName() const;
virtual TokenKind GetTokenKind() const {return tkTypedef};
virtual wxString GetTokenKindString() const {return _T("typedef");};
// some public functions
wxString m_ReferenceType;
};
class MacroDefineToken: public Token
{
friend class TokenTree;
public:
MacroDefineToken(const wxString& name, unsigned int file, unsigned int line, size_t ticket);
virtual ~MacroDefineToken();
virtual wxString DisplayName() const;
virtual TokenKind GetTokenKind() const {return tkMacro};
virtual wxString GetTokenKindString() const {return _T("macro");};
// some public functions
wxString m_Replacement;
};
class ClassTemplateToken: public ClassToken
{
friend class TokenTree;
public:
ClassTemplateToken(const wxString& name, unsigned int file, unsigned int line, size_t ticket);
virtual ~ClassTemplateToken();
virtual wxString DisplayName() const;
virtual TokenKind GetTokenKind() const {return tkClassTemplate};
virtual wxString GetTokenKindString() const {return _T("class-template");};
// some public functions
wxString m_TemplateParameter;
wxArrayString m_TemplateParameterList; //for a class template, this is the formal template argument list
};
class ScopeAliasToken: public Token
{
friend class TokenTree;
public:
ScopeAliasToken(const wxString& name, unsigned int file, unsigned int line, size_t ticket);
virtual ~ScopeAliasToken();
// some public functions
wxString m_TemplateAlias;
int m_ReferenceTokenIdx;
};
class FunctionTemplateToken: public FunctionToken
{
friend class TokenTree;
public:
FunctionTemplateToken(const wxString& name, unsigned int file, unsigned int line, size_t ticket);
virtual ~FunctionTemplateToken();
virtual wxString DisplayName() const;
virtual TokenKind GetTokenKind() const {return tkFunctionTemplate};
virtual wxString GetTokenKindString() const {return _T("function-template");};
// some public functions
wxString m_TemplateParameter; //formal parameter
wxArrayString m_TemplateParameterList;
};
class FunctionTemplateSpecializationToken: public FunctionTemplateToken
{
friend class TokenTree;
public:
FunctionTemplateSpecializationToken(const wxString& name, unsigned int file, unsigned int line, size_t ticket);
virtual ~FunctionTemplateSpecializationToken();
virtual wxString DisplayName() const;
virtual TokenKind GetTokenKind() const {return tkFunctionTemplateSpecialization};
virtual wxString GetTokenKindString() const {return _T("function-template-specialization");};
// some public functions
wxString m_TemplateArgument; // actual parameter
std::map<wxString, wxString> m_TemplateMap;
};
--- End code ---
I divide the template and template specialization, because sometimes, a template specialization has its own class definition lines.
One question remains:
The Token tree are generally std::vector<Token*>
So, once I get a pointer, I need to translate the base type pointer to derived type.
So, here is the proposed method:
--- Code: ---Token * tk = GetSomeTokenFromTokenTree();
If (tk->GetTokenKind == tkFunction)
{
TokenFunctionToken * tk1 = (TokenFunctionToken *)tk;
tk->SomeFunctionOfFunctionToken();
}
--- End code ---
BTW: I don't know how llvm's method did, I have little knowledge about advanced C++. :)
oBFusCATed:
--- Quote from: ollydbg on November 28, 2013, 10:57:53 am ---
--- Code: --- virtual wxString DisplayName() const {return wxEmptyString};
virtual TokenKind GetTokenKind() const {return tkUndefined};
virtual wxString GetTokenKindString() const {return wxEmptyString};
virtual wxString GetNamespace() const {return wxEmptyString};
--- End code ---
--- End quote ---
These functions look inefficient, why don't you make them return const wxString& and be pure virtual?
--- Quote from: ollydbg on November 28, 2013, 10:57:53 am ---BTW: I don't know how llvm's method did, I have little knowledge about advanced C++. :)
--- End quote ---
Look at their code, I doubt it is that complex.
But if you need dynamic_cast only in CC plugin it is safe to use it instead of some home-made solution.
Just keep in mind that dynamic_cast won't work across dlopened shared libraries.
And one final note:
Is this change needed now?
Because, if you do it in trunk it will cause quite a lot of pain for merging the cc_interface branch back to trunk.
So either post pone it for after the merge or communicate with Alpha if it is OK to apply it in his branch.
Or even fork his branch and work on your fork, then use rebase to move your changes on top of his branch when he pushes commits.
ollydbg:
--- Quote from: oBFusCATed on November 28, 2013, 11:26:42 am ---
--- Quote from: ollydbg on November 28, 2013, 10:57:53 am ---
--- Code: --- virtual wxString DisplayName() const {return wxEmptyString};
virtual TokenKind GetTokenKind() const {return tkUndefined};
virtual wxString GetTokenKindString() const {return wxEmptyString};
virtual wxString GetNamespace() const {return wxEmptyString};
--- End code ---
--- End quote ---
These functions look inefficient, why don't you make them return const wxString& and be pure virtual?
--- End quote ---
Will do it, thanks.
--- Quote ---
--- Quote from: ollydbg on November 28, 2013, 10:57:53 am ---BTW: I don't know how llvm's method did, I have little knowledge about advanced C++. :)
--- End quote ---
Look at their code, I doubt it is that complex.
But if you need dynamic_cast only in CC plugin it is safe to use it instead of some home-made solution.
Just keep in mind that dynamic_cast won't work across dlopened shared libraries.
--- End quote ---
Do we need a dynamic_cast here in my code snippet?
--- Code: ---Token * tk = GetSomeTokenFromTokenTree();
If (tk->GetTokenKind == tkFunction)
{
TokenFunctionToken * tk1 = (TokenFunctionToken *)tk;
tk->SomeFunctionOfFunctionToken();
}
--- End code ---
Here, dynamic_cast and static_cast are the same, right? I think I will have some code like:
--- Code: ---Token * tk = GetSomeTokenFromTokenTree();
if (tk->GetTokenKind() == tkFunction)
{
TokenFunctionToken * tk1 = (TokenFunctionToken *)tk;
tk->SomeFunctionOfFunctionToken();
}
else if (tk->GetTokenKind() == tkClass)
{
TokenClassToken * tk1 = (TokenClassToken *)tk;
tk->SomeFunctionOfClassToken();
}
else if (tk->GetTokenKind() == tkClass)
{
}
else if ...
--- End code ---
Is it OK that we have a lot of if-else clause?
--- Quote ---And one final note:
Is this change needed now?
Because, if you do it in trunk it will cause quite a lot of pain for merging the cc_interface branch back to trunk.
So either post pone it for after the merge or communicate with Alpha if it is OK to apply it in his branch.
Or even fork his branch and work on your fork, then use rebase to move your changes on top of his branch when he pushes commits.
--- End quote ---
No hurry, I will avoid the pain by your suggestion, I think I can not finish the refactoring soon. If the draft code snippet get approved by your guys, then I can start coding, I think it will take some months.
oBFusCATed:
--- Quote from: ollydbg on November 28, 2013, 01:37:54 pm ---Is it OK that we have a lot of if-else clause?
--- End quote ---
Probably you need to have a virtual function in your base class for this case.
You can use a switch statement, but as far as I know this is why people want to use inheritance - to have less cases where they need switches.
I guess you need to read one-two-three articles on clean OOP design, to see what options you have with classes.
I can't comment on the usefulness of some design, when I don't know the old design.
My comments are just general in this case.
btw: Please don't use C style cases. Try to use only C++ (static_cast, const_cast, reinterpret_cast, dynamic_cast, they are generally safer).
ollydbg:
--- Quote from: oBFusCATed on November 28, 2013, 02:10:29 pm ---
--- Quote from: ollydbg on November 28, 2013, 01:37:54 pm ---Is it OK that we have a lot of if-else clause?
--- End quote ---
Probably you need to have a virtual function in your base class for this case.
You can use a switch statement, but as far as I know this is why people want to use inheritance - to have less cases where they need switches.
I guess you need to read one-two-three articles on clean OOP design, to see what options you have with classes.
--- End quote ---
Thanks, I generally know this idea, by adding a virtual function in the base class, I can wrap all the if-else clause's contents to every virtual function of the derived class, thus avoid the if-else or switch statements. I will read some articles about this idea.
--- Quote ---btw: Please don't use C style cases. Try to use only C++ (static_cast, const_cast, reinterpret_cast, dynamic_cast, they are generally safer).
--- End quote ---
Ok, will do it.
Navigation
[0] Message Index
[#] Next page
[*] Previous page
Go to full version