Commit 05b647a4 authored by Milian Wolff's avatar Milian Wolff
Browse files

c++11 support: first work towards proper DUChain integration of lambda expressions

- a lambda expression now properly gets a function type associated
- the lambda declarator now is represented by a function context
which gets imported into the body of the lambda expression

known problems:
- the surrounding context is still implicitly imported into the
body context
- the return-type is not properly computed in cases where no
explicit trailing return type is given but only a single
return statement in the body instead
- lambda captures are still not handled at all

CCBUG: 279699
parent 33ba56c7
......@@ -1112,6 +1112,22 @@ void ContextBuilder::visitCatchStatement(CatchStatementAST *node)
}
}
void ContextBuilder::visitLambdaDeclarator(LambdaDeclaratorAST* node)
{
if (node->parameter_declaration_clause) {
DUContext* ctx = openContext(node->parameter_declaration_clause, DUContext::Function);
addImportedContexts();
if(compilingContexts())
queueImportedContext(ctx);
}
DefaultVisitor::visitLambdaDeclarator(node);
if (node->parameter_declaration_clause) {
closeContext();
}
}
bool ContextBuilder::createContextIfNeeded(AST* node, DUContext* importedParentContext)
{
QVector<DUContext::Import> imports;
......
......@@ -199,6 +199,7 @@ protected:
virtual void closeTypeForInitializer(InitializerAST *node);
virtual void closeTypeForDeclarator(DeclaratorAST *node);
virtual void visitParameterDeclarationClause(ParameterDeclarationClauseAST* node);
virtual void visitLambdaDeclarator(LambdaDeclaratorAST* node);
void queueImportedContext(DUContext* context) {
DUChainReadLocker lock(DUChain::lock());
......
......@@ -2387,6 +2387,29 @@ void ExpressionVisitor::createDelayedType( AST* node , bool expression ) {
}
}
void ExpressionVisitor::visitLambdaExpression(LambdaExpressionAST *node)
{
DefaultVisitor::visitLambdaExpression(node);
FunctionType* type = new FunctionType;
if (node->declarator && node->declarator->parameter_declaration_clause) {
if (buildParametersFromDeclaration(node->declarator->parameter_declaration_clause)) {
foreach(const OverloadResolver::Parameter& param, m_parameters) {
type->addArgument(param.type);
}
}
}
if (node->declarator && node->declarator->trailing_return_type) {
visit(node->declarator->trailing_return_type);
type->setReturnType(m_lastType);
}
if (!type->returnType()) {
///TODO: if body consists of only a single return statement, use that type as return type
type->setReturnType(AbstractType::Ptr(new IntegralType(IntegralType::TypeVoid)));
}
m_lastType = AbstractType::Ptr( type );
m_lastInstance = Instance(true);
}
void ExpressionVisitor::visit(AST* node)
{
if (!node) {
......
......@@ -340,6 +340,7 @@ private:
virtual void visitUnaryExpression(UnaryExpressionAST *) ;
virtual void visitSignalSlotExpression (SignalSlotExpressionAST*);
virtual void visitTypeIDOperator(TypeIDOperatorAST *);
virtual void visitLambdaExpression(LambdaExpressionAST *);
virtual void visit(AST* node);
void putStringType();
......
......@@ -204,6 +204,7 @@ private slots:
void testInitListRegressions();
void testBug284536();
void testBug285004();
void testLambda();
//END C++2011
private:
......
......@@ -31,6 +31,7 @@
#include <language/duchain/types/integraltype.h>
#include <language/duchain/types/pointertype.h>
#include <language/duchain/types/arraytype.h>
#include <language/duchain/dumpchain.h>
#include "typeutils.h"
......@@ -484,3 +485,47 @@ void TestDUChain::testBug285004()
QVERIFY(top);
DUChainReadLocker lock;
}
void TestDUChain::testLambda()
{
// see also: https://bugs.kde.org/show_bug.cgi?id=279699
const QByteArray code = "int main() {\n"
" int i;\n"
" auto f = [] (int i) { i = 0; };\n"
"}\n";
LockedTopDUContext top = parse(code, DumpAll);
QVERIFY(top);
DUChainReadLocker lock;
dumpDUContext(top);
DUContext* mainCtx = top->childContexts().last();
QCOMPARE(mainCtx->childContexts().size(), 2);
// (int i)
QCOMPARE(mainCtx->childContexts().first()->type(), DUContext::Function);
QCOMPARE(mainCtx->childContexts().first()->range(), RangeInRevision(2, 15, 2, 20));
// { i = 0; }
QCOMPARE(mainCtx->childContexts().last()->type(), DUContext::Other);
QCOMPARE(mainCtx->childContexts().last()->range(), RangeInRevision(2, 22, 2, 32));
// int i; in main context
QCOMPARE(mainCtx->localDeclarations().size(), 2);
Declaration* iDecl = mainCtx->localDeclarations().at(0);
// no uses
QCOMPARE(iDecl->uses().size(), 0);
// (int i) in lambda argument context
QCOMPARE(mainCtx->childContexts().first()->localDeclarations().size(), 1);
Declaration* iLambdaDecl = mainCtx->childContexts().first()->localDeclarations().first();
QCOMPARE(iLambdaDecl->uses().size(), 1);
QCOMPARE(iLambdaDecl->uses().begin()->size(), 1);
QCOMPARE(iLambdaDecl->uses().begin()->first(), RangeInRevision(2, 24, 2, 25));
Declaration* fDecl = mainCtx->localDeclarations().at(1);
TypePtr< FunctionType > funType = fDecl->type<FunctionType>();
QVERIFY(funType);
QCOMPARE(funType->indexedArgumentsSize(), 1u);
QVERIFY(funType->arguments().first()->equals(iLambdaDecl->abstractType().constData()));
QVERIFY(funType->returnType());
QVERIFY(funType->returnType().cast<IntegralType>());
QCOMPARE(funType->returnType().cast<IntegralType>()->dataType(), (uint) IntegralType::TypeVoid);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment