From 92db5afba48dffeb78287f0f319ef6ed89bfda4a Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 5 Jan 2017 10:34:03 +0100 Subject: [PATCH] AutoTest: Handle re-implemented test functions appropriate If a derived test case implements the same private slot as one of its base classes one of these information got lost as both were using the same key to store the information at. Additionally take care of what is possible and sensible when using QtTest and deriving test cases from others. Task-number: QTCREATORBUG-17522 Change-Id: I0d2a47c820d5eb002f8bdd851a07a4774e9838f0 Reviewed-by: David Schulz --- src/plugins/autotest/qtest/qttestparser.cpp | 81 +++++++++++++++---- src/plugins/autotest/qtest/qttestvisitors.cpp | 2 +- 2 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/plugins/autotest/qtest/qttestparser.cpp b/src/plugins/autotest/qtest/qttestparser.cpp index d42945529e3..35b82fa62ed 100644 --- a/src/plugins/autotest/qtest/qttestparser.cpp +++ b/src/plugins/autotest/qtest/qttestparser.cpp @@ -30,6 +30,7 @@ #include "../autotest_utils.h" #include +#include namespace Autotest { namespace Internal { @@ -175,24 +176,67 @@ static QMap checkForDataTags(const QString &fil return visitor.dataTags(); } -static QMap baseClassTestFunctions(const QSet &bases, - const CPlusPlus::Document::Ptr &doc, const CPlusPlus::Snapshot &snapshot) +/*! + * \brief Checks whether \a testFunctions (keys are full qualified names) contains already the + * given \a function (unqualified name). + * + * \return true if this function is already contained, false otherwise + */ +static bool containsFunction(const QMap &testFunctions, + const QString &function) { - QMap testFunctions; - for (const QString &baseClassName : bases) { - TestVisitor baseVisitor(baseClassName, snapshot); + const QString search = "::" + function; + return Utils::anyOf(testFunctions.keys(), [&search] (const QString &key) { + return key.endsWith(search); + }); +} + +static void mergeTestFunctions(QMap &testFunctions, + const QMap &inheritedFunctions) +{ + static const QString dataSuffix("_data"); + // take over only inherited test functions that have not been re-implemented + QMap::ConstIterator it = inheritedFunctions.begin(); + QMap::ConstIterator end = inheritedFunctions.end(); + for ( ; it != end; ++it) { + const QString functionName = it.key(); + const QString &shortName = functionName.mid(functionName.lastIndexOf(':') + 1); + if (shortName.endsWith(dataSuffix)) { + const QString &correspondingFunc = functionName.left(functionName.size() + - dataSuffix.size()); + // inherited test data functions only if we're inheriting the corresponding test + // function as well (and the inherited test function is not omitted) + if (inheritedFunctions.contains(correspondingFunc)) { + if (!testFunctions.contains(correspondingFunc)) + continue; + testFunctions.insert(functionName, it.value()); + } + } else if (!containsFunction(testFunctions, shortName)) { + // normal test functions only if not re-implemented + testFunctions.insert(functionName, it.value()); + } + } +} + +static void fetchAndMergeBaseTestFunctions(const QSet &baseClasses, + QMap &testFunctions, + const CPlusPlus::Document::Ptr &doc, + const CPlusPlus::Snapshot &snapshot) +{ + QList bases = baseClasses.toList(); + while (!bases.empty()) { + const QString base = bases.takeFirst(); + TestVisitor baseVisitor(base, snapshot); baseVisitor.setInheritedMode(true); - CPlusPlus::Document::Ptr declaringDoc = declaringDocument(doc, snapshot, baseClassName); + CPlusPlus::Document::Ptr declaringDoc = declaringDocument(doc, snapshot, base); if (declaringDoc.isNull()) continue; baseVisitor.accept(declaringDoc->globalNamespace()); - if (baseVisitor.resultValid()) - testFunctions.unite(baseVisitor.privateSlots()); - const QSet currentBaseBases = baseVisitor.baseClasses(); - // recursively check base classes - testFunctions.unite(baseClassTestFunctions(currentBaseBases, doc, snapshot)); + if (!baseVisitor.resultValid()) + continue; + bases.append(baseVisitor.baseClasses().toList()); + mergeTestFunctions(testFunctions, baseVisitor.privateSlots()); } - return testFunctions; } static QtTestCodeLocationList tagLocationsFor(const QtTestParseResult *func, @@ -239,8 +283,11 @@ static bool handleQtTest(QFutureInterface futureInterface, return false; QMap testFunctions = visitor.privateSlots(); - // gather appropriate information of base classes as well - testFunctions.unite(baseClassTestFunctions(visitor.baseClasses(), declaringDoc, snapshot)); + // gather appropriate information of base classes as well and merge into already found + // functions - but only as far as QtTest can handle this appropriate + fetchAndMergeBaseTestFunctions( + visitor.baseClasses(), testFunctions, declaringDoc, snapshot); + const QSet &files = filesWithDataFunctionDefinitions(testFunctions); // TODO: change to QHash<> @@ -263,10 +310,12 @@ static bool handleQtTest(QFutureInterface futureInterface, const QMap::ConstIterator end = testFunctions.end(); for ( ; it != end; ++it) { const QtTestCodeLocationAndType &location = it.value(); + QString functionName = it.key(); + functionName = functionName.mid(functionName.lastIndexOf(':') + 1); QtTestParseResult *func = new QtTestParseResult(id); func->itemType = location.m_type; - func->name = testCaseName + "::" + it.key(); - func->displayName = it.key(); + func->name = testCaseName + "::" + functionName; + func->displayName = functionName; func->fileName = location.m_name; func->line = location.m_line; func->column = location.m_column; diff --git a/src/plugins/autotest/qtest/qttestvisitors.cpp b/src/plugins/autotest/qtest/qttestvisitors.cpp index 4b6b53b3dae..ca68f20581e 100644 --- a/src/plugins/autotest/qtest/qttestvisitors.cpp +++ b/src/plugins/autotest/qtest/qttestvisitors.cpp @@ -84,7 +84,7 @@ bool TestVisitor::visit(CPlusPlus::Class *symbol) else locationAndType.m_type = TestTreeItem::TestFunctionOrSet; locationAndType.m_inherited = m_inherited; - m_privSlots.insert(name, locationAndType); + m_privSlots.insert(className + "::" + name, locationAndType); } } for (unsigned counter = 0, end = symbol->baseClassCount(); counter < end; ++counter) {