C++: Store lambda captures in the code model.

Done-with: Erik Verbruggen
Task-number: QTCREATORBUG-7968
Task-number: QTCREATORBUG-7949

Change-Id: I0cf727052d0a3536ed96ee894b18768c9538c213
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
Nikolai Kosjar
2012-10-25 16:22:42 +02:00
parent be516c7c6e
commit 9f38f7bfbc
12 changed files with 103 additions and 23 deletions

View File

@@ -403,12 +403,22 @@ unsigned CallAST::lastToken() const
/** \generated */ /** \generated */
unsigned CaptureAST::firstToken() const unsigned CaptureAST::firstToken() const
{ {
if (amper_token)
return amper_token;
if (identifier)
if (unsigned candidate = identifier->firstToken())
return candidate;
return 0; return 0;
} }
/** \generated */ /** \generated */
unsigned CaptureAST::lastToken() const unsigned CaptureAST::lastToken() const
{ {
if (identifier)
if (unsigned candidate = identifier->lastToken())
return candidate;
if (amper_token)
return amper_token + 1;
return 1; return 1;
} }

View File

@@ -4394,8 +4394,14 @@ protected:
class CaptureAST: public AST class CaptureAST: public AST
{ {
public:
unsigned amper_token;
NameAST *identifier;
public: public:
CaptureAST() CaptureAST()
: amper_token(0)
, identifier(0)
{} {}
virtual CaptureAST *asCapture() { return this; } virtual CaptureAST *asCapture() { return this; }

View File

@@ -1703,6 +1703,9 @@ LambdaCaptureAST *LambdaCaptureAST::clone(MemoryPool *pool) const
CaptureAST *CaptureAST::clone(MemoryPool *pool) const CaptureAST *CaptureAST::clone(MemoryPool *pool) const
{ {
CaptureAST *ast = new (pool) CaptureAST; CaptureAST *ast = new (pool) CaptureAST;
ast->amper_token = amper_token;
if (identifier)
ast->identifier = identifier->clone(pool);
return ast; return ast;
} }

View File

@@ -2898,6 +2898,13 @@ bool ASTMatcher::match(CaptureAST *node, CaptureAST *pattern)
(void) node; (void) node;
(void) pattern; (void) pattern;
pattern->amper_token = node->amper_token;
if (! pattern->identifier)
pattern->identifier = node->identifier;
else if (! AST::match(node->identifier, pattern->identifier, this))
return false;
return true; return true;
} }

View File

@@ -1107,9 +1107,10 @@ public:
return __ast; return __ast;
} }
CaptureAST *Capture() CaptureAST *Capture(NameAST *identifier = 0)
{ {
CaptureAST *__ast = new (&pool) CaptureAST; CaptureAST *__ast = new (&pool) CaptureAST;
__ast->identifier = identifier;
return __ast; return __ast;
} }

View File

@@ -1237,6 +1237,7 @@ void LambdaCaptureAST::accept0(ASTVisitor *visitor)
void CaptureAST::accept0(ASTVisitor *visitor) void CaptureAST::accept0(ASTVisitor *visitor)
{ {
if (visitor->visit(this)) { if (visitor->visit(this)) {
accept(identifier, visitor);
} }
visitor->endVisit(this); visitor->endVisit(this);
} }

View File

@@ -1069,7 +1069,7 @@ void Bind::capture(CaptureAST *ast)
if (! ast) if (! ast)
return; return;
// See QTCREATORBUG-7968 name(ast->identifier);
} }
bool Bind::visit(LambdaDeclaratorAST *ast) bool Bind::visit(LambdaDeclaratorAST *ast)

View File

@@ -6294,43 +6294,56 @@ bool Parser::parseLambdaCapture(LambdaCaptureAST *&node)
return true; return true;
} }
bool Parser::parseCapture(CaptureAST *&) bool Parser::parseCapture(CaptureAST *&node)
{ {
// See QTCREATORBUG-7968
DEBUG_THIS_RULE(); DEBUG_THIS_RULE();
if (LA() == T_THIS) {
consumeToken();
return true;
}
if (LA() == T_AMPER)
consumeToken();
if (LA() == T_IDENTIFIER) { if (LA() == T_IDENTIFIER) {
consumeToken(); SimpleNameAST *ast = new (_pool) SimpleNameAST;
return true; ast->identifier_token = consumeToken();
} else if (LA() == T_AMPER && LA(2) == T_IDENTIFIER) { node = new (_pool) CaptureAST;
consumeToken(); node->identifier = ast;
consumeToken();
return true;
} else if (LA() == T_THIS) {
consumeToken();
return true; return true;
} }
return false; return false;
} }
bool Parser::parseCaptureList(CaptureListAST *&) bool Parser::parseCaptureList(CaptureListAST *&node)
{ {
DEBUG_THIS_RULE(); DEBUG_THIS_RULE();
CaptureAST *capture = 0; CaptureAST *capture = 0;
if (parseCapture(capture)) { if (parseCapture(capture)) {
node = new (_pool) CaptureListAST;
node->value = capture;
CaptureListAST **l = &node->next;
while (LA() == T_COMMA) { while (LA() == T_COMMA) {
consumeToken(); // consume `,' consumeToken(); // consume `,'
CaptureAST *capture = 0;
parseCapture(capture); parseCapture(capture);
if (capture) {
*l = new (_pool) CaptureListAST;
(*l)->value = capture;
l = &(*l)->next;
}
} }
return true;
} }
return true; return false;
} }
bool Parser::parseLambdaDeclarator(LambdaDeclaratorAST *&node) bool Parser::parseLambdaDeclarator(LambdaDeclaratorAST *&node)

