From c6fc0be8ae15e43abb765323d7edaf7741405878 Mon Sep 17 00:00:00 2001 From: Flex Ferrum Date: Sat, 28 Jan 2012 22:58:08 +0400 Subject: 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 --- src/libs/3rdparty/cplusplus/Bind.cpp | 48 ++++++++++- src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp | 3 +- src/libs/3rdparty/cplusplus/Symbols.cpp | 12 +++ src/libs/3rdparty/cplusplus/Symbols.h | 3 + src/libs/cplusplus/ResolveExpression.cpp | 95 +++++++++++++++++++++- 5 files changed, 153 insertions(+), 8 deletions(-) (limited to 'src/libs') diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index 435e01dfe5..13a819a19f 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -337,8 +337,14 @@ FullySpecifiedType Bind::declarator(DeclaratorAST *ast, const FullySpecifiedType return type; std::swap(_declaratorId, declaratorId); + bool isAuto = false; + if (translationUnit()->cxx0xEnabled()) + isAuto = type.isAuto(); + for (SpecifierListAST *it = ast->attribute_list; it; it = it->next) { type = this->specifier(it->value, type); + if (type.isAuto()) + isAuto = true; } for (PtrOperatorListAST *it = ast->ptr_operator_list; it; it = it->next) { type = this->ptrOperator(it->value, type); @@ -349,9 +355,17 @@ FullySpecifiedType Bind::declarator(DeclaratorAST *ast, const FullySpecifiedType type = this->coreDeclarator(ast->core_declarator, type); for (SpecifierListAST *it = ast->post_attribute_list; it; it = it->next) { type = this->specifier(it->value, type); + if (type.isAuto()) + isAuto = true; } // unsigned equals_token = ast->equals_token; ExpressionTy initializer = this->expression(ast->initializer); + if (translationUnit()->cxx0xEnabled() && isAuto) { + + type = initializer; + type.setAuto(true); + } + std::swap(_declaratorId, declaratorId); return type; } @@ -1231,11 +1245,29 @@ bool Bind::visit(ForeachStatementAST *ast) } DeclaratorIdAST *declaratorId = 0; 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) { unsigned sourceLocation = location(declaratorId->name, ast->firstToken()); Declaration *decl = control()->newDeclaration(sourceLocation, declaratorId->name->name); decl->setType(type); + decl->setInitializer(initializer); block->addMember(decl); } @@ -1791,6 +1823,16 @@ bool Bind::visit(SimpleDeclarationAST *ast) if (declaratorId && declaratorId->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()) { decl->setVisibility(_visibility); @@ -2576,8 +2618,10 @@ bool Bind::visit(SimpleSpecifierAST *ast) break; case T_AUTO: - if (_type.isAuto()) - translationUnit()->error(ast->specifier_token, "duplicate `%s'", spell(ast->specifier_token)); + if (!translationUnit()->cxx0xEnabled()) { + if (_type.isAuto()) + translationUnit()->error(ast->specifier_token, "duplicate `%s'", spell(ast->specifier_token)); + } _type.setAuto(true); break; diff --git a/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp b/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp index 1a2e63d78c..6ed6f4e105 100644 --- a/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp +++ b/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp @@ -47,7 +47,6 @@ FullySpecifiedType FullySpecifiedType::qualifiedType() const { FullySpecifiedType ty = *this; ty.setFriend(false); - ty.setAuto(false); ty.setRegister(false); ty.setStatic(false); ty.setExtern(false); @@ -236,4 +235,4 @@ bool FullySpecifiedType::match(const FullySpecifiedType &otherTy, TypeMatcher *m return false; return type()->matchType(otherTy.type(), matcher); -} +} \ No newline at end of file diff --git a/src/libs/3rdparty/cplusplus/Symbols.cpp b/src/libs/3rdparty/cplusplus/Symbols.cpp index b1b7fbcefd..be4dd85e9f 100644 --- a/src/libs/3rdparty/cplusplus/Symbols.cpp +++ b/src/libs/3rdparty/cplusplus/Symbols.cpp @@ -92,11 +92,13 @@ void UsingDeclaration::visitSymbol0(SymbolVisitor *visitor) Declaration::Declaration(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name) : Symbol(translationUnit, sourceLocation, name) + , _initializer(0) { } Declaration::Declaration(Clone *clone, Subst *subst, Declaration *original) : Symbol(clone, subst, original) , _type(clone->type(original->_type, subst)) + , _initializer(clone->stringLiteral(original->_initializer)) { } Declaration::~Declaration() @@ -105,9 +107,19 @@ Declaration::~Declaration() void Declaration::setType(const FullySpecifiedType &type) { _type = type; } +void Declaration::setInitializer(const StringLiteral *initializer) +{ + _initializer = initializer; +} + FullySpecifiedType Declaration::type() const { return _type; } +const StringLiteral *Declaration::getInitializer() const +{ + return _initializer; +} + void Declaration::visitSymbol0(SymbolVisitor *visitor) { visitor->visit(this); } diff --git a/src/libs/3rdparty/cplusplus/Symbols.h b/src/libs/3rdparty/cplusplus/Symbols.h index 9de640ff2a..ec65e926f7 100644 --- a/src/libs/3rdparty/cplusplus/Symbols.h +++ b/src/libs/3rdparty/cplusplus/Symbols.h @@ -104,9 +104,11 @@ public: virtual ~Declaration(); void setType(const FullySpecifiedType &type); + void setInitializer(StringLiteral const* initializer); // Symbol's interface virtual FullySpecifiedType type() const; + const StringLiteral *getInitializer() const; virtual const Declaration *asDeclaration() const { return this; } @@ -125,6 +127,7 @@ protected: private: FullySpecifiedType _type; + const StringLiteral *_initializer; }; class CPLUSPLUS_EXPORT EnumeratorDeclaration: public Declaration diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 66d5dfbd38..5db83fe873 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -35,6 +35,7 @@ #include "Overview.h" #include "DeprecatedGenTemplateInstance.h" #include "CppRewriter.h" +#include "TypeOfExpression.h" #include #include @@ -45,6 +46,7 @@ #include #include #include +#include #include #include @@ -402,11 +404,39 @@ bool ResolveExpression::visit(UnaryExpressionAST *ast) QMutableListIterator it(_results); while (it.hasNext()) { LookupItem p = it.next(); - if (PointerType *ptrTy = p.type()->asPointerType()) { + FullySpecifiedType ty = p.type(); + NamedType *namedTy = ty->asNamedType(); + if (namedTy != 0) { + const QList 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()); it.setValue(p); - } else { - it.remove(); + added = true; + } 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) { - const QList candidates = _context.lookup(ast->name, _scope); + QList candidates = _context.lookup(ast->name, _scope); + QList newCandidates; + + for (QList::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 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(newCandidates); return false; } -- cgit v1.2.3