From 87583738f960e83918da3b66e455e75c144fbf8e Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Wed, 28 Sep 2016 19:27:11 +0300 Subject: [PATCH] moc: support nested q_namespaces Nested namespaces are quite common, therefore moc should support them. Task-number: QTBUG-55415 Change-Id: I756cab36d498eb4342b402d255836d5d30f07b30 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/tools/moc/moc.cpp | 38 ++++++++++-- tests/auto/tools/moc/namespace.h | 72 +++++++++++++++++++++- tests/auto/tools/moc/namespace_no_merge.h | 74 +++++++++++++++++++++++ tests/auto/tools/moc/tst_moc.cpp | 4 ++ 4 files changed, 181 insertions(+), 7 deletions(-) create mode 100644 tests/auto/tools/moc/namespace_no_merge.h diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index e4b9b19758..3bd87e1f01 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -538,7 +538,6 @@ bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def) return true; } - void Moc::parse() { QVector namespaceList; @@ -560,9 +559,27 @@ void Moc::parse() until(RBRACE); def.end = index; index = def.begin + 1; + const bool parseNamespace = currentFilenames.size() <= 1; + if (parseNamespace) { + for (int i = namespaceList.size() - 1; i >= 0; --i) { + if (inNamespace(&namespaceList.at(i))) { + def.qualified.prepend(namespaceList.at(i).classname + "::"); + } + } + } while (parseNamespace && inNamespace(&def) && hasNext()) { switch (next()) { + case NAMESPACE: + if (test(IDENTIFIER)) { + if (test(EQ)) { + // namespace Foo = Bar::Baz; + until(SEMIC); + } else if (!test(SEMIC)) { + until(RBRACE); + } + } + break; case Q_NAMESPACE_TOKEN: def.hasQNamespace = true; break; @@ -857,13 +874,22 @@ void Moc::parse() continue; ClassDef def; static_cast(def) = static_cast(n); - if (!def.qualified.isEmpty()) - def.qualified += "::"; def.qualified += def.classname; def.hasQGadget = true; - classList += def; - knownGadgets.insert(def.classname, def.qualified); - knownGadgets.insert(def.qualified, def.qualified); + auto it = std::find_if(classList.begin(), classList.end(), [&def](const ClassDef &val) { + return def.classname == val.classname && def.qualified == val.qualified; + }); + + if (it != classList.end()) { + it->classInfoList += def.classInfoList; + it->enumDeclarations.unite(def.enumDeclarations); + it->enumList += def.enumList; + it->flagAliases.unite(def.flagAliases); + } else { + knownGadgets.insert(def.classname, def.qualified); + knownGadgets.insert(def.qualified, def.qualified); + classList += def; + } } } diff --git a/tests/auto/tools/moc/namespace.h b/tests/auto/tools/moc/namespace.h index 2bb1d8e958..6e04831589 100644 --- a/tests/auto/tools/moc/namespace.h +++ b/tests/auto/tools/moc/namespace.h @@ -1,7 +1,77 @@ -#pragma once +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NAMESPACE_H +#define NAMESPACE_H #include +#include "namespace_no_merge.h" +// moc should not merge namespace_no_merge.h content with this one ! + namespace FooNamespace { Q_NAMESPACE + enum class Enum1 { + Key1, + Key2 + }; + Q_ENUM_NS(Enum1) + + namespace FooNestedNamespace { + Q_NAMESPACE + enum class Enum2 { + Key3, + Key4 + }; + Q_ENUM_NS(Enum2) + } + + using namespace FooNamespace; + namespace Bar = FooNamespace; + + // Moc should merge this namespace with the previous one + namespace FooNestedNamespace { + Q_NAMESPACE + enum class Enum3 { + Key5, + Key6 + }; + Q_ENUM_NS(Enum3) + + namespace FooMoreNestedNamespace { + Q_NAMESPACE + enum class Enum4 { + Key7, + Key8 + }; + Q_ENUM_NS(Enum4) + } + } } + +#endif // NAMESPACE_H diff --git a/tests/auto/tools/moc/namespace_no_merge.h b/tests/auto/tools/moc/namespace_no_merge.h new file mode 100644 index 0000000000..8d1639ad4c --- /dev/null +++ b/tests/auto/tools/moc/namespace_no_merge.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NAMESPACE_NO_MERGE_H +#define NAMESPACE_NO_MERGE_H + +#include + +namespace FooNamespace { + Q_NAMESPACE + enum class MEnum1 { + Key1, + Key2 + }; + Q_ENUM_NS(MEnum1) + + namespace FooNestedNamespace { + Q_NAMESPACE + enum class MEnum2 { + Key3, + Key4 + }; + Q_ENUM_NS(MEnum2) + } + + using namespace FooNamespace; + namespace Bar = FooNamespace; + + // Moc should merge this namespace with the previous one + namespace FooNestedNamespace { + Q_NAMESPACE + enum class MEnum3 { + Key5, + Key6 + }; + Q_ENUM_NS(MEnum3) + + namespace FooMoreNestedNamespace { + Q_NAMESPACE + enum class MEnum4 { + Key7, + Key8 + }; + Q_ENUM_NS(MEnum4) + } + } +} + +#endif // NAMESPACE_NO_MERGE_H diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index 601b1bb36b..ecf6c7e992 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -3777,6 +3777,10 @@ void tst_Moc::testQNamespace() QCOMPARE(meta.name(), "TestEnum1"); QCOMPARE(meta.enclosingMetaObject(), &TestQNamespace::staticMetaObject); QCOMPARE(meta.keyCount(), 2); + + QCOMPARE(FooNamespace::staticMetaObject.enumeratorCount(), 1); + QCOMPARE(FooNamespace::FooNestedNamespace::staticMetaObject.enumeratorCount(), 2); + QCOMPARE(FooNamespace::FooNestedNamespace::FooMoreNestedNamespace::staticMetaObject.enumeratorCount(), 1); } QTEST_MAIN(tst_Moc)