recently the code completion was enhanced by recognizing declaration in if / for/while constructs, this is great.
I would like to take it one step small further : range based for :
* say you have a container ==> vector/list/... "container"
for (auto foo : container)
for (const auto foo : container)
for (auto& foo : container)
for (const auto& foo : container)
foo is of the value type (disregarding const and references here) of the container.
Example :
std::vector<MyType> container; ===> foo is of type MyType
So the syntax seems simple in the "for( ... : ...)", the challenge probably is, do we know the 'container' its value type ? And can we deduce this second level of determination ?
What do our CC experts think ?
for (auto foo : container)
Keep in mind that instead of container there might be expression. And "auto" have different meaning in c++03.
As you can see here: http://en.cppreference.com/w/cpp/language/range-for , loop declaration:
for ( range_declaration : range_expression) loop_statement
is equals to
auto && __range = range_expression ;
auto __begin = __range.begin(); // or begin(__range);
auto __end = __range.end(); // or end(__range);
for (;__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
and declaration is logically equals to decltype(expression) foo = expression
To implement decltype parser might use NativeParser::AI to find out type of expression (all required tokens should be already in tree), but actually ParserThread doesn't have access to NativeParser object.
CodeCompletion class -> NativeParser -> Parser -> ParserThread -> Tokenizer
Thats true, but:
source file is parsed in ParserThread, and TokenTree is build there. So what can parser do when "auto" or "decltype" token occurs?
My idea was to detect real type of variable defined as "decltype" using NativeParserBase::ResolveActualType or somethin like that. All tokens required to detect real type of "auto" variable or function probably will be already in tree.
Lets assume you have access to nativeParser in ParserThread, so you can write something like this in DoParse:
if(token == ParserConsts::dectype)
{
m_Tokenizer.GetToken(); // eat "decltype"
m_Tokenizer.GetToken(); // eat "("
string type = m_Tokenizer.GetToken();
//release lock here
TokenIdxSet result;
nativeParser->resolveActualType(m_tree, type, ..., result) // or AI( ..., type, result)
//lock again
Token *newToken = DoAddToken(tkVariable, token, smallTokenizer.GetLineNumber());
newToken->m_FullType = tree[result.begin()]->m_FullType;
}
I understand your idea.
size_t NativeParserBase::ResolveActualType(TokenTree* tree,
wxString searchText,
const TokenIdxSet& searchScope,
TokenIdxSet& result)
See the third parameter, it is the searchScope, which is a C++ exposed scope(context). It can be introduced by
1, using directive
2, class inheritance
3, scope exposed in its include files
4, other cases
So, how do you get them?
The dirty thing is C++ grammar is context sensitive, it is hard to solve which type when the Parserthread meet a decltype.
Another thing is:
Is it possible to introduce a Token, which has type string named "undefined" or "lasy", then when NativeParser need to show tooltip or code suggestion, it can solve them. (I mean solve the types later when needed)
Final thought, type solving is related to semantic check stage, but our CC's parser mostly do a syntax check, so if we need precise information, a full parser (Clang or GCC) is needed.