aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs
diff options
context:
space:
mode:
authorFlex Ferrum <flexferrum@gmail.com>2012-01-28 22:58:08 +0400
committerRoberto Raggi <roberto.raggi@nokia.com>2012-01-31 10:03:36 +0100
commitc6fc0be8ae15e43abb765323d7edaf7741405878 (patch)
tree28be4293dd50e455c4507f3f9646e4db91f0aca5 /src/libs
parent0651e28d04933647740b92322fe8f7f279cb6954 (diff)
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>
Diffstat (limited to 'src/libs')
-rw-r--r--src/libs/3rdparty/cplusplus/Bind.cpp48
-rw-r--r--src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp3
-rw-r--r--src/libs/3rdparty/cplusplus/Symbols.cpp12
-rw-r--r--src/libs/3rdparty/cplusplus/Symbols.h3
-rw-r--r--src/libs/cplusplus/ResolveExpression.cpp95
5 files changed, 153 insertions, 8 deletions
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 <Control.h>
#include <AST.h>
@@ -45,6 +46,7 @@
#include <CoreTypes.h>
#include <TypeVisitor.h>
#include <NameVisitor.h>
+#include <Templates.h>
#include <QtCore/QList>
#include <QtCore/QtDebug>
@@ -402,11 +404,39 @@ bool ResolveExpression::visit(UnaryExpressionAST *ast)
QMutableListIterator<LookupItem > 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<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());
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<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(newCandidates);
return false;
}