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) {