diff options
author | Volodymyr Zibarov <gogan419@gmail.com> | 2020-05-14 23:07:05 +0300 |
---|---|---|
committer | Volodymyr Zibarov <gogan419@gmail.com> | 2020-05-29 12:39:28 +0000 |
commit | 9ee693ee229d28bd618e8dd44bc6b12750d43a29 (patch) | |
tree | 7a2a4dd6679fd3647228b5c39d1fc2724ff133a3 /tests | |
parent | be97943372bc80d2440daa20cd658599d765b9a9 (diff) | |
download | qt-creator-9ee693ee229d28bd618e8dd44bc6b12750d43a29.tar.gz |
C++: fix built-in code model to work with shared_ptr on MSVC 2017
These changes target Find Usages feature to work with shared_ptr.
Improve libs/3rdparty/cplusplus and plugins/cplusplus:
parse __declspec() attribute,
call to variadic function template without specified template arguments,
if constexpr,
c++11 attributes [[value]],
function templates with default parameters,
resolve order for function vs template with default parameter,
template operator->() with default arguments,
template specialization with numeric values,
find best partial specialization,
fix partial specialization for non-first specialized argument
Fixes: QTCREATORBUG-7866
Fixes: QTCREATORBUG-20781
Fixes: QTCREATORBUG-22857
Fixes: QTCREATORBUG-17825
Change-Id: I31a080f7729edfb2ee9650f1aff48daeba5a673b
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Reviewed-by: Nikolai Kosjar <pinaceae.pinus@gmail.com>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/cplusplus/ast/tst_ast.cpp | 49 | ||||
-rw-r--r-- | tests/auto/cplusplus/findusages/tst_findusages.cpp | 504 | ||||
-rw-r--r-- | tests/auto/cplusplus/semantic/tst_semantic.cpp | 2 |
3 files changed, 554 insertions, 1 deletions
diff --git a/tests/auto/cplusplus/ast/tst_ast.cpp b/tests/auto/cplusplus/ast/tst_ast.cpp index eaac17ade3..c44fc4279e 100644 --- a/tests/auto/cplusplus/ast/tst_ast.cpp +++ b/tests/auto/cplusplus/ast/tst_ast.cpp @@ -118,6 +118,8 @@ private slots: void crash_test_1(); void thread_local_1(); + void msvc_attributes_declspec(); + // expressions void simple_name_1(); void template_id_1(); @@ -141,6 +143,7 @@ private slots: void if_statement_2(); void if_statement_3(); void if_else_statement(); + void if_constexpr(); void while_statement(); void while_condition_statement(); void for_statement(); @@ -169,6 +172,7 @@ private slots: //! checks for both correct ellipsis tokens in //! "template<class ...Args> class T : Args... {};" void cpp11_variadic_inheritance(); + void cpp11_attributes(); // Q_PROPERTY void cpp_qproperty(); @@ -281,6 +285,14 @@ void tst_AST::thread_local_1() QCOMPARE(Token::name(T___THREAD), "__thread"); } +void tst_AST::msvc_attributes_declspec() +{ + const char *inp = "class __declspec(novtable) Name{};"; + QSharedPointer<TranslationUnit> unit(parseDeclaration(inp)); + QVERIFY(unit->ast()); + QCOMPARE(diag.errorCount, 0); +} + void tst_AST::simple_declaration_1() { QSharedPointer<TranslationUnit> unit(parseStatement("\n" @@ -1322,6 +1334,43 @@ void tst_AST::cpp11_variadic_inheritance() QVERIFY(ba->ellipsis_token != 0); // important } +void tst_AST::cpp11_attributes() +{ + QSharedPointer<TranslationUnit> unit(parseDeclaration( + "[[noreturn]] void f() {throw \"error\";}", + false, false, true)); + AST *ast = unit->ast(); + QVERIFY(ast != nullptr); + + DeclarationAST *d = ast->asDeclaration(); + QVERIFY(d != nullptr); + + FunctionDefinitionAST *f = d->asFunctionDefinition(); + QVERIFY(f != nullptr); + QVERIFY(f->decl_specifier_list != nullptr); + QVERIFY(f->decl_specifier_list->value != nullptr); + + StdAttributeSpecifierAST *attr = f->decl_specifier_list->value->asStdAttributeSpecifier(); + QVERIFY(attr != nullptr); +} + +void tst_AST::if_constexpr() +{ + QSharedPointer<TranslationUnit> unit(parseStatement("if constexpr (a) b;",true)); + + AST *ast = unit->ast(); + QVERIFY(ast != 0); + + IfStatementAST *stmt = ast->asIfStatement(); + QVERIFY(stmt != 0); + QCOMPARE(stmt->if_token, 1); + QCOMPARE(stmt->constexpr_token, 2); + QCOMPARE(stmt->lparen_token, 3); + QVERIFY(stmt->condition != 0); + QCOMPARE(stmt->rparen_token, 5); + QVERIFY(stmt->statement != 0); +} + void tst_AST::cpp_qproperty() { QFETCH(QByteArray, source); diff --git a/tests/auto/cplusplus/findusages/tst_findusages.cpp b/tests/auto/cplusplus/findusages/tst_findusages.cpp index d961cb449d..2b38759ed2 100644 --- a/tests/auto/cplusplus/findusages/tst_findusages.cpp +++ b/tests/auto/cplusplus/findusages/tst_findusages.cpp @@ -115,6 +115,16 @@ 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 tst_FindUsages::dump(const QList<Usage> &usages) const @@ -1076,5 +1086,499 @@ 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); +} + QTEST_APPLESS_MAIN(tst_FindUsages) #include "tst_findusages.moc" diff --git a/tests/auto/cplusplus/semantic/tst_semantic.cpp b/tests/auto/cplusplus/semantic/tst_semantic.cpp index 51c1fadf7e..deda2aab2c 100644 --- a/tests/auto/cplusplus/semantic/tst_semantic.cpp +++ b/tests/auto/cplusplus/semantic/tst_semantic.cpp @@ -612,7 +612,7 @@ void tst_Semantic::template_instance_1() Declaration *decl = templ->memberAt(1)->asClass()->memberAt(0)->asDeclaration(); QVERIFY(decl); - FullySpecifiedType templArgs[] = {control->integerType(IntegerType::Int)}; + TemplateArgument templArgs[] = {FullySpecifiedType(control->integerType(IntegerType::Int))}; const Name *templId = control->templateNameId(control->identifier("QList"), false, templArgs, 1); FullySpecifiedType genTy = DeprecatedGenTemplateInstance::instantiate(templId, decl, control); |