View File

@@ -869,7 +869,7 @@ void FindUsages::capture(CaptureAST *ast)
if (! ast) if (! ast)
return; return;
// See QTCREATORBUG-7968 this->name(ast->identifier);
} }
bool FindUsages::visit(LambdaDeclaratorAST *ast) bool FindUsages::visit(LambdaDeclaratorAST *ast)

View File

@@ -127,6 +127,11 @@ protected:
return true; return true;
} }
virtual bool visit(CaptureAST *ast)
{
return checkLocalUse(ast->identifier, ast->firstToken());
}
virtual bool visit(IdExpressionAST *ast) virtual bool visit(IdExpressionAST *ast)
{ {
return checkLocalUse(ast->name, ast->firstToken()); return checkLocalUse(ast->name, ast->firstToken());

View File

@@ -77,7 +77,8 @@ class tst_FindUsages: public QObject
private Q_SLOTS: private Q_SLOTS:
void inlineMethod(); void inlineMethod();
// void lambdaArg(); void lambdaCaptureByValue();
void lambdaCaptureByReference();
// Qt keywords // Qt keywords
void qproperty_1(); void qproperty_1();
@@ -124,15 +125,46 @@ void tst_FindUsages::inlineMethod()
QCOMPARE(findUsages.references().size(), 2); QCOMPARE(findUsages.references().size(), 2);
} }
#if 0 /* see QTCREATORBUG-7968 */ void tst_FindUsages::lambdaCaptureByValue()
void tst_FindUsages::lambdaArg()
{ {
const QByteArray src = "\n" const QByteArray src = "\n"
"void f() {\n" "void f() {\n"
" int test;\n" " int test;\n"
" [test] { ++test; };\n" " [test] { ++test; };\n"
"}\n"; "}\n";
Document::Ptr doc = Document::create("lambdaArg"); Document::Ptr doc = Document::create("lambdaCaptureByValue");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 1U);
Snapshot snapshot;
snapshot.insert(doc);
Function *f = doc->globalSymbolAt(0)->asFunction();
QVERIFY(f);
QCOMPARE(f->memberCount(), 1U);
Block *b = f->memberAt(0)->asBlock();
QCOMPARE(b->memberCount(), 2U);
Declaration *d = b->memberAt(0)->asDeclaration();
QVERIFY(d);
QCOMPARE(d->name()->identifier()->chars(), "test");
FindUsages findUsages(src, doc, snapshot);
findUsages(d);
QCOMPARE(findUsages.usages().size(), 3);
}
void tst_FindUsages::lambdaCaptureByReference()
{
const QByteArray src = "\n"
"void f() {\n"
" int test;\n"
" [&test] { ++test; };\n"
"}\n";
Document::Ptr doc = Document::create("lambdaCaptureByReference");
doc->setUtf8Source(src); doc->setUtf8Source(src);
doc->parse(); doc->parse();
doc->check(); doc->check();
@@ -156,7 +188,6 @@ void tst_FindUsages::lambdaArg()
findUsages(d); findUsages(d);
QCOMPARE(findUsages.usages().size(), 3); QCOMPARE(findUsages.usages().size(), 3);
} }
#endif
#if 0 #if 0
@interface Clazz {} +(void)method:(int)arg; @end @interface Clazz {} +(void)method:(int)arg; @end

View File

@@ -1645,6 +1645,9 @@ virtual bool visit(LambdaCaptureAST *ast)
virtual bool visit(CaptureAST *ast) virtual bool visit(CaptureAST *ast)
{ {
if (ast->amper_token)
terminal(ast->amper_token, ast);
nonterminal(ast->identifier);
return false; return false;
} }