moc: parse classes that use Q_DECL_FINAL|final|sealed

This only works with the C++11 contextual keyword
directly, the MSVC equivalent 'sealed', or the Qt
define for it.

While this isn't a problem for syncqt, being an
internal tool, moc should eventually be able to parse
user code using local C++11-final-wrapping macros.
For this, I guess moc would have to be taught to
expand macros in code and not just test #if clauses,
potentially driven by something like
  #pragma qt-moc expand-this
  #define MY_FINAL_CLASS final
but that's something for someone more intimately
familiar with moc's source than I am.

Change-Id: Id6aec961a881e8d5a9b76a7fc8e1c02c71913f64
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
bb10
Marc Mutz 2012-03-05 17:55:59 +01:00 committed by Qt by Nokia
parent d811b2434b
commit 80694dd614
4 changed files with 178 additions and 4 deletions

View File

@ -100,13 +100,16 @@ bool Moc::parseClassHead(ClassDef *def)
QByteArray name = lexem();
// support "class IDENT name" and "class IDENT(IDENT) name"
// also support "class IDENT name (final|sealed|Q_DECL_FINAL)"
if (test(LPAREN)) {
until(RPAREN);
if (!test(IDENTIFIER))
return false;
name = lexem();
} else if (test(IDENTIFIER)) {
name = lexem();
const QByteArray lex = lexem();
if (lex != "final" && lex != "sealed" && lex != "Q_DECL_FINAL")
name = lex;
}
def->qualified += name;
@ -118,6 +121,13 @@ bool Moc::parseClassHead(ClassDef *def)
}
}
def->classname = name;
if (test(IDENTIFIER)) {
const QByteArray lex = lexem();
if (lex != "final" && lex != "sealed" && lex != "Q_DECL_FINAL")
return false;
}
if (test(COLON)) {
do {
test(VIRTUAL);

View File

@ -0,0 +1,133 @@
/****************************************************************************
**
** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
** Contact: http://www.qt-project.org/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef TESTS_AUTO_CORELIB_TOOLS_MOC_CXX11_FINAL_CLASSES_H
#define TESTS_AUTO_CORELIB_TOOLS_MOC_CXX11_FINAL_CLASSES_H
#include <QtCore/QObject>
#ifndef Q_MOC_RUN // hide from moc
# define final
# define sealed
# define EXPORT_MACRO
# define EXPORT_MACRO2(X,Y,Z)
#endif
class FinalTestClassQt Q_DECL_FINAL : public QObject
{
Q_OBJECT
public:
explicit FinalTestClassQt(QObject *parent = 0)
: QObject(parent) {}
};
class EXPORT_MACRO ExportedFinalTestClassQt Q_DECL_FINAL : public QObject
{
Q_OBJECT
public:
explicit ExportedFinalTestClassQt(QObject *parent = 0)
: QObject(parent) {}
};
class EXPORT_MACRO2(X,Y,Z) ExportedFinalTestClassQtX Q_DECL_FINAL : public QObject
{
Q_OBJECT
public:
explicit ExportedFinalTestClassQtX(QObject *parent = 0)
: QObject(parent) {}
};
class FinalTestClassCpp11 final : public QObject
{
Q_OBJECT
public:
explicit FinalTestClassCpp11(QObject *parent = 0)
: QObject(parent) {}
};
class EXPORT_MACRO ExportedFinalTestClassCpp11 final : public QObject
{
Q_OBJECT
public:
explicit ExportedFinalTestClassCpp11(QObject *parent = 0)
: QObject(parent) {}
};
class EXPORT_MACRO2(X,Y,Z) ExportedFinalTestClassCpp11X final : public QObject
{
Q_OBJECT
public:
explicit ExportedFinalTestClassCpp11X(QObject *parent = 0)
: QObject(parent) {}
};
class SealedTestClass sealed : public QObject
{
Q_OBJECT
public:
explicit SealedTestClass(QObject *parent = 0)
: QObject(parent) {}
};
class EXPORT_MACRO ExportedSealedTestClass sealed : public QObject
{
Q_OBJECT
public:
explicit ExportedSealedTestClass(QObject *parent = 0)
: QObject(parent) {}
};
class EXPORT_MACRO2(X,Y,Z) ExportedSealedTestClassX sealed : public QObject
{
Q_OBJECT
public:
explicit ExportedSealedTestClassX(QObject *parent = 0)
: QObject(parent) {}
};
#ifndef Q_MOC_RUN
# undef final
# undef sealed
# undef EXPORT_MACRO
# undef EXPORT_MACRO2
#endif
#endif // TESTS_AUTO_CORELIB_TOOLS_MOC_CXX11_FINAL_CLASSES_H

View File

@ -18,7 +18,10 @@ HEADERS += using-namespaces.h no-keywords.h task87883.h c-comments.h backslash-n
slots-with-void-template.h qinvokable.h namespaced-flags.h trigraphs.h \
escapes-in-string-literals.h cstyle-enums.h qprivateslots.h gadgetwithnoenums.h \
dir-in-include-path.h single_function_keyword.h task192552.h task189996.h \
task234909.h task240368.h pure-virtual-signals.h cxx11-enums.h
task234909.h task240368.h pure-virtual-signals.h cxx11-enums.h \
cxx11-final-classes.h \
if(*-g++*|*-icc*|*-clang*|*-llvm):!irix-*:!win32-*: HEADERS += os9-newlines.h win-newlines.h
SOURCES += tst_moc.cpp

View File

@ -44,6 +44,7 @@
#include <QtTest/QtTest>
#include <stdio.h>
#include <qobject.h>
#include <qmetaobject.h>
#include "using-namespaces.h"
#include "assign-namespace.h"
@ -70,6 +71,7 @@
#include "parse-boost.h"
#endif
#include "cxx11-enums.h"
#include "cxx11-final-classes.h"
QT_USE_NAMESPACE
@ -475,7 +477,6 @@ CtorTestClass::CtorTestClass(QObject *parent)
CtorTestClass::CtorTestClass(int, int, int) {}
class tst_Moc : public QObject
{
Q_OBJECT
@ -542,8 +543,9 @@ private slots:
void cxx11Enums_data();
void cxx11Enums();
void returnRefs();
void privateSignalConnection();
void finalClasses_data();
void finalClasses();
signals:
void sigWithUnsignedArg(unsigned foo);
@ -2225,7 +2227,33 @@ void tst_Moc::privateSignalConnection()
// Which doesn't work as ClassWithPrivateSignals::QPrivateSignal is private.
}
void tst_Moc::finalClasses_data()
{
QTest::addColumn<QString>("className");
QTest::addColumn<QString>("expected");
QTest::newRow("FinalTestClassQt") << FinalTestClassQt::staticMetaObject.className() << "FinalTestClassQt";
QTest::newRow("ExportedFinalTestClassQt") << ExportedFinalTestClassQt::staticMetaObject.className() << "ExportedFinalTestClassQt";
QTest::newRow("ExportedFinalTestClassQtX") << ExportedFinalTestClassQtX::staticMetaObject.className() << "ExportedFinalTestClassQtX";
QTest::newRow("FinalTestClassCpp11") << FinalTestClassCpp11::staticMetaObject.className() << "FinalTestClassCpp11";
QTest::newRow("ExportedFinalTestClassCpp11") << ExportedFinalTestClassCpp11::staticMetaObject.className() << "ExportedFinalTestClassCpp11";
QTest::newRow("ExportedFinalTestClassCpp11X") << ExportedFinalTestClassCpp11X::staticMetaObject.className() << "ExportedFinalTestClassCpp11X";
QTest::newRow("SealedTestClass") << SealedTestClass::staticMetaObject.className() << "SealedTestClass";
QTest::newRow("ExportedSealedTestClass") << ExportedSealedTestClass::staticMetaObject.className() << "ExportedSealedTestClass";
QTest::newRow("ExportedSealedTestClassX") << ExportedSealedTestClassX::staticMetaObject.className() << "ExportedSealedTestClassX";
}
void tst_Moc::finalClasses()
{
QFETCH(QString, className);
QFETCH(QString, expected);
QCOMPARE(className, expected);
}
QTEST_MAIN(tst_Moc)
#include "tst_moc.moc"