diff options
author | Dmitry Ashkadov <dmitry.ashkadov@gmail.com> | 2014-11-13 22:18:53 +0300 |
---|---|---|
committer | Orgad Shaneh <orgads@gmail.com> | 2016-06-22 17:47:59 +0000 |
commit | 43075f5fb165e764f11abd35c4cc06cbda969a20 (patch) | |
tree | ec7a69d1a1a4d72bb7d3d0a9eb2d342b7afcc650 | |
parent | c0f3094866923f27692e654f94cd55546f5c87d5 (diff) |
C++: Add support of ref-qualifier for functions.
Now the ref-qualifier (& or &&) of the function declaration
is propagated to GUI. For example, 'Refactor' -> 'Add Definition'
preserves the ref-qualifier.
Change-Id: I8ac4e1cad4e44985e94230aabbd9858a7e929fee
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
-rw-r--r-- | src/libs/3rdparty/cplusplus/Bind.cpp | 8 | ||||
-rw-r--r-- | src/libs/3rdparty/cplusplus/Symbols.cpp | 6 | ||||
-rw-r--r-- | src/libs/3rdparty/cplusplus/Symbols.h | 10 | ||||
-rw-r--r-- | src/libs/cplusplus/CppRewriter.cpp | 1 | ||||
-rw-r--r-- | src/libs/cplusplus/TypePrettyPrinter.cpp | 11 | ||||
-rw-r--r-- | tests/auto/cplusplus/semantic/tst_semantic.cpp | 105 | ||||
-rw-r--r-- | tests/auto/cplusplus/typeprettyprinter/tst_typeprettyprinter.cpp | 35 |
7 files changed, 176 insertions, 0 deletions
diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index d8f9861e7d..a97c71ec5c 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -3255,6 +3255,14 @@ bool Bind::visit(FunctionDeclaratorAST *ast) fun->setOverride(type.isOverride()); fun->setFinal(type.isFinal()); + // propagate ref-qualifier + if (ast->ref_qualifier_token) { + const Kind kind = tokenAt(ast->ref_qualifier_token).kind(); + CPP_CHECK(kind == T_AMPER || kind == T_AMPER_AMPER); // & or && are only allowed + fun->setRefQualifier(kind == T_AMPER ? Function::LvalueRefQualifier : + Function::RvalueRefQualifier); + } + this->exceptionSpecification(ast->exception_specification, type); if (ast->as_cpp_initializer != 0) { fun->setAmbiguous(true); diff --git a/src/libs/3rdparty/cplusplus/Symbols.cpp b/src/libs/3rdparty/cplusplus/Symbols.cpp index f8a8440c09..6a69ca2dc4 100644 --- a/src/libs/3rdparty/cplusplus/Symbols.cpp +++ b/src/libs/3rdparty/cplusplus/Symbols.cpp @@ -367,6 +367,12 @@ bool Function::isPureVirtual() const void Function::setPureVirtual(bool isPureVirtual) { f._isPureVirtual = isPureVirtual; } +Function::RefQualifier Function::refQualifier() const +{ return static_cast<RefQualifier>(f._refQualifier); } + +void Function::setRefQualifier(Function::RefQualifier refQualifier) +{ f._refQualifier = refQualifier; } + bool Function::isAmbiguous() const { return f._isAmbiguous; } diff --git a/src/libs/3rdparty/cplusplus/Symbols.h b/src/libs/3rdparty/cplusplus/Symbols.h index 826c816b69..a545644cfa 100644 --- a/src/libs/3rdparty/cplusplus/Symbols.h +++ b/src/libs/3rdparty/cplusplus/Symbols.h @@ -298,6 +298,12 @@ public: InvokableMethod }; + enum RefQualifier { + NoRefQualifier, // a function declared w/o & and && => *this may be lvalue or rvalue + LvalueRefQualifier, // a function declared with & => *this is lvalue + RvalueRefQualifier // a function declared with && => *this is rvalue + }; + public: Function(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name); Function(Clone *clone, Subst *subst, Function *original); @@ -344,6 +350,9 @@ public: bool isPureVirtual() const; void setPureVirtual(bool isPureVirtual); + RefQualifier refQualifier() const; + void setRefQualifier(RefQualifier refQualifier); + bool isSignatureEqualTo(const Function *other, Matcher *matcher = 0) const; bool isAmbiguous() const; // internal @@ -384,6 +393,7 @@ private: unsigned _isVolatile: 1; unsigned _isAmbiguous: 1; unsigned _methodKey: 3; + unsigned _refQualifier: 2; }; union { unsigned _flags; diff --git a/src/libs/cplusplus/CppRewriter.cpp b/src/libs/cplusplus/CppRewriter.cpp index 4a7325a6c4..1ce9cc2dfa 100644 --- a/src/libs/cplusplus/CppRewriter.cpp +++ b/src/libs/cplusplus/CppRewriter.cpp @@ -135,6 +135,7 @@ public: funTy->copy(type); funTy->setConst(type->isConst()); funTy->setVolatile(type->isVolatile()); + funTy->setRefQualifier(type->refQualifier()); funTy->setName(rewrite->rewriteName(type->name())); diff --git a/src/libs/cplusplus/TypePrettyPrinter.cpp b/src/libs/cplusplus/TypePrettyPrinter.cpp index 282deb830e..e3693f17a0 100644 --- a/src/libs/cplusplus/TypePrettyPrinter.cpp +++ b/src/libs/cplusplus/TypePrettyPrinter.cpp @@ -454,6 +454,17 @@ void TypePrettyPrinter::visit(Function *type) appendSpace(); _text += QLatin1String("volatile"); } + + // add ref-qualifier + if (type->refQualifier() != Function::NoRefQualifier) { + if (!_overview->starBindFlags.testFlag(Overview::BindToLeftSpecifier) + || (!type->isConst() && !type->isVolatile())) { + appendSpace(); + } + _text += type->refQualifier() == Function::LvalueRefQualifier + ? QLatin1String("&") + : QLatin1String("&&"); + } } } diff --git a/tests/auto/cplusplus/semantic/tst_semantic.cpp b/tests/auto/cplusplus/semantic/tst_semantic.cpp index ff0f6bc58c..b7a4c161cf 100644 --- a/tests/auto/cplusplus/semantic/tst_semantic.cpp +++ b/tests/auto/cplusplus/semantic/tst_semantic.cpp @@ -50,6 +50,9 @@ using namespace CPlusPlus; +// to use in tests directly w/o convertion to int +Q_DECLARE_METATYPE(Function::RefQualifier) + class tst_Semantic: public QObject { Q_OBJECT @@ -150,6 +153,8 @@ public: private slots: void function_declaration_1(); void function_declaration_2(); + void function_declaration_ref_qualifier_data(); + void function_declaration_ref_qualifier(); void function_definition_1(); void nested_class_1(); void alias_declaration_1(); @@ -202,6 +207,7 @@ void tst_Semantic::function_declaration_1() QVERIFY(funTy); QVERIFY(funTy->returnType()->isVoidType()); QCOMPARE(funTy->argumentCount(), 0U); + QCOMPARE(funTy->refQualifier(), Function::NoRefQualifier); QVERIFY(decl->name()->isNameId()); const Identifier *funId = decl->name()->asNameId()->identifier(); @@ -225,6 +231,7 @@ void tst_Semantic::function_declaration_2() QVERIFY(funTy); QVERIFY(funTy->returnType()->isVoidType()); QCOMPARE(funTy->argumentCount(), 1U); + QCOMPARE(funTy->refQualifier(), Function::NoRefQualifier); // check the formal argument. Argument *arg = funTy->argumentAt(0)->asArgument(); @@ -261,6 +268,103 @@ void tst_Semantic::function_declaration_2() QCOMPARE(foo, QByteArray("foo")); } +void tst_Semantic::function_declaration_ref_qualifier_data() +{ + QTest::addColumn<QString>("code"); + QTest::addColumn<bool>("success"); + QTest::addColumn<Function::RefQualifier>("refQualifier"); + + QTest::newRow("no") + << "void f();" << true << Function::NoRefQualifier; + + QTest::newRow("no_const") + << "void f() const;" << true << Function::NoRefQualifier; + + QTest::newRow("no_const_noexcept") + << "void f() const noexcept;" << true << Function::NoRefQualifier; + + QTest::newRow("lvalue") + << "void f() &;" << true << Function::LvalueRefQualifier; + + QTest::newRow("lvalue_const") + << "void f() const &;" << true << Function::LvalueRefQualifier; + + QTest::newRow("lvalue_const_noexcept") + << "void f() const & noexcept;" << true << Function::LvalueRefQualifier; + + QTest::newRow("rvalue") + << "void f() &&;" << true << Function::RvalueRefQualifier; + + QTest::newRow("rvalue_const") + << "void f() const &&;" << true << Function::RvalueRefQualifier; + + QTest::newRow("rvalue_const_noexcept") + << "void f() const && noexcept;" << true << Function::RvalueRefQualifier; + + QTest::newRow("lvalue_more_spaces") + << "void f() const &;" << true << Function::LvalueRefQualifier; + + QTest::newRow("rvalue_more_spaces") + << "void f() && noexcept;" << true << Function::RvalueRefQualifier; + + QTest::newRow("lvalue_more_newline") + << "void f() const\n&;" << true << Function::LvalueRefQualifier; + + QTest::newRow("rvalue_more_newline") + << "void f() const\n&&;" << true << Function::RvalueRefQualifier; + + QTest::newRow("lvalue_no_space") + << "void f() const& noexcept;" << true << Function::LvalueRefQualifier; + + QTest::newRow("rvalue_no_space") + << "void f() const&& noexcept;" << true << Function::RvalueRefQualifier; + + QTest::newRow("lvalue_before_const") + << "void f() & const;" << false << Function::NoRefQualifier; + + QTest::newRow("rvalue_before_const") + << "void f() && const;" << false << Function::NoRefQualifier; + + QTest::newRow("lvalue_after_noexcept") + << "void f() const noexcept &;" << false << Function::NoRefQualifier; + + QTest::newRow("rvalue_after_noexcept") + << "void f() const noexcept &&;" << false << Function::NoRefQualifier; + + QTest::newRow("lvalue_double") + << "void f() const & & noexcept;" << false << Function::NoRefQualifier; + + QTest::newRow("rvalue_double") + << "void f() const && && noexcept;" << false << Function::NoRefQualifier; +} + +void tst_Semantic::function_declaration_ref_qualifier() +{ + QFETCH(QString, code); + QFETCH(bool, success); + QFETCH(Function::RefQualifier, refQualifier); + + QSharedPointer<Document> doc = document(code.toUtf8(), false, false, true); + if (!success) { + QVERIFY(doc->errorCount > 0); + return; + } + QCOMPARE(doc->errorCount, 0U); + QCOMPARE(doc->globals->memberCount(), 1U); + + Declaration *decl = doc->globals->memberAt(0)->asDeclaration(); + QVERIFY(decl); + + FullySpecifiedType declTy = decl->type(); + Function *funTy = declTy->asFunctionType(); + QVERIFY(funTy); + QVERIFY(funTy->returnType()->isVoidType()); + QCOMPARE(funTy->argumentCount(), 0U); + + // check the ref-qualifier + QCOMPARE(funTy->refQualifier(), refQualifier); +} + void tst_Semantic::function_definition_1() { QSharedPointer<Document> doc = document("void foo() {}"); @@ -271,6 +375,7 @@ void tst_Semantic::function_definition_1() QVERIFY(funTy); QVERIFY(funTy->returnType()->isVoidType()); QCOMPARE(funTy->argumentCount(), 0U); + QCOMPARE(funTy->refQualifier(), Function::NoRefQualifier); QVERIFY(funTy->name()->isNameId()); const Identifier *funId = funTy->name()->asNameId()->identifier(); diff --git a/tests/auto/cplusplus/typeprettyprinter/tst_typeprettyprinter.cpp b/tests/auto/cplusplus/typeprettyprinter/tst_typeprettyprinter.cpp index 11b08e30dc..a028f9afec 100644 --- a/tests/auto/cplusplus/typeprettyprinter/tst_typeprettyprinter.cpp +++ b/tests/auto/cplusplus/typeprettyprinter/tst_typeprettyprinter.cpp @@ -93,6 +93,33 @@ static FullySpecifiedType fnTy(const QString &name, const FullySpecifiedType &re return FullySpecifiedType(fn); } +static FullySpecifiedType refThis(const FullySpecifiedType &type) +{ + FullySpecifiedType result(type); + Function *f = dynamic_cast<Function*>(result.type()); + Q_ASSERT(f); + f->setRefQualifier(Function::LvalueRefQualifier); + return result; +} + +static FullySpecifiedType rrefThis(const FullySpecifiedType &type) +{ + FullySpecifiedType result(type); + Function *function = dynamic_cast<Function*>(result.type()); + Q_ASSERT(function); + function->setRefQualifier(Function::RvalueRefQualifier); + return result; +} + +static FullySpecifiedType cnstThis(const FullySpecifiedType &type) +{ + FullySpecifiedType result(type); + Function *function = dynamic_cast<Function*>(result.type()); + Q_ASSERT(function); + function->setConst(true); + return result; +} + static FullySpecifiedType ptr(const FullySpecifiedType &el) { return FullySpecifiedType(new PointerType(el)); } @@ -166,6 +193,14 @@ void tst_TypePrettyPrinter::basic_data() addRow(fnTy("foo", voidTy(), intTy()), bindToNothing, "void foo(int)", "foo"); addRow(fnTy("foo", voidTy(), intTy()), bindToAll, "void foo(int)", "foo"); + addRow(refThis(fnTy("foo", voidTy())), bindToNothing, "void foo() &", "foo"); + addRow(rrefThis(fnTy("foo", voidTy())), bindToNothing, "void foo() &&", "foo"); + addRow(refThis(fnTy("foo", voidTy())), bindToAll, "void foo() &", "foo"); + addRow(rrefThis(fnTy("foo", voidTy())), bindToAll, "void foo() &&", "foo"); + addRow(cnstThis(refThis(fnTy("foo", voidTy()))), bindToNothing, "void foo() const &", "foo"); + addRow(cnstThis(rrefThis(fnTy("foo", voidTy()))), bindToNothing, "void foo() const &&", "foo"); + addRow(cnstThis(refThis(fnTy("foo", voidTy()))), bindToAll, "void foo() const&", "foo"); + addRow(cnstThis(rrefThis(fnTy("foo", voidTy()))), bindToAll, "void foo() const&&", "foo"); // Pointers to functions and arrays are also excluded. It seems to be quite unusal to have // a space there. |