aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Ashkadov <dmitry.ashkadov@gmail.com>2014-11-13 22:18:53 +0300
committerOrgad Shaneh <orgads@gmail.com>2016-06-22 17:47:59 +0000
commit43075f5fb165e764f11abd35c4cc06cbda969a20 (patch)
treeec7a69d1a1a4d72bb7d3d0a9eb2d342b7afcc650
parentc0f3094866923f27692e654f94cd55546f5c87d5 (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.cpp8
-rw-r--r--src/libs/3rdparty/cplusplus/Symbols.cpp6
-rw-r--r--src/libs/3rdparty/cplusplus/Symbols.h10
-rw-r--r--src/libs/cplusplus/CppRewriter.cpp1
-rw-r--r--src/libs/cplusplus/TypePrettyPrinter.cpp11
-rw-r--r--tests/auto/cplusplus/semantic/tst_semantic.cpp105
-rw-r--r--tests/auto/cplusplus/typeprettyprinter/tst_typeprettyprinter.cpp35
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.