forked from qt-creator/qt-creator
C++: Type deduction for auto-declared variables implemented
Handled to major cases of 'auto' variable declaration: 1. auto var = someInitializer; 2. Q_FOREACH(auto item, collection) or foreach(auto item, collection) In first case type deducted directly from initializer. If variable has no initializer then corresponded error reported. In second case type deducted from '*collection.begin()' expression. Change-Id: Ie930add1648b99440281ae04d973fd6904bc9e46 Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
This commit is contained in:
committed by
Roberto Raggi
parent
0651e28d04
commit
c6fc0be8ae
48
src/libs/3rdparty/cplusplus/Bind.cpp
vendored
48
src/libs/3rdparty/cplusplus/Bind.cpp
vendored
@@ -337,8 +337,14 @@ FullySpecifiedType Bind::declarator(DeclaratorAST *ast, const FullySpecifiedType
|
|||||||
return type;
|
return type;
|
||||||
|
|
||||||
std::swap(_declaratorId, declaratorId);
|
std::swap(_declaratorId, declaratorId);
|
||||||
|
bool isAuto = false;
|
||||||
|
if (translationUnit()->cxx0xEnabled())
|
||||||
|
isAuto = type.isAuto();
|
||||||
|
|
||||||
for (SpecifierListAST *it = ast->attribute_list; it; it = it->next) {
|
for (SpecifierListAST *it = ast->attribute_list; it; it = it->next) {
|
||||||
type = this->specifier(it->value, type);
|
type = this->specifier(it->value, type);
|
||||||
|
if (type.isAuto())
|
||||||
|
isAuto = true;
|
||||||
}
|
}
|
||||||
for (PtrOperatorListAST *it = ast->ptr_operator_list; it; it = it->next) {
|
for (PtrOperatorListAST *it = ast->ptr_operator_list; it; it = it->next) {
|
||||||
type = this->ptrOperator(it->value, type);
|
type = this->ptrOperator(it->value, type);
|
||||||
@@ -349,9 +355,17 @@ FullySpecifiedType Bind::declarator(DeclaratorAST *ast, const FullySpecifiedType
|
|||||||
type = this->coreDeclarator(ast->core_declarator, type);
|
type = this->coreDeclarator(ast->core_declarator, type);
|
||||||
for (SpecifierListAST *it = ast->post_attribute_list; it; it = it->next) {
|
for (SpecifierListAST *it = ast->post_attribute_list; it; it = it->next) {
|
||||||
type = this->specifier(it->value, type);
|
type = this->specifier(it->value, type);
|
||||||
|
if (type.isAuto())
|
||||||
|
isAuto = true;
|
||||||
}
|
}
|
||||||
// unsigned equals_token = ast->equals_token;
|
// unsigned equals_token = ast->equals_token;
|
||||||
ExpressionTy initializer = this->expression(ast->initializer);
|
ExpressionTy initializer = this->expression(ast->initializer);
|
||||||
|
if (translationUnit()->cxx0xEnabled() && isAuto) {
|
||||||
|
|
||||||
|
type = initializer;
|
||||||
|
type.setAuto(true);
|
||||||
|
}
|
||||||
|
|
||||||
std::swap(_declaratorId, declaratorId);
|
std::swap(_declaratorId, declaratorId);
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
@@ -1231,11 +1245,29 @@ bool Bind::visit(ForeachStatementAST *ast)
|
|||||||
}
|
}
|
||||||
DeclaratorIdAST *declaratorId = 0;
|
DeclaratorIdAST *declaratorId = 0;
|
||||||
type = this->declarator(ast->declarator, type, &declaratorId);
|
type = this->declarator(ast->declarator, type, &declaratorId);
|
||||||
|
const StringLiteral *initializer = 0;
|
||||||
|
if (type.isAuto() && translationUnit()->cxx0xEnabled()) {
|
||||||
|
ExpressionTy exprType = this->expression(ast->expression);
|
||||||
|
|
||||||
|
ArrayType* arrayType = 0;
|
||||||
|
arrayType = exprType->asArrayType();
|
||||||
|
|
||||||
|
if (arrayType != 0)
|
||||||
|
type = arrayType->elementType();
|
||||||
|
else if (ast->expression != 0) {
|
||||||
|
unsigned startOfExpression = ast->expression->firstToken();
|
||||||
|
unsigned endOfExpression = ast->expression->lastToken();
|
||||||
|
const StringLiteral *sl = asStringLiteral(startOfExpression, endOfExpression);
|
||||||
|
const std::string buff = std::string("*") + sl->chars() + ".begin()";
|
||||||
|
initializer = control()->stringLiteral(buff.c_str(), buff.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (declaratorId && declaratorId->name) {
|
if (declaratorId && declaratorId->name) {
|
||||||
unsigned sourceLocation = location(declaratorId->name, ast->firstToken());
|
unsigned sourceLocation = location(declaratorId->name, ast->firstToken());
|
||||||
Declaration *decl = control()->newDeclaration(sourceLocation, declaratorId->name->name);
|
Declaration *decl = control()->newDeclaration(sourceLocation, declaratorId->name->name);
|
||||||
decl->setType(type);
|
decl->setType(type);
|
||||||
|
decl->setInitializer(initializer);
|
||||||
block->addMember(decl);
|
block->addMember(decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1791,6 +1823,16 @@ bool Bind::visit(SimpleDeclarationAST *ast)
|
|||||||
if (declaratorId && declaratorId->name)
|
if (declaratorId && declaratorId->name)
|
||||||
fun->setName(declaratorId->name->name); // update the function name
|
fun->setName(declaratorId->name->name); // update the function name
|
||||||
}
|
}
|
||||||
|
else if (declTy.isAuto()) {
|
||||||
|
const ExpressionAST *initializer = it->value->initializer;
|
||||||
|
if (!initializer)
|
||||||
|
translationUnit()->error(location(declaratorId->name, ast->firstToken()), "auto-initialized variable must have an initializer");
|
||||||
|
else {
|
||||||
|
unsigned startOfExpression = initializer->firstToken();
|
||||||
|
unsigned endOfExpression = initializer->lastToken();
|
||||||
|
decl->setInitializer(asStringLiteral(startOfExpression, endOfExpression));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_scope->isClass()) {
|
if (_scope->isClass()) {
|
||||||
decl->setVisibility(_visibility);
|
decl->setVisibility(_visibility);
|
||||||
@@ -2576,8 +2618,10 @@ bool Bind::visit(SimpleSpecifierAST *ast)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case T_AUTO:
|
case T_AUTO:
|
||||||
if (_type.isAuto())
|
if (!translationUnit()->cxx0xEnabled()) {
|
||||||
translationUnit()->error(ast->specifier_token, "duplicate `%s'", spell(ast->specifier_token));
|
if (_type.isAuto())
|
||||||
|
translationUnit()->error(ast->specifier_token, "duplicate `%s'", spell(ast->specifier_token));
|
||||||
|
}
|
||||||
_type.setAuto(true);
|
_type.setAuto(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@@ -47,7 +47,6 @@ FullySpecifiedType FullySpecifiedType::qualifiedType() const
|
|||||||
{
|
{
|
||||||
FullySpecifiedType ty = *this;
|
FullySpecifiedType ty = *this;
|
||||||
ty.setFriend(false);
|
ty.setFriend(false);
|
||||||
ty.setAuto(false);
|
|
||||||
ty.setRegister(false);
|
ty.setRegister(false);
|
||||||
ty.setStatic(false);
|
ty.setStatic(false);
|
||||||
ty.setExtern(false);
|
ty.setExtern(false);
|
||||||
|
12
src/libs/3rdparty/cplusplus/Symbols.cpp
vendored
12
src/libs/3rdparty/cplusplus/Symbols.cpp
vendored
@@ -92,11 +92,13 @@ void UsingDeclaration::visitSymbol0(SymbolVisitor *visitor)
|
|||||||
|
|
||||||
Declaration::Declaration(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name)
|
Declaration::Declaration(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name)
|
||||||
: Symbol(translationUnit, sourceLocation, name)
|
: Symbol(translationUnit, sourceLocation, name)
|
||||||
|
, _initializer(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
Declaration::Declaration(Clone *clone, Subst *subst, Declaration *original)
|
Declaration::Declaration(Clone *clone, Subst *subst, Declaration *original)
|
||||||
: Symbol(clone, subst, original)
|
: Symbol(clone, subst, original)
|
||||||
, _type(clone->type(original->_type, subst))
|
, _type(clone->type(original->_type, subst))
|
||||||
|
, _initializer(clone->stringLiteral(original->_initializer))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
Declaration::~Declaration()
|
Declaration::~Declaration()
|
||||||
@@ -105,9 +107,19 @@ Declaration::~Declaration()
|
|||||||
void Declaration::setType(const FullySpecifiedType &type)
|
void Declaration::setType(const FullySpecifiedType &type)
|
||||||
{ _type = type; }
|
{ _type = type; }
|
||||||
|
|
||||||
|
void Declaration::setInitializer(const StringLiteral *initializer)
|
||||||
|
{
|
||||||
|
_initializer = initializer;
|
||||||
|
}
|
||||||
|
|
||||||
FullySpecifiedType Declaration::type() const
|
FullySpecifiedType Declaration::type() const
|
||||||
{ return _type; }
|
{ return _type; }
|
||||||
|
|
||||||
|
const StringLiteral *Declaration::getInitializer() const
|
||||||
|
{
|
||||||
|
return _initializer;
|
||||||
|
}
|
||||||
|
|
||||||
void Declaration::visitSymbol0(SymbolVisitor *visitor)
|
void Declaration::visitSymbol0(SymbolVisitor *visitor)
|
||||||
{ visitor->visit(this); }
|
{ visitor->visit(this); }
|
||||||
|
|
||||||
|
3
src/libs/3rdparty/cplusplus/Symbols.h
vendored
3
src/libs/3rdparty/cplusplus/Symbols.h
vendored
@@ -104,9 +104,11 @@ public:
|
|||||||
virtual ~Declaration();
|
virtual ~Declaration();
|
||||||
|
|
||||||
void setType(const FullySpecifiedType &type);
|
void setType(const FullySpecifiedType &type);
|
||||||
|
void setInitializer(StringLiteral const* initializer);
|
||||||
|
|
||||||
// Symbol's interface
|
// Symbol's interface
|
||||||
virtual FullySpecifiedType type() const;
|
virtual FullySpecifiedType type() const;
|
||||||
|
const StringLiteral *getInitializer() const;
|
||||||
|
|
||||||
virtual const Declaration *asDeclaration() const
|
virtual const Declaration *asDeclaration() const
|
||||||
{ return this; }
|
{ return this; }
|
||||||
@@ -125,6 +127,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
FullySpecifiedType _type;
|
FullySpecifiedType _type;
|
||||||
|
const StringLiteral *_initializer;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CPLUSPLUS_EXPORT EnumeratorDeclaration: public Declaration
|
class CPLUSPLUS_EXPORT EnumeratorDeclaration: public Declaration
|
||||||
|
@@ -35,6 +35,7 @@
|
|||||||
#include "Overview.h"
|
#include "Overview.h"
|
||||||
#include "DeprecatedGenTemplateInstance.h"
|
#include "DeprecatedGenTemplateInstance.h"
|
||||||
#include "CppRewriter.h"
|
#include "CppRewriter.h"
|
||||||
|
#include "TypeOfExpression.h"
|
||||||
|
|
||||||
#include <Control.h>
|
#include <Control.h>
|
||||||
#include <AST.h>
|
#include <AST.h>
|
||||||
@@ -45,6 +46,7 @@
|
|||||||
#include <CoreTypes.h>
|
#include <CoreTypes.h>
|
||||||
#include <TypeVisitor.h>
|
#include <TypeVisitor.h>
|
||||||
#include <NameVisitor.h>
|
#include <NameVisitor.h>
|
||||||
|
#include <Templates.h>
|
||||||
|
|
||||||
#include <QtCore/QList>
|
#include <QtCore/QList>
|
||||||
#include <QtCore/QtDebug>
|
#include <QtCore/QtDebug>
|
||||||
@@ -402,11 +404,39 @@ bool ResolveExpression::visit(UnaryExpressionAST *ast)
|
|||||||
QMutableListIterator<LookupItem > it(_results);
|
QMutableListIterator<LookupItem > it(_results);
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
LookupItem p = it.next();
|
LookupItem p = it.next();
|
||||||
if (PointerType *ptrTy = p.type()->asPointerType()) {
|
FullySpecifiedType ty = p.type();
|
||||||
|
NamedType *namedTy = ty->asNamedType();
|
||||||
|
if (namedTy != 0) {
|
||||||
|
const QList<LookupItem> types = _context.lookup(namedTy->name(), p.scope());
|
||||||
|
if (!types.empty())
|
||||||
|
ty = types.front().type();
|
||||||
|
}
|
||||||
|
bool added = false;
|
||||||
|
if (PointerType *ptrTy = ty->asPointerType()) {
|
||||||
p.setType(ptrTy->elementType());
|
p.setType(ptrTy->elementType());
|
||||||
it.setValue(p);
|
it.setValue(p);
|
||||||
} else {
|
added = true;
|
||||||
it.remove();
|
} else if (namedTy != 0) {
|
||||||
|
const Name *starOp = control()->operatorNameId(OperatorNameId::StarOp);
|
||||||
|
if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), p.scope())) {
|
||||||
|
foreach (const LookupItem &r, b->find(starOp)) {
|
||||||
|
Symbol *overload = r.declaration();
|
||||||
|
if (Function *funTy = overload->type()->asFunctionType()) {
|
||||||
|
if (maybeValidPrototype(funTy, 0)) {
|
||||||
|
if (Function *proto = instantiate(b->templateId(), funTy)->asFunctionType()) {
|
||||||
|
FullySpecifiedType retTy = proto->returnType().simplified();
|
||||||
|
p.setType(retTy);
|
||||||
|
p.setScope(proto->enclosingScope());
|
||||||
|
it.setValue(p);
|
||||||
|
added = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!added)
|
||||||
|
it.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -431,8 +461,65 @@ bool ResolveExpression::visit(QualifiedNameAST *ast)
|
|||||||
|
|
||||||
bool ResolveExpression::visit(SimpleNameAST *ast)
|
bool ResolveExpression::visit(SimpleNameAST *ast)
|
||||||
{
|
{
|
||||||
const QList<LookupItem> candidates = _context.lookup(ast->name, _scope);
|
QList<LookupItem> candidates = _context.lookup(ast->name, _scope);
|
||||||
|
QList<LookupItem> newCandidates;
|
||||||
|
|
||||||
|
for (QList<LookupItem>::iterator it = candidates.begin(); it != candidates.end(); ++ it) {
|
||||||
|
LookupItem& item = *it;
|
||||||
|
if (!item.type()->isUndefinedType())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (item.declaration() == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (item.type().isAuto()) {
|
||||||
|
const Declaration *decl = item.declaration()->asDeclaration();
|
||||||
|
if (!decl)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Document::Ptr doc = _context.snapshot().document(decl->fileName());
|
||||||
|
|
||||||
|
const StringLiteral *initializationString = decl->getInitializer();
|
||||||
|
if (initializationString == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QByteArray initializer = QByteArray::fromRawData(initializationString->chars(), initializationString->size()).trimmed();
|
||||||
|
|
||||||
|
// Skip lambda-function initializers
|
||||||
|
if (initializer.length() > 0 && initializer[0] == '[')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TypeOfExpression exprTyper;
|
||||||
|
exprTyper.init(doc, _context.snapshot(), _context.bindings());
|
||||||
|
|
||||||
|
QList<LookupItem> typeItems = exprTyper(initializer, decl->enclosingScope(), TypeOfExpression::Preprocess);
|
||||||
|
if (typeItems.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CPlusPlus::Clone cloner(_context.control().data());
|
||||||
|
|
||||||
|
for (int n = 0; n < typeItems.size(); ++ n) {
|
||||||
|
FullySpecifiedType newType = cloner.type(typeItems[n].type(), 0);
|
||||||
|
if (n == 0) {
|
||||||
|
item.setType(newType);
|
||||||
|
item.setScope(typeItems[n].scope());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LookupItem newItem(item);
|
||||||
|
newItem.setType(newType);
|
||||||
|
newItem.setScope(typeItems[n].scope());
|
||||||
|
newCandidates.push_back(newItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item.setType(item.declaration()->type());
|
||||||
|
item.setScope(item.declaration()->enclosingScope());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addResults(candidates);
|
addResults(candidates);
|
||||||
|
addResults(newCandidates);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user