aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/cplusplus/findusages/tst_findusages.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/cplusplus/findusages/tst_findusages.cpp')
-rw-r--r--tests/auto/cplusplus/findusages/tst_findusages.cpp809
1 files changed, 809 insertions, 0 deletions
diff --git a/tests/auto/cplusplus/findusages/tst_findusages.cpp b/tests/auto/cplusplus/findusages/tst_findusages.cpp
index d961cb449d..2dd9566021 100644
--- a/tests/auto/cplusplus/findusages/tst_findusages.cpp
+++ b/tests/auto/cplusplus/findusages/tst_findusages.cpp
@@ -84,6 +84,11 @@ private Q_SLOTS:
void shadowedNames_2();
void staticVariables();
+ void functionNameFoundInArguments();
+ void memberFunctionFalsePositives_QTCREATORBUG2176();
+ void resolveTemplateConstructor();
+ void templateConstructorVsCallOperator();
+
// Qt keywords
void qproperty_1();
@@ -115,6 +120,19 @@ private Q_SLOTS:
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 tst_FindUsages::dump(const QList<Usage> &usages) const
@@ -339,6 +357,222 @@ void tst_FindUsages::staticVariables()
QCOMPARE(findUsages.usages().size(), 5);
}
+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].line, 1);
+ QCOMPARE(find.usages()[0].col, 5);
+
+ QCOMPARE(find.usages()[1].line, 4);
+ QCOMPARE(find.usages()[1].col, 16);
+
+ 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].line, 3);
+ QCOMPARE(find.usages()[0].col, 15);
+
+ QCOMPARE(find.usages()[1].line, 5);
+ QCOMPARE(find.usages()[1].col, 24);
+
+ find(variableFoo);
+ QCOMPARE(find.usages().size(), 2);
+
+ QCOMPARE(find.usages()[0].line, 5);
+ QCOMPARE(find.usages()[0].col, 12);
+
+ 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);
+}
+
+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);
+}
+
#if 0
@interface Clazz {} +(void)method:(int)arg; @end
@implementation Clazz +(void)method:(int)arg {
@@ -1076,5 +1310,580 @@ void tst_FindUsages::memberAccessAsTemplate()
}
}
+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);
+ }
+}
+
+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);
+ find(sv);
+ QCOMPARE(find.usages().size(), 3);
+ }
+}
+
+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);
+ }
+}
+
+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);
+ }
+}
+
+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;\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].line, 2);
+ QCOMPARE(find.usages()[0].col, 15);
+ QCOMPARE(find.usages()[1].line, 13);
+ QCOMPARE(find.usages()[1].col, 9);
+
+ find(sv[2]);
+ QCOMPARE(find.usages().size(), 2);
+
+ QCOMPARE(find.usages()[0].line, 3);
+ QCOMPARE(find.usages()[0].col, 15);
+ QCOMPARE(find.usages()[1].line, 14);
+ QCOMPARE(find.usages()[1].col, 9);
+ }
+}
+
+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].line, 1);
+ QCOMPARE(find.usages()[0].col, 15);
+ QCOMPARE(find.usages()[1].line, 9);
+ QCOMPARE(find.usages()[1].col, 9);
+
+ find(sv[1]);
+ QCOMPARE(find.usages().size(), 2);
+
+ QCOMPARE(find.usages()[0].line, 2);
+ QCOMPARE(find.usages()[0].col, 15);
+ 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].line, 1);
+ QCOMPARE(find.usages()[0].col, 15);
+ QCOMPARE(find.usages()[1].line, 9);
+ QCOMPARE(find.usages()[1].col, 10);
+
+ find(sv[1]);
+ QCOMPARE(find.usages().size(), 2);
+
+ QCOMPARE(find.usages()[0].line, 2);
+ QCOMPARE(find.usages()[0].col, 15);
+ 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);
+
+ find(sv[1]);
+ QCOMPARE(find.usages().size(), 2);
+
+ find(sv[2]);
+ QCOMPARE(find.usages().size(), 2);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
QTEST_APPLESS_MAIN(tst_FindUsages)
#include "tst_findusages.moc"