Files
qt-creator/tests/auto/cplusplus/findusages/tst_findusages.cpp
Christian Kandeler ff2322ac0b CPlusPlus: Fix mis-classification of pure virtuals
Syntactically, they do have an initializer, but they are not
initializations.

Change-Id: I0556b279ce2d173868585cbce085b803c1cff285
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
2020-12-03 09:09:52 +00:00

2292 lines
72 KiB
C++

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "../cplusplus_global.h"
#include <QtTest>
#include <QObject>
#include <QList>
#include <cplusplus/AST.h>
#include <cplusplus/ASTVisitor.h>
#include <cplusplus/CppDocument.h>
#include <cplusplus/FindUsages.h>
#include <cplusplus/Literals.h>
#include <cplusplus/LookupContext.h>
#include <cplusplus/Name.h>
#include <cplusplus/Overview.h>
#include <cplusplus/ResolveExpression.h>
#include <cplusplus/Symbols.h>
#include <cplusplus/TranslationUnit.h>
//TESTED_COMPONENT=src/libs/cplusplus
using namespace CPlusPlus;
class CollectNames: public ASTVisitor
{
public:
CollectNames(TranslationUnit *xUnit): ASTVisitor(xUnit) {}
QList<NameAST*> operator()(const char *name) {
_name = name;
_exprs.clear();
accept(translationUnit()->ast());
return _exprs;
}
virtual bool preVisit(AST *ast) {
if (NameAST *nameAst = ast->asName())
if (!qstrcmp(_name, nameAst->name->identifier()->chars()))
_exprs.append(nameAst);
return true;
}
private:
QList<NameAST*> _exprs;
const char *_name;
};
class tst_FindUsages: public QObject
{
Q_OBJECT
private:
void dump(const QList<Usage> &usages) const;
private Q_SLOTS:
void inlineMethod();
void lambdaCaptureByValue();
void lambdaCaptureByReference();
void shadowedNames_1();
void shadowedNames_2();
void staticVariables();
void functionNameFoundInArguments();
void memberFunctionFalsePositives_QTCREATORBUG2176();
void resolveTemplateConstructor();
void templateConstructorVsCallOperator();
// Qt keywords
void qproperty_1();
// Objective-C
void objc_args();
// void objc_methods();
// void objc_fields();
// void objc_classes();
// templates
void instantiateTemplateWithNestedClass();
void operatorAsteriskOfNestedClassOfTemplateClass_QTCREATORBUG9006();
void operatorArrowOfNestedClassOfTemplateClass_QTCREATORBUG9005();
void templateClassParameters();
void templateClass_className();
void templateFunctionParameters();
void anonymousClass_QTCREATORBUG8963();
void anonymousClass_QTCREATORBUG11859();
void using_insideGlobalNamespace();
void using_insideNamespace();
void using_insideFunction();
void templatedFunction_QTCREATORBUG9749();
void usingInDifferentNamespace_QTCREATORBUG7978();
void unicodeIdentifier();
void inAlignas();
void memberAccessAsTemplate();
void variadicFunctionTemplate();
void typeTemplateParameterWithDefault();
void resolveOrder_for_templateFunction_vs_function();
void templateArrowOperator_with_defaultType();
void templateSpecialization_with_IntArgument();
void templateSpecialization_with_BoolArgument();
void templatePartialSpecialization();
void templatePartialSpecialization_2();
void template_SFINAE_1();
void variableTemplateInExpression();
void variadicMacros();
void writableRefs();
};
void tst_FindUsages::dump(const QList<Usage> &usages) const
{
QTextStream err(stderr, QIODevice::WriteOnly);
err << "DEBUG : " << usages.size() << " usages:" << Qt::endl;
foreach (const Usage &usage, usages) {
err << "DEBUG : " << usage.path << ":" << usage.line << ":" << usage.col << ":"
<< usage.len << ":" << usage.lineText << Qt::endl;
}
}
void tst_FindUsages::inlineMethod()
{
const QByteArray src = "\n"
"class Tst {\n"
" int method(int arg) {\n"
" return arg;\n"
" }\n"
"};\n";
Document::Ptr doc = Document::create("inlineMethod");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 1);
Snapshot snapshot;
snapshot.insert(doc);
Class *tst = doc->globalSymbolAt(0)->asClass();
QVERIFY(tst);
QCOMPARE(tst->memberCount(), 1);
Function *method = tst->memberAt(0)->asFunction();
QVERIFY(method);
QCOMPARE(method->argumentCount(), 1);
Argument *arg = method->argumentAt(0)->asArgument();
QVERIFY(arg);
QCOMPARE(arg->identifier()->chars(), "arg");
FindUsages findUsages(src, doc, snapshot);
findUsages(arg);
QCOMPARE(findUsages.usages().size(), 2);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Read);
QCOMPARE(findUsages.references().size(), 2);
}
void tst_FindUsages::lambdaCaptureByValue()
{
const QByteArray src = "\n"
"void f() {\n"
" int test;\n"
" [test] { ++test; };\n"
"}\n";
Document::Ptr doc = Document::create("lambdaCaptureByValue");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 1);
Snapshot snapshot;
snapshot.insert(doc);
Function *f = doc->globalSymbolAt(0)->asFunction();
QVERIFY(f);
QCOMPARE(f->memberCount(), 1);
Block *b = f->memberAt(0)->asBlock();
QCOMPARE(b->memberCount(), 2);
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);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Read);
}
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->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 1);
Snapshot snapshot;
snapshot.insert(doc);
Function *f = doc->globalSymbolAt(0)->asFunction();
QVERIFY(f);
QCOMPARE(f->memberCount(), 1);
Block *b = f->memberAt(0)->asBlock();
QCOMPARE(b->memberCount(), 2);
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);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
QEXPECT_FAIL(nullptr, "parser does not record capture type", Continue);
QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Write);
}
void tst_FindUsages::shadowedNames_1()
{
const QByteArray src = "\n"
"int a();\n"
"struct X{ int a(); };\n"
"int X::a() {}\n"
"void f(X x) { x.a(); }\n"
"void g() { a(); }\n"
;
Document::Ptr doc = Document::create("shadowedNames_1");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 5);
Snapshot snapshot;
snapshot.insert(doc);
Declaration *d = doc->globalSymbolAt(0)->asDeclaration();
QVERIFY(d);
QCOMPARE(d->name()->identifier()->chars(), "a");
FindUsages findUsages(src, doc, snapshot);
findUsages(d);
QCOMPARE(findUsages.usages().size(), 2);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
}
void tst_FindUsages::shadowedNames_2()
{
const QByteArray src = "\n"
"int a();\n"
"struct X{ int a(); };\n"
"int X::a() {}\n"
"void f(X x) { x.a(); }\n"
"void g() { a(); }\n";
Document::Ptr doc = Document::create("shadowedNames_2");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 5);
Snapshot snapshot;
snapshot.insert(doc);
Class *c = doc->globalSymbolAt(1)->asClass();
QVERIFY(c);
QCOMPARE(c->name()->identifier()->chars(), "X");
QCOMPARE(c->memberCount(), 1);
Declaration *d = c->memberAt(0)->asDeclaration();
QVERIFY(d);
QCOMPARE(d->name()->identifier()->chars(), "a");
FindUsages findUsages(src, doc, snapshot);
findUsages(d);
QCOMPARE(findUsages.usages().size(), 3);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
}
void tst_FindUsages::staticVariables()
{
const QByteArray src = "\n"
"struct Outer\n"
"{\n"
" static int Foo;\n"
" struct Inner\n"
" {\n"
" Outer *outer;\n"
" void foo();\n"
" };\n"
"};\n"
"\n"
"int Outer::Foo = 42;\n"
"\n"
"void Outer::Inner::foo()\n"
"{\n"
" Foo = 7;\n"
" Outer::Foo = 7;\n"
" outer->Foo = 7;\n"
"}\n"
;
Document::Ptr doc = Document::create("staticVariables");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 3);
Snapshot snapshot;
snapshot.insert(doc);
Class *c = doc->globalSymbolAt(0)->asClass();
QVERIFY(c);
QCOMPARE(c->name()->identifier()->chars(), "Outer");
QCOMPARE(c->memberCount(), 2);
Declaration *d = c->memberAt(0)->asDeclaration();
QVERIFY(d);
QCOMPARE(d->name()->identifier()->chars(), "Foo");
FindUsages findUsages(src, doc, snapshot);
findUsages(d);
QCOMPARE(findUsages.usages().size(), 5);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Initialization);
QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Write);
QCOMPARE(findUsages.usages().at(3).type, Usage::Type::Write);
QCOMPARE(findUsages.usages().at(4).type, Usage::Type::Write);
}
void tst_FindUsages::functionNameFoundInArguments()
{
const QByteArray src =
R"(
void bar(); // call find usages for bar from here. This is 1st result
void foo(int bar); // should not be found
void foo(int bar){} // should not be found
void foo2(int b=bar()); // 2nd result
void foo2(int b=bar()){} // 3rd result
)";
Document::Ptr doc = Document::create("functionNameFoundInArguments");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QVERIFY(doc->globalSymbolCount() >= 1);
Symbol *s = doc->globalSymbolAt(0);
QCOMPARE(s->name()->identifier()->chars(), "bar");
Snapshot snapshot;
snapshot.insert(doc);
FindUsages find(src, doc, snapshot);
find(s);
QCOMPARE(find.usages().size(), 3);
QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
QCOMPARE(find.usages()[0].line, 1);
QCOMPARE(find.usages()[0].col, 5);
QCOMPARE(find.usages()[1].type, Usage::Type::Other);
QCOMPARE(find.usages()[1].line, 4);
QCOMPARE(find.usages()[1].col, 16);
QCOMPARE(find.usages()[2].type, Usage::Type::Other);
QCOMPARE(find.usages()[2].line, 5);
QCOMPARE(find.usages()[2].col, 16);
}
void tst_FindUsages::memberFunctionFalsePositives_QTCREATORBUG2176()
{
const QByteArray src =
R"(
void otherFunction(int value){}
struct Struct{
static int foo(){return 1;}
int bar(){
int foo=Struct::foo();
otherFunction(foo);
}
};
)";
Document::Ptr doc = Document::create("memberFunctionFalsePositives");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 2);
Class *s = doc->globalSymbolAt(1)->asClass();
QVERIFY(s);
QCOMPARE(s->name()->identifier()->chars(), "Struct");
QCOMPARE(s->memberCount(), 2);
Symbol *memberFunctionFoo = s->memberAt(0);
QVERIFY(memberFunctionFoo);
QCOMPARE(memberFunctionFoo->name()->identifier()->chars(), "foo");
QVERIFY(memberFunctionFoo->asFunction());
Function* bar = s->memberAt(1)->asFunction();
QVERIFY(bar);
QCOMPARE(bar->name()->identifier()->chars(), "bar");
QCOMPARE(bar->memberCount(), 1);
Block* block = bar->memberAt(0)->asBlock();
QVERIFY(block);
QCOMPARE(block->memberCount(), 1);
Symbol *variableFoo = block->memberAt(0);
QVERIFY(variableFoo);
QCOMPARE(variableFoo->name()->identifier()->chars(), "foo");
QVERIFY(variableFoo->asDeclaration());
Snapshot snapshot;
snapshot.insert(doc);
FindUsages find(src, doc, snapshot);
find(memberFunctionFoo);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
QCOMPARE(find.usages()[0].line, 3);
QCOMPARE(find.usages()[0].col, 15);
QCOMPARE(find.usages()[1].type, Usage::Type::Other);
QCOMPARE(find.usages()[1].line, 5);
QCOMPARE(find.usages()[1].col, 24);
find(variableFoo);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages()[0].type, Usage::Type::Initialization);
QCOMPARE(find.usages()[0].line, 5);
QCOMPARE(find.usages()[0].col, 12);
QCOMPARE(find.usages()[1].type, Usage::Type::Read);
QCOMPARE(find.usages()[1].line, 6);
QCOMPARE(find.usages()[1].col, 22);
}
void tst_FindUsages::resolveTemplateConstructor()
{
const QByteArray src =
R"(
struct MyStruct { int value; };
template <class T> struct Tmp {
T str;
};
template <class T> struct Tmp2 {
Tmp2(){}
T str;
};
template <class T> struct Tmp3 {
Tmp3(int i){}
T str;
};
int main() {
auto tmp = Tmp<MyStruct>();
auto tmp2 = Tmp2<MyStruct>();
auto tmp3 = Tmp3<MyStruct>(1);
tmp.str.value;
tmp2.str.value;
tmp3.str.value;
Tmp<MyStruct>().str.value;
Tmp2<MyStruct>().str.value;
Tmp3<MyStruct>(1).str.value;
}
)";
Document::Ptr doc = Document::create("resolveTemplateConstructor");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QVERIFY(doc->globalSymbolCount() == 5);
Class *s = doc->globalSymbolAt(0)->asClass();
QVERIFY(s);
QCOMPARE(s->name()->identifier()->chars(), "MyStruct");
QCOMPARE(s->memberCount(), 1);
Declaration *sv = s->memberAt(0)->asDeclaration();
QVERIFY(sv);
QCOMPARE(sv->name()->identifier()->chars(), "value");
Snapshot snapshot;
snapshot.insert(doc);
FindUsages find(src, doc, snapshot);
find(sv);
QCOMPARE(find.usages().size(), 7);
QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
QCOMPARE(find.usages().at(2).type, Usage::Type::Read);
QCOMPARE(find.usages().at(3).type, Usage::Type::Read);
QCOMPARE(find.usages().at(4).type, Usage::Type::Read);
QCOMPARE(find.usages().at(5).type, Usage::Type::Read);
QCOMPARE(find.usages().at(6).type, Usage::Type::Read);
}
void tst_FindUsages::templateConstructorVsCallOperator()
{
const QByteArray src =
R"(
struct MyStruct { int value; };
template<class T> struct Tmp {
T str;
MyStruct operator()() { return MyStruct(); }
};
struct Simple {
MyStruct str;
MyStruct operator()() { return MyStruct(); }
};
int main()
{
Tmp<MyStruct>().str.value;
Tmp<MyStruct>()().value;
Tmp<MyStruct> t;
t().value;
Simple().str.value;
Simple()().value;
Simple s;
s().value;
}
)";
Document::Ptr doc = Document::create("resolveTemplateConstructor");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QVERIFY(doc->globalSymbolCount() == 4);
Class *s = doc->globalSymbolAt(0)->asClass();
QVERIFY(s);
QCOMPARE(s->name()->identifier()->chars(), "MyStruct");
QCOMPARE(s->memberCount(), 1);
Declaration *sv = s->memberAt(0)->asDeclaration();
QVERIFY(sv);
QCOMPARE(sv->name()->identifier()->chars(), "value");
Snapshot snapshot;
snapshot.insert(doc);
FindUsages find(src, doc, snapshot);
find(sv);
QCOMPARE(find.usages().size(), 7);
QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
QCOMPARE(find.usages().at(2).type, Usage::Type::Read);
QCOMPARE(find.usages().at(3).type, Usage::Type::Read);
QCOMPARE(find.usages().at(4).type, Usage::Type::Read);
QCOMPARE(find.usages().at(5).type, Usage::Type::Read);
QCOMPARE(find.usages().at(6).type, Usage::Type::Read);
}
#if 0
@interface Clazz {} +(void)method:(int)arg; @end
@implementation Clazz +(void)method:(int)arg {
[Clazz method:arg];
}
@end
#endif
const QByteArray objcSource = "\n"
"@interface Clazz {} +(void)method:(int)arg; @end\n"
"@implementation Clazz +(void)method:(int)arg {\n"
" [Clazz method:arg];\n"
"}\n"
"@end\n";
void tst_FindUsages::objc_args()
{
Document::Ptr doc = Document::create("objc_args");
doc->setUtf8Source(objcSource);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 2);
Snapshot snapshot;
snapshot.insert(doc);
TranslationUnit *xUnit = doc->translationUnit();
QList<NameAST*>exprs = CollectNames(xUnit)("arg");
QCOMPARE(exprs.size(), 3);
ObjCClass *iface = doc->globalSymbolAt(0)->asObjCClass();
QVERIFY(iface);
QVERIFY(iface->isInterface());
QCOMPARE(iface->memberCount(), 1);
Declaration *methodIface = iface->memberAt(0)->asDeclaration();
QVERIFY(methodIface);
QCOMPARE(methodIface->identifier()->chars(), "method");
QVERIFY(methodIface->type()->isObjCMethodType());
ObjCClass *impl = doc->globalSymbolAt(1)->asObjCClass();
QVERIFY(impl);
QVERIFY(!impl->isInterface());
QCOMPARE(impl->memberCount(), 1);
ObjCMethod *methodImpl = impl->memberAt(0)->asObjCMethod();
QVERIFY(methodImpl);
QCOMPARE(methodImpl->identifier()->chars(), "method");
QCOMPARE(methodImpl->argumentCount(), 1);
Argument *arg = methodImpl->argumentAt(0)->asArgument();
QCOMPARE(arg->identifier()->chars(), "arg");
FindUsages findUsages(objcSource, doc, snapshot);
findUsages(arg);
QCOMPARE(findUsages.usages().size(), 2);
QCOMPARE(findUsages.references().size(), 2);
}
void tst_FindUsages::qproperty_1()
{
const QByteArray src = "\n"
"class Tst: public QObject {\n"
" Q_PROPERTY(int x READ x WRITE setX NOTIFY xChanged)\n"
"public:\n"
" int x() { return _x; }\n"
" void setX(int x) { if (_x != x) { _x = x; emit xChanged(x); } }\n"
"signals:\n"
" void xChanged(int);\n"
"private:\n"
" int _x;\n"
"};\n";
Document::Ptr doc = Document::create("qproperty_1");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 1);
Snapshot snapshot;
snapshot.insert(doc);
Class *tst = doc->globalSymbolAt(0)->asClass();
QVERIFY(tst);
QCOMPARE(tst->memberCount(), 5);
Function *setX_method = tst->memberAt(2)->asFunction();
QVERIFY(setX_method);
QCOMPARE(setX_method->identifier()->chars(), "setX");
QCOMPARE(setX_method->argumentCount(), 1);
FindUsages findUsages(src, doc, snapshot);
findUsages(setX_method);
QCOMPARE(findUsages.usages().size(), 2);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Declaration);
QCOMPARE(findUsages.references().size(), 2);
}
void tst_FindUsages::instantiateTemplateWithNestedClass()
{
const QByteArray src = "\n"
"struct Foo\n"
"{ int bar; };\n"
"template <typename T>\n"
"struct Template\n"
"{\n"
" struct Nested\n"
" {\n"
" T t;\n"
" }nested;\n"
"};\n"
"void f()\n"
"{\n"
" Template<Foo> templateFoo;\n"
" templateFoo.nested.t.bar;\n"
"}\n"
;
Document::Ptr doc = Document::create("simpleTemplate");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 3);
Snapshot snapshot;
snapshot.insert(doc);
Class *classFoo = doc->globalSymbolAt(0)->asClass();
QVERIFY(classFoo);
QCOMPARE(classFoo->memberCount(), 1);
Declaration *barDeclaration = classFoo->memberAt(0)->asDeclaration();
QVERIFY(barDeclaration);
QCOMPARE(barDeclaration->name()->identifier()->chars(), "bar");
FindUsages findUsages(src, doc, snapshot);
findUsages(barDeclaration);
QCOMPARE(findUsages.usages().size(), 2);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Read);
}
void tst_FindUsages::operatorAsteriskOfNestedClassOfTemplateClass_QTCREATORBUG9006()
{
const QByteArray src = "\n"
"struct Foo { int foo; };\n"
"\n"
"template<class T>\n"
"struct Outer\n"
"{\n"
" struct Nested\n"
" {\n"
" const T &operator*() { return t; }\n"
" T t;\n"
" };\n"
"};\n"
"\n"
"void bug()\n"
"{\n"
" Outer<Foo>::Nested nested;\n"
" (*nested).foo;\n"
"}\n"
;
Document::Ptr doc = Document::create("operatorAsteriskOfNestedClassOfTemplateClass_QTCREATORBUG9006");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 3);
Snapshot snapshot;
snapshot.insert(doc);
Class *classFoo = doc->globalSymbolAt(0)->asClass();
QVERIFY(classFoo);
QCOMPARE(classFoo->memberCount(), 1);
Declaration *fooDeclaration = classFoo->memberAt(0)->asDeclaration();
QVERIFY(fooDeclaration);
QCOMPARE(fooDeclaration->name()->identifier()->chars(), "foo");
FindUsages findUsages(src, doc, snapshot);
findUsages(fooDeclaration);
QCOMPARE(findUsages.usages().size(), 2);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Read);
}
void tst_FindUsages::anonymousClass_QTCREATORBUG8963()
{
const QByteArray src =
"typedef enum {\n"
" FIRST\n"
"} isNotInt;\n"
"typedef struct {\n"
" int isint;\n"
" int isNotInt;\n"
"} Struct;\n"
"void foo()\n"
"{\n"
" Struct s;\n"
" s.isint;\n"
" s.isNotInt;\n"
" FIRST;\n"
"}\n"
;
Document::Ptr doc = Document::create("anonymousClass_QTCREATORBUG8963");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 5);
Snapshot snapshot;
snapshot.insert(doc);
Class *structSymbol = doc->globalSymbolAt(2)->asClass();
QVERIFY(structSymbol);
QCOMPARE(structSymbol->memberCount(), 2);
Declaration *isNotIntDeclaration = structSymbol->memberAt(1)->asDeclaration();
QVERIFY(isNotIntDeclaration);
QCOMPARE(isNotIntDeclaration->name()->identifier()->chars(), "isNotInt");
FindUsages findUsages(src, doc, snapshot);
findUsages(isNotIntDeclaration);
QCOMPARE(findUsages.usages().size(), 2);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Read);
}
void tst_FindUsages::anonymousClass_QTCREATORBUG11859()
{
const QByteArray src =
"struct Foo {\n"
"};\n"
"typedef struct {\n"
" int Foo;\n"
"} Struct;\n"
"void foo()\n"
"{\n"
" Struct s;\n"
" s.Foo;\n"
"}\n"
;
Document::Ptr doc = Document::create("anonymousClass_QTCREATORBUG11859");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 4);
Snapshot snapshot;
snapshot.insert(doc);
Class *fooAsStruct = doc->globalSymbolAt(0)->asClass();
QVERIFY(fooAsStruct);
Class *structSymbol = doc->globalSymbolAt(1)->asClass();
QVERIFY(structSymbol);
QCOMPARE(structSymbol->memberCount(), 1);
Declaration *fooAsMemberOfAnonymousStruct = structSymbol->memberAt(0)->asDeclaration();
QVERIFY(fooAsMemberOfAnonymousStruct);
QCOMPARE(fooAsMemberOfAnonymousStruct->name()->identifier()->chars(), "Foo");
FindUsages findUsages(src, doc, snapshot);
findUsages(fooAsStruct);
QCOMPARE(findUsages.references().size(), 1);
QCOMPARE(findUsages.usages().size(), 1);
QCOMPARE(findUsages.usages().first().type, Usage::Type::Declaration);
findUsages(fooAsMemberOfAnonymousStruct);
QCOMPARE(findUsages.references().size(), 2);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Read);
}
void tst_FindUsages::using_insideGlobalNamespace()
{
const QByteArray src =
"namespace NS\n"
"{\n"
"struct Struct\n"
"{\n"
" int bar;\n"
"};\n"
"}\n"
"using NS::Struct;\n"
"void foo()\n"
"{\n"
" Struct s;\n"
"}\n"
;
Document::Ptr doc = Document::create("using_insideGlobalNamespace");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 3);
Snapshot snapshot;
snapshot.insert(doc);
Namespace *nsSymbol = doc->globalSymbolAt(0)->asNamespace();
QVERIFY(nsSymbol);
QCOMPARE(nsSymbol->memberCount(), 1);
Class *structSymbol = nsSymbol->memberAt(0)->asClass();
QVERIFY(structSymbol);
FindUsages findUsages(src, doc, snapshot);
findUsages(structSymbol);
QCOMPARE(findUsages.usages().size(), 3);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
}
void tst_FindUsages::using_insideNamespace()
{
const QByteArray src =
"namespace NS\n"
"{\n"
"struct Struct\n"
"{\n"
" int bar;\n"
"};\n"
"}\n"
"namespace NS1\n"
"{\n"
"using NS::Struct;\n"
"void foo()\n"
"{\n"
" Struct s;\n"
"}\n"
"}\n"
;
Document::Ptr doc = Document::create("using_insideNamespace");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 2);
Snapshot snapshot;
snapshot.insert(doc);
Namespace *nsSymbol = doc->globalSymbolAt(0)->asNamespace();
QVERIFY(nsSymbol);
QCOMPARE(nsSymbol->memberCount(), 1);
Class *structSymbol = nsSymbol->memberAt(0)->asClass();
QVERIFY(structSymbol);
FindUsages findUsages(src, doc, snapshot);
findUsages(structSymbol);
QCOMPARE(findUsages.usages().size(), 3);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
}
void tst_FindUsages::using_insideFunction()
{
const QByteArray src =
"namespace NS\n"
"{\n"
"struct Struct\n"
"{\n"
" int bar;\n"
"};\n"
"}\n"
"void foo()\n"
"{\n"
" using NS::Struct;\n"
" Struct s;\n"
"}\n"
;
Document::Ptr doc = Document::create("using_insideFunction");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 2);
Snapshot snapshot;
snapshot.insert(doc);
Namespace *nsSymbol = doc->globalSymbolAt(0)->asNamespace();
QVERIFY(nsSymbol);
QCOMPARE(nsSymbol->memberCount(), 1);
Class *structSymbol = nsSymbol->memberAt(0)->asClass();
QVERIFY(structSymbol);
FindUsages findUsages(src, doc, snapshot);
findUsages(structSymbol);
QCOMPARE(findUsages.usages().size(), 3);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
}
void tst_FindUsages::operatorArrowOfNestedClassOfTemplateClass_QTCREATORBUG9005()
{
const QByteArray src = "\n"
"struct Foo { int foo; };\n"
"\n"
"template<class T>\n"
"struct Outer\n"
"{\n"
" struct Nested\n"
" {\n"
" T *operator->() { return 0; }\n"
" };\n"
"};\n"
"\n"
"void bug()\n"
"{\n"
" Outer<Foo>::Nested nested;\n"
" nested->foo;\n"
"}\n"
;
Document::Ptr doc = Document::create("operatorArrowOfNestedClassOfTemplateClass_QTCREATORBUG9005");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 3);
Snapshot snapshot;
snapshot.insert(doc);
Class *classFoo = doc->globalSymbolAt(0)->asClass();
QVERIFY(classFoo);
QCOMPARE(classFoo->memberCount(), 1);
Declaration *fooDeclaration = classFoo->memberAt(0)->asDeclaration();
QVERIFY(fooDeclaration);
QCOMPARE(fooDeclaration->name()->identifier()->chars(), "foo");
FindUsages findUsages(src, doc, snapshot);
findUsages(fooDeclaration);
QCOMPARE(findUsages.usages().size(), 2);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Read);
}
void tst_FindUsages::templateClassParameters()
{
const QByteArray src = "\n"
"template <class T>\n"
"struct TS\n"
"{\n"
" void set(T t) { T t1 = t; }\n"
" T get();\n"
" T t;\n"
"};\n"
;
Document::Ptr doc = Document::create("templateClassParameters");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 1);
Snapshot snapshot;
snapshot.insert(doc);
Template *templateClassTS = doc->globalSymbolAt(0)->asTemplate();
QVERIFY(templateClassTS);
QCOMPARE(templateClassTS->memberCount(), 2);
QCOMPARE(templateClassTS->templateParameterCount(), 1);
TypenameArgument *templArgument = templateClassTS->templateParameterAt(0)->asTypenameArgument();
QVERIFY(templArgument);
FindUsages findUsages(src, doc, snapshot);
findUsages(templArgument);
QCOMPARE(findUsages.usages().size(), 5);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(3).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(4).type, Usage::Type::Other);
}
void tst_FindUsages::templateClass_className()
{
const QByteArray src = "\n"
"template <class T>\n"
"struct TS\n"
"{\n"
" TS();\n"
" ~TS();\n"
"};\n"
"template <class T>\n"
"TS<T>::TS()\n"
"{\n"
"}\n"
"template <class T>\n"
"TS<T>::~TS()\n"
"{\n"
"}\n"
;
Document::Ptr doc = Document::create("templateClass_className");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 3);
Snapshot snapshot;
snapshot.insert(doc);
Template *templateClassTS = doc->globalSymbolAt(0)->asTemplate();
QVERIFY(templateClassTS);
Class *classTS = templateClassTS->memberAt(1)->asClass();
QVERIFY(classTS);
QCOMPARE(classTS->memberCount(), 2);
FindUsages findUsages(src, doc, snapshot);
findUsages(classTS);
QCOMPARE(findUsages.usages().size(), 7);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(3).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(4).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(5).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(6).type, Usage::Type::Other);
}
void tst_FindUsages::templateFunctionParameters()
{
const QByteArray src = "\n"
"template<class T>\n"
"T foo(T t)\n"
"{\n"
" typename T;\n"
"}\n"
;
Document::Ptr doc = Document::create("templateFunctionParameters");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 1);
Snapshot snapshot;
snapshot.insert(doc);
Template *templateFunctionTS = doc->globalSymbolAt(0)->asTemplate();
QVERIFY(templateFunctionTS);
QCOMPARE(templateFunctionTS->memberCount(), 2);
QCOMPARE(templateFunctionTS->templateParameterCount(), 1);
TypenameArgument *templArgument = templateFunctionTS->templateParameterAt(0)->asTypenameArgument();
QVERIFY(templArgument);
FindUsages findUsages(src, doc, snapshot);
findUsages(templArgument);
QCOMPARE(findUsages.usages().size(), 4);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(3).type, Usage::Type::Other);
}
void tst_FindUsages::templatedFunction_QTCREATORBUG9749()
{
const QByteArray src = "\n"
"template <class IntType> char *reformatInteger(IntType value, int format) {}\n"
"void func(int code, int format) {\n"
" reformatInteger(code, format);"
"}\n"
;
Document::Ptr doc = Document::create("templatedFunction_QTCREATORBUG9749");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 2);
Snapshot snapshot;
snapshot.insert(doc);
Template *funcTempl = doc->globalSymbolAt(0)->asTemplate();
QVERIFY(funcTempl);
QCOMPARE(funcTempl->memberCount(), 2);
Function *func = funcTempl->memberAt(1)->asFunction();
FindUsages findUsages(src, doc, snapshot);
findUsages(func);
QCOMPARE(findUsages.usages().size(), 2);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
}
void tst_FindUsages::usingInDifferentNamespace_QTCREATORBUG7978()
{
const QByteArray src = "\n"
"struct S {};\n"
"namespace std\n"
"{\n"
" template <typename T> struct shared_ptr{};\n"
"}\n"
"namespace NS\n"
"{\n"
" using std::shared_ptr;\n"
"}\n"
"void fun()\n"
"{\n"
" NS::shared_ptr<S> p;\n"
"}\n"
;
Document::Ptr doc = Document::create("usingInDifferentNamespace_QTCREATORBUG7978");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 4);
Snapshot snapshot;
snapshot.insert(doc);
Namespace *ns = doc->globalSymbolAt(1)->asNamespace();
QVERIFY(ns);
QCOMPARE(ns->memberCount(), 1);
Template *templateClass = ns->memberAt(0)->asTemplate();
FindUsages findUsages(src, doc, snapshot);
findUsages(templateClass);
QCOMPARE(findUsages.usages().size(), 3);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Other);
QCOMPARE(findUsages.usages().at(2).type, Usage::Type::Other);
}
void tst_FindUsages::unicodeIdentifier()
{
const QByteArray src = "\n"
"int var" TEST_UNICODE_IDENTIFIER ";\n"
"void f() { var" TEST_UNICODE_IDENTIFIER " = 1; }\n";
;
Document::Ptr doc = Document::create("u");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 2);
Snapshot snapshot;
snapshot.insert(doc);
Declaration *declaration = doc->globalSymbolAt(0)->asDeclaration();
QVERIFY(declaration);
FindUsages findUsages(src, doc, snapshot);
findUsages(declaration);
const QList<Usage> usages = findUsages.usages();
QCOMPARE(usages.size(), 2);
QCOMPARE(findUsages.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(findUsages.usages().at(1).type, Usage::Type::Write);
QCOMPARE(usages.at(0).len, 7);
QCOMPARE(usages.at(1).len, 7);
}
void tst_FindUsages::inAlignas()
{
const QByteArray src = "\n"
"struct One {};\n"
"struct alignas(One) Two {};\n"
;
Document::Ptr doc = Document::create("inAlignas");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 2);
Snapshot snapshot;
snapshot.insert(doc);
Class *c = doc->globalSymbolAt(0)->asClass();
QVERIFY(c);
QCOMPARE(c->name()->identifier()->chars(), "One");
FindUsages find(src, doc, snapshot);
find(c);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
QCOMPARE(find.usages()[0].line, 1);
QCOMPARE(find.usages()[0].col, 7);
QCOMPARE(find.usages()[1].type, Usage::Type::Other);
QCOMPARE(find.usages()[1].line, 2);
QCOMPARE(find.usages()[1].col, 15);
}
void tst_FindUsages::memberAccessAsTemplate()
{
const QByteArray src = "\n"
"struct Foo {};\n"
"struct Bar {\n"
" template <typename T>\n"
" T *templateFunc() { return 0; }\n"
"};\n"
"struct Test {\n"
" Bar member;\n"
" void testFunc();\n"
"};\n"
"void Test::testFunc() {\n"
" member.templateFunc<Foo>();\n"
"}\n";
Document::Ptr doc = Document::create("memberAccessAsTemplate");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 4);
Snapshot snapshot;
snapshot.insert(doc);
{ // Test "Foo"
Class *c = doc->globalSymbolAt(0)->asClass();
QVERIFY(c);
QCOMPARE(c->name()->identifier()->chars(), "Foo");
FindUsages find(src, doc, snapshot);
find(c);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
QCOMPARE(find.usages()[0].line, 1);
QCOMPARE(find.usages()[0].col, 7);
QCOMPARE(find.usages()[1].type, Usage::Type::Other);
QCOMPARE(find.usages()[1].line, 11);
QCOMPARE(find.usages()[1].col, 24);
}
{ // Test "templateFunc"
Class *c = doc->globalSymbolAt(1)->asClass();
QVERIFY(c);
QCOMPARE(c->name()->identifier()->chars(), "Bar");
QCOMPARE(c->memberCount(), 1);
Template *f = c->memberAt(0)->asTemplate();
QVERIFY(f);
QCOMPARE(f->name()->identifier()->chars(), "templateFunc");
FindUsages find(src, doc, snapshot);
find(f);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages()[0].type, Usage::Type::Declaration);
QCOMPARE(find.usages()[0].line, 4);
QCOMPARE(find.usages()[0].col, 7);
QCOMPARE(find.usages()[1].type, Usage::Type::Other);
QCOMPARE(find.usages()[1].line, 11);
QCOMPARE(find.usages()[1].col, 11);
}
}
void tst_FindUsages::variadicFunctionTemplate()
{
const QByteArray src = "struct S{int value;};\n"
"template<class ... Types> S foo(Types & ... args){return S();}\n"
"int main(){\n"
" foo().value;\n"
" foo(1).value;\n"
" foo(1,2).value;\n"
"}";
Document::Ptr doc = Document::create("variadicFunctionTemplate");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QVERIFY(doc->globalSymbolCount()>=1);
Snapshot snapshot;
snapshot.insert(doc);
{ // Test "S::value"
Class *c = doc->globalSymbolAt(0)->asClass();
QVERIFY(c);
QCOMPARE(c->name()->identifier()->chars(), "S");
QCOMPARE(c->memberCount(), 1);
Declaration *v = c->memberAt(0)->asDeclaration();
QVERIFY(v);
QCOMPARE(v->name()->identifier()->chars(), "value");
FindUsages find(src, doc, snapshot);
find(v);
QCOMPARE(find.usages().size(), 4);
QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
QCOMPARE(find.usages().at(2).type, Usage::Type::Read);
QCOMPARE(find.usages().at(3).type, Usage::Type::Read);
}
}
void tst_FindUsages::typeTemplateParameterWithDefault()
{
const QByteArray src = "struct X{int value;};\n"
"struct S{int value;};\n"
"template<class T = S> T foo(){return T();}\n"
"int main(){\n"
" foo<X>().value;\n"
" foo<S>().value;\n"
" foo().value;\n" // this is S.value
"}";
Document::Ptr doc = Document::create("typeTemplateParameterWithDefault");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QVERIFY(doc->globalSymbolCount()>=2);
Snapshot snapshot;
snapshot.insert(doc);
{ // Test "S::value"
Class *x = doc->globalSymbolAt(0)->asClass();
QVERIFY(x);
QCOMPARE(x->name()->identifier()->chars(), "X");
QCOMPARE(x->memberCount(), 1);
Class *s = doc->globalSymbolAt(1)->asClass();
QVERIFY(s);
QCOMPARE(s->name()->identifier()->chars(), "S");
QCOMPARE(s->memberCount(), 1);
Declaration *xv = x->memberAt(0)->asDeclaration();
QVERIFY(xv);
QCOMPARE(xv->name()->identifier()->chars(), "value");
Declaration *sv = s->memberAt(0)->asDeclaration();
QVERIFY(sv);
QCOMPARE(sv->name()->identifier()->chars(), "value");
FindUsages find(src, doc, snapshot);
find(xv);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
find(sv);
QCOMPARE(find.usages().size(), 3);
QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
QCOMPARE(find.usages().at(2).type, Usage::Type::Read);
}
}
void tst_FindUsages::resolveOrder_for_templateFunction_vs_function()
{
const QByteArray src = "struct X{int value;};\n"
"struct S{int value;};\n"
"X foo(){return X();}\n"
"template<class T = S> T foo(){return T();}\n"
"int main(){\n"
" foo().value;\n" // this is X.value
"}";
Document::Ptr doc = Document::create("resolveOrder_for_templateFunction_vs_function");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QVERIFY(doc->globalSymbolCount()>=1);
Snapshot snapshot;
snapshot.insert(doc);
{ // Test "S::value"
Class *x = doc->globalSymbolAt(0)->asClass();
QVERIFY(x);
QCOMPARE(x->name()->identifier()->chars(), "X");
QCOMPARE(x->memberCount(), 1);
Declaration *xv = x->memberAt(0)->asDeclaration();
QVERIFY(xv);
QCOMPARE(xv->name()->identifier()->chars(), "value");
FindUsages find(src, doc, snapshot);
find(xv);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
}
}
void tst_FindUsages::templateArrowOperator_with_defaultType()
{
const QByteArray src = "struct S{int value;};\n"
"struct C{\n"
" S* s;\n"
" template<class T = S> \n"
" T* operator->(){return &s;}\n"
"};\n"
"int main(){\n"
" C().operator -> ()->value;\n"
" C()->value;\n"
"}\n";
Document::Ptr doc = Document::create("templateArrowOperator_with_defaultType");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QVERIFY(doc->globalSymbolCount()>=1);
Snapshot snapshot;
snapshot.insert(doc);
{ // Test "S::value"
Class *s = doc->globalSymbolAt(0)->asClass();
QVERIFY(s);
QCOMPARE(s->name()->identifier()->chars(), "S");
QCOMPARE(s->memberCount(), 1);
Declaration *sv = s->memberAt(0)->asDeclaration();
QVERIFY(sv);
QCOMPARE(sv->name()->identifier()->chars(), "value");
FindUsages find(src, doc, snapshot);
find(sv);
QCOMPARE(find.usages().size(), 3);
QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
QCOMPARE(find.usages().at(2).type, Usage::Type::Read);
}
}
void tst_FindUsages::templateSpecialization_with_IntArgument()
{
const QByteArray src = "\n"
"struct S0{ int value = 0; };\n"
"struct S1{ int value = 1; };\n"
"struct S2{ int value = 2; };\n"
"template<int N> struct S { S0 s; };\n"
"template<> struct S<1> { S1 s; };\n"
"template<> struct S<2> { S2 s; };\n"
"int main()\n"
"{\n"
" S<0> s0;\n"
" S<1> s1;\n"
" S<2> s2;\n"
" s0.s.value;\n"
" s1.s.value;\n"
" s2.s.value = s2.s.value;\n"
"}\n";
Document::Ptr doc = Document::create("templateSpecialization_with_IntArgument");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QVERIFY(doc->globalSymbolCount()>=3);
Snapshot snapshot;
snapshot.insert(doc);
{
Class *s[3] = {
doc->globalSymbolAt(0)->asClass(),
doc->globalSymbolAt(1)->asClass(),
doc->globalSymbolAt(2)->asClass(),
};
QVERIFY(s[0]);
QVERIFY(s[1]);
QVERIFY(s[2]);
QCOMPARE(s[0]->name()->identifier()->chars(), "S0");
QCOMPARE(s[1]->name()->identifier()->chars(), "S1");
QCOMPARE(s[2]->name()->identifier()->chars(), "S2");
QCOMPARE(s[0]->memberCount(), 1);
QCOMPARE(s[1]->memberCount(), 1);
QCOMPARE(s[2]->memberCount(), 1);
Declaration *sv[3] = {
s[0]->memberAt(0)->asDeclaration(),
s[1]->memberAt(0)->asDeclaration(),
s[2]->memberAt(0)->asDeclaration(),
};
QVERIFY(sv[0]);
QVERIFY(sv[1]);
QVERIFY(sv[2]);
QCOMPARE(sv[0]->name()->identifier()->chars(), "value");
QCOMPARE(sv[1]->name()->identifier()->chars(), "value");
QCOMPARE(sv[2]->name()->identifier()->chars(), "value");
FindUsages find(src, doc, snapshot);
find(sv[0]);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages()[0].line, 1);
QCOMPARE(find.usages()[0].col, 15);
QCOMPARE(find.usages()[1].line, 12);
QCOMPARE(find.usages()[1].col, 9);
find(sv[1]);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages()[0].type, Usage::Type::Initialization);
QCOMPARE(find.usages()[0].line, 2);
QCOMPARE(find.usages()[0].col, 15);
QCOMPARE(find.usages()[1].type, Usage::Type::Read);
QCOMPARE(find.usages()[1].line, 13);
QCOMPARE(find.usages()[1].col, 9);
find(sv[2]);
QCOMPARE(find.usages().size(), 3);
QCOMPARE(find.usages()[0].type, Usage::Type::Initialization);
QCOMPARE(find.usages()[0].line, 3);
QCOMPARE(find.usages()[0].col, 15);
QCOMPARE(find.usages()[1].type, Usage::Type::Write);
QCOMPARE(find.usages()[1].line, 14);
QCOMPARE(find.usages()[1].col, 9);
QCOMPARE(find.usages()[2].type, Usage::Type::Read);
QCOMPARE(find.usages()[2].line, 14);
QCOMPARE(find.usages()[2].col, 22);
}
}
void tst_FindUsages::templateSpecialization_with_BoolArgument()
{
const QByteArray src = "\n"
"struct S0{ int value = 0; };\n"
"struct S1{ int value = 1; };\n"
"template<bool B> struct S { S0 s; };\n"
"template<> struct S<true> { S1 s; };\n"
"int main()\n"
"{\n"
" S<false> s0;\n"
" S<true> s1;\n"
" s0.s.value;\n"
" s1.s.value;\n"
"}\n";
Document::Ptr doc = Document::create("templateSpecialization_with_BoolArgument");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QVERIFY(doc->globalSymbolCount()>=3);
Snapshot snapshot;
snapshot.insert(doc);
{
Class *s[2] = {
doc->globalSymbolAt(0)->asClass(),
doc->globalSymbolAt(1)->asClass(),
};
QVERIFY(s[0]);
QVERIFY(s[1]);
QCOMPARE(s[0]->name()->identifier()->chars(), "S0");
QCOMPARE(s[1]->name()->identifier()->chars(), "S1");
QCOMPARE(s[0]->memberCount(), 1);
QCOMPARE(s[1]->memberCount(), 1);
Declaration *sv[2] = {
s[0]->memberAt(0)->asDeclaration(),
s[1]->memberAt(0)->asDeclaration(),
};
QVERIFY(sv[0]);
QVERIFY(sv[1]);
QCOMPARE(sv[0]->name()->identifier()->chars(), "value");
QCOMPARE(sv[1]->name()->identifier()->chars(), "value");
FindUsages find(src, doc, snapshot);
find(sv[0]);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages()[0].type, Usage::Type::Initialization);
QCOMPARE(find.usages()[0].line, 1);
QCOMPARE(find.usages()[0].col, 15);
QCOMPARE(find.usages()[1].type, Usage::Type::Read);
QCOMPARE(find.usages()[1].line, 9);
QCOMPARE(find.usages()[1].col, 9);
find(sv[1]);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages()[0].type, Usage::Type::Initialization);
QCOMPARE(find.usages()[0].line, 2);
QCOMPARE(find.usages()[0].col, 15);
QCOMPARE(find.usages()[1].type, Usage::Type::Read);
QCOMPARE(find.usages()[1].line, 10);
QCOMPARE(find.usages()[1].col, 9);
}
}
void tst_FindUsages::templatePartialSpecialization()
{
const QByteArray src = "\n"
"struct S0{ int value = 0; };\n"
"struct S1{ int value = 1; };\n"
"template<class T, class U> struct S { S0 ss; };\n"
"template<class U> struct S<float, U> { S1 ss; };\n"
"int main()\n"
"{\n"
" S<int, int> s0;\n"
" S<float, int> s1;\n"
" s0.ss.value;\n"
" s1.ss.value;\n"
"}\n";
Document::Ptr doc = Document::create("templatePartialSpecialization");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QVERIFY(doc->globalSymbolCount()>=3);
Snapshot snapshot;
snapshot.insert(doc);
{
Class *s[2] = {
doc->globalSymbolAt(0)->asClass(),
doc->globalSymbolAt(1)->asClass(),
};
QVERIFY(s[0]);
QVERIFY(s[1]);
QCOMPARE(s[0]->name()->identifier()->chars(), "S0");
QCOMPARE(s[1]->name()->identifier()->chars(), "S1");
QCOMPARE(s[0]->memberCount(), 1);
QCOMPARE(s[1]->memberCount(), 1);
Declaration *sv[2] = {
s[0]->memberAt(0)->asDeclaration(),
s[1]->memberAt(0)->asDeclaration(),
};
QVERIFY(sv[0]);
QVERIFY(sv[1]);
QCOMPARE(sv[0]->name()->identifier()->chars(), "value");
QCOMPARE(sv[1]->name()->identifier()->chars(), "value");
FindUsages find(src, doc, snapshot);
find(sv[0]);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages()[0].type, Usage::Type::Initialization);
QCOMPARE(find.usages()[0].line, 1);
QCOMPARE(find.usages()[0].col, 15);
QCOMPARE(find.usages()[1].type, Usage::Type::Read);
QCOMPARE(find.usages()[1].line, 9);
QCOMPARE(find.usages()[1].col, 10);
find(sv[1]);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages()[0].type, Usage::Type::Initialization);
QCOMPARE(find.usages()[0].line, 2);
QCOMPARE(find.usages()[0].col, 15);
QCOMPARE(find.usages()[1].type, Usage::Type::Read);
QCOMPARE(find.usages()[1].line, 10);
QCOMPARE(find.usages()[1].col, 10);
}
}
void tst_FindUsages::templatePartialSpecialization_2()
{
const QByteArray src =
R"(
struct S0{int value=0;};
struct S1{int value=1;};
struct S2{int value=2;};
template<class T1, class T2> struct S{T1 ss;};
template<class U> struct S<int, U>{ U ss; };
template<class V> struct S<V*, int>{ V *ss; };
int main()
{
S<S0, float> s0;
s0.ss.value;
S<int, S1> s1;
s1.ss.value;
S<S2*, int> s2;
s2.ss->value;
}
)";
Document::Ptr doc = Document::create("templatePartialSpecialization_2");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QVERIFY(doc->globalSymbolCount()>=3);
Snapshot snapshot;
snapshot.insert(doc);
FindUsages find(src, doc, snapshot);
Class *s[3];
Declaration *sv[3];
for (int i = 0; i < 3; i++) {
s[i] = doc->globalSymbolAt(i)->asClass();
QVERIFY(s[i]);
QCOMPARE(s[i]->memberCount(), 1);
sv[i] = s[i]->memberAt(0)->asDeclaration();
QVERIFY(sv[i]);
QCOMPARE(sv[i]->name()->identifier()->chars(), "value");
}
QCOMPARE(s[0]->name()->identifier()->chars(), "S0");
QCOMPARE(s[1]->name()->identifier()->chars(), "S1");
QCOMPARE(s[2]->name()->identifier()->chars(), "S2");
find(sv[0]);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages().at(0).type, Usage::Type::Initialization);
QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
find(sv[1]);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages().at(0).type, Usage::Type::Initialization);
QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
find(sv[2]);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages().at(0).type, Usage::Type::Initialization);
QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
}
void tst_FindUsages::template_SFINAE_1()
{
const QByteArray src =
R"(
struct S{int value=1;};
template<class, class> struct is_same {};
template<class T> struct is_same<T, T> {using type = int;};
template<class T = S, typename is_same<T, S>::type = 0> T* foo(){return new T();}
int main(){
foo()->value;
}
)";
Document::Ptr doc = Document::create("template_SFINAE_1");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QVERIFY(doc->globalSymbolCount()>=1);
Snapshot snapshot;
snapshot.insert(doc);
Class *s = doc->globalSymbolAt(0)->asClass();
QVERIFY(s);
QCOMPARE(s->name()->identifier()->chars(), "S");
QCOMPARE(s->memberCount(), 1);
Declaration *sv = s->memberAt(0)->asDeclaration();
QVERIFY(sv);
QCOMPARE(sv->name()->identifier()->chars(), "value");
FindUsages find(src, doc, snapshot);
find(sv);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages().at(0).type, Usage::Type::Initialization);
QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
}
void tst_FindUsages::variableTemplateInExpression()
{
const QByteArray src =
R"(
struct S{int value;};
template<class T> constexpr int foo = sizeof(T);
template<class T1, class T2>
struct pair{
pair() noexcept(foo<T1> + foo<T2>){}
T1 first;
T2 second;
};
int main(){
pair<int, S> pair;
pair.second.value;
}
)";
Document::Ptr doc = Document::create("variableTemplateInExpression");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QVERIFY(doc->globalSymbolCount()>=1);
Snapshot snapshot;
snapshot.insert(doc);
Class *s = doc->globalSymbolAt(0)->asClass();
QVERIFY(s);
QCOMPARE(s->name()->identifier()->chars(), "S");
QCOMPARE(s->memberCount(), 1);
Declaration *sv = s->memberAt(0)->asDeclaration();
QVERIFY(sv);
QCOMPARE(sv->name()->identifier()->chars(), "value");
FindUsages find(src, doc, snapshot);
find(sv);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
}
void tst_FindUsages::variadicMacros()
{
const QByteArray src =
R"(
struct MyStruct { int value; };
#define FOO( ... ) int foo()
FOO(1) {
MyStruct s;
s.value;
}
int main(){}
)";
Document::Ptr doc = Document::create("variadicMacros");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QVERIFY(doc->globalSymbolCount() >= 1);
Snapshot snapshot;
snapshot.insert(doc);
Class *s = doc->globalSymbolAt(0)->asClass();
QVERIFY(s);
QCOMPARE(s->name()->identifier()->chars(), "MyStruct");
QCOMPARE(s->memberCount(), 1);
Declaration *sv = s->memberAt(0)->asDeclaration();
QVERIFY(sv);
QCOMPARE(sv->name()->identifier()->chars(), "value");
FindUsages find(src, doc, snapshot);
find(sv);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(find.usages().at(1).type, Usage::Type::Read);
}
void tst_FindUsages::writableRefs()
{
const QByteArray src = R"(
struct S {
S() : value2(value) {}
static int value;
int value2;
static void *p;
static const void *p2;
struct Nested {
int constFunc() const;
void constFunc(int) const;
void nonConstFunc();
} n;
Nested constFunc() const;
void nonConstFunc();
static void staticFunc1() {}
static void staticFunc2();
virtual void pureVirtual() = 0;
virtual void pureVirtual2() = 0 {}
};
void func1(int &);
void func2(const int &);
void func3(int *);
void func4(const int *);
void func5(int);
int main()
{
S s;
auto *p = &s.value;
int **pp;
p = &s.value;
*pp = &s.value;
//p = &s::value; FIXME: This one is not found at all...
s.p = &s.value;
// s::p = &s::value; FIXME: Same here.
(&s)->p = &((new S)->value);
const int *p2 = &s.value;
s.p2 = &s.value;
int * const p3 = &s.value;
int &r = s.value;
const int &cr = s.value;
func1(s.value);
func2(s.value);
func3(&s.value);
func4(&s.value);
func5(s.value);
*p = 5;
func1(*p);
func2(*p);
func3(p);
func4(p);
func5(p);
int &r2 = *p;
const int &cr2 = *p;
s = S();
auto * const ps = &s;
const auto *ps2 = &s;
auto &pr = s;
const auto pr2 = &s;
s.constFunc().nonConstFunc();
s.nonConstFunc();
(&s)->nonConstFunc();
s.n.constFunc();
s.n.nonConstFunc();
s.n.constFunc(s.value);
delete s.p;
switch (S::value) {
case S::value: break;
}
switch (S::value = 5) {
default: break;
}
if (S::value) {}
if (S::value = 0) {}
++S::value;
S::value--;
s.staticFunc1();
s.staticFunc2();
S::value = sizeof S::value;
int array[3];
array[S::value] = S::value;
S::value = array[S::value];
}
)";
const Document::Ptr doc = Document::create("writableRefs");
doc->setUtf8Source(src);
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QCOMPARE(doc->globalSymbolCount(), 7);
Snapshot snapshot;
snapshot.insert(doc);
Class * const structS = doc->globalSymbolAt(0)->asClass();
QVERIFY(structS);
QCOMPARE(structS->name()->identifier()->chars(), "S");
QCOMPARE(structS->memberCount(), 13);
Declaration * const sv = structS->memberAt(1)->asDeclaration();
QVERIFY(sv);
QCOMPARE(sv->name()->identifier()->chars(), "value");
// Access to struct member
FindUsages find(src, doc, snapshot);
find(sv);
QCOMPARE(find.usages().size(), 31);
QCOMPARE(find.usages().at(0).type, Usage::Type::Read);
QCOMPARE(find.usages().at(1).type, Usage::Type::Declaration);
QCOMPARE(find.usages().at(2).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(3).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(4).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(5).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(6).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(7).type, Usage::Type::Read);
QCOMPARE(find.usages().at(8).type, Usage::Type::Read);
QCOMPARE(find.usages().at(9).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(10).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(11).type, Usage::Type::Read);
QCOMPARE(find.usages().at(12).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(13).type, Usage::Type::Read);
QCOMPARE(find.usages().at(14).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(15).type, Usage::Type::Read);
QCOMPARE(find.usages().at(16).type, Usage::Type::Read);
QCOMPARE(find.usages().at(17).type, Usage::Type::Read);
QCOMPARE(find.usages().at(18).type, Usage::Type::Read);
QCOMPARE(find.usages().at(19).type, Usage::Type::Read);
QCOMPARE(find.usages().at(20).type, Usage::Type::Write);
QCOMPARE(find.usages().at(21).type, Usage::Type::Read);
QCOMPARE(find.usages().at(22).type, Usage::Type::Write);
QCOMPARE(find.usages().at(23).type, Usage::Type::Write);
QCOMPARE(find.usages().at(24).type, Usage::Type::Write);
QCOMPARE(find.usages().at(25).type, Usage::Type::Write);
QCOMPARE(find.usages().at(26).type, Usage::Type::Read);
QCOMPARE(find.usages().at(27).type, Usage::Type::Read);
QCOMPARE(find.usages().at(28).type, Usage::Type::Read);
QCOMPARE(find.usages().at(29).type, Usage::Type::Write);
QCOMPARE(find.usages().at(30).type, Usage::Type::Read);
Declaration * const sv2 = structS->memberAt(2)->asDeclaration();
QVERIFY(sv2);
QCOMPARE(sv2->name()->identifier()->chars(), "value2");
// Member initialization in constructor
find(sv2);
QCOMPARE(find.usages().size(), 2);
QCOMPARE(find.usages().at(0).type, Usage::Type::Write);
QCOMPARE(find.usages().at(1).type, Usage::Type::Declaration);
// Make sure that pure virtual declaration is not mistaken for an assignment.
Declaration * const pureVirtual = structS->memberAt(11)->asDeclaration();
QVERIFY(pureVirtual);
QCOMPARE(pureVirtual->name()->identifier()->chars(), "pureVirtual");
find(pureVirtual);
QCOMPARE(find.usages().size(), 1);
QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
Function * const pureVirtual2 = structS->memberAt(12)->asFunction();
QVERIFY(pureVirtual2);
QCOMPARE(pureVirtual2->name()->identifier()->chars(), "pureVirtual2");
find(pureVirtual2);
QCOMPARE(find.usages().size(), 1);
QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
Function * const main = doc->globalSymbolAt(6)->asFunction();
QVERIFY(main);
QCOMPARE(main->memberCount(), 1);
Block * const block = main->memberAt(0)->asBlock();
QVERIFY(block);
QCOMPARE(block->memberCount(), 18);
// Access to pointer
Declaration * const p = block->memberAt(1)->asDeclaration();
QVERIFY(p);
QCOMPARE(p->name()->identifier()->chars(), "p");
find(p);
QCOMPARE(find.usages().size(), 10);
QCOMPARE(find.usages().at(0).type, Usage::Type::Initialization);
QCOMPARE(find.usages().at(1).type, Usage::Type::Write);
QCOMPARE(find.usages().at(2).type, Usage::Type::Write);
QCOMPARE(find.usages().at(3).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(4).type, Usage::Type::Read);
QCOMPARE(find.usages().at(5).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(6).type, Usage::Type::Read);
QCOMPARE(find.usages().at(7).type, Usage::Type::Read);
QCOMPARE(find.usages().at(8).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(9).type, Usage::Type::Read);
// Access to struct variable via its members
Declaration * const varS = block->memberAt(0)->asDeclaration();
QVERIFY(varS);
QCOMPARE(varS->name()->identifier()->chars(), "s");
find(varS);
QCOMPARE(find.usages().size(), 33);
QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(find.usages().at(1).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(2).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(3).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(4).type, Usage::Type::Write);
QCOMPARE(find.usages().at(5).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(6).type, Usage::Type::Write);
QCOMPARE(find.usages().at(7).type, Usage::Type::Read);
QCOMPARE(find.usages().at(8).type, Usage::Type::Write);
QCOMPARE(find.usages().at(9).type, Usage::Type::Read);
QCOMPARE(find.usages().at(10).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(11).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(12).type, Usage::Type::Read);
QCOMPARE(find.usages().at(13).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(14).type, Usage::Type::Read);
QCOMPARE(find.usages().at(15).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(16).type, Usage::Type::Read);
QCOMPARE(find.usages().at(17).type, Usage::Type::Read);
// Direct access to struct variable
QCOMPARE(find.usages().at(18).type, Usage::Type::Write);
QCOMPARE(find.usages().at(19).type, Usage::Type::WritableRef);
QEXPECT_FAIL(nullptr, "parser does not record const qualifier for auto types", Continue);
QCOMPARE(find.usages().at(20).type, Usage::Type::Read);
QEXPECT_FAIL(nullptr, "parser does not record reference qualifier for auto types", Continue);
QCOMPARE(find.usages().at(21).type, Usage::Type::WritableRef);
QEXPECT_FAIL(nullptr, "parser does not record const qualifier for auto types", Continue);
QCOMPARE(find.usages().at(22).type, Usage::Type::Read);
// Member function calls.
QCOMPARE(find.usages().at(23).type, Usage::Type::Read);
QCOMPARE(find.usages().at(24).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(25).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(26).type, Usage::Type::Read);
QCOMPARE(find.usages().at(27).type, Usage::Type::WritableRef);
QCOMPARE(find.usages().at(28).type, Usage::Type::Read);
QCOMPARE(find.usages().at(29).type, Usage::Type::Read);
QCOMPARE(find.usages().at(31).type, Usage::Type::Other);
QEXPECT_FAIL(nullptr, "parser does not expose static specifier", Continue);
QCOMPARE(find.usages().at(32).type, Usage::Type::Other);
// Usages of struct type
find(structS);
QCOMPARE(find.usages().size(), 18);
QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(find.usages().at(1).type, Usage::Type::Other);
QCOMPARE(find.usages().at(2).type, Usage::Type::Other);
QCOMPARE(find.usages().at(3).type, Usage::Type::Other);
QCOMPARE(find.usages().at(4).type, Usage::Type::Other);
// These are conceptually questionable, as S is a type and thus we cannot "read from"
// or "write to" it. But it possibly matches the intuitive user expectation.
QCOMPARE(find.usages().at(5).type, Usage::Type::Read);
QCOMPARE(find.usages().at(6).type, Usage::Type::Read);
QCOMPARE(find.usages().at(7).type, Usage::Type::Write);
QCOMPARE(find.usages().at(8).type, Usage::Type::Read);
QCOMPARE(find.usages().at(9).type, Usage::Type::Write);
QCOMPARE(find.usages().at(10).type, Usage::Type::Write);
QCOMPARE(find.usages().at(11).type, Usage::Type::Write);
QCOMPARE(find.usages().at(12).type, Usage::Type::Write);
QCOMPARE(find.usages().at(13).type, Usage::Type::Read);
QCOMPARE(find.usages().at(14).type, Usage::Type::Read);
QCOMPARE(find.usages().at(15).type, Usage::Type::Read);
QCOMPARE(find.usages().at(16).type, Usage::Type::Write);
QCOMPARE(find.usages().at(17).type, Usage::Type::Read);
// Arrays.
Declaration * const array = block->memberAt(17)->asDeclaration();
QVERIFY(p);
QCOMPARE(array->name()->identifier()->chars(), "array");
find(array);
QCOMPARE(find.usages().size(), 3);
QCOMPARE(find.usages().at(0).type, Usage::Type::Declaration);
QCOMPARE(find.usages().at(1).type, Usage::Type::Write);
QCOMPARE(find.usages().at(2).type, Usage::Type::Read);
}
QTEST_APPLESS_MAIN(tst_FindUsages)
#include "tst_findusages.moc"