AutoTest: Do not lose information of base classes

In case the base class is defined outside of the file with the
derived class we are missing the correct entry point.
Work around this by getting alternative entry points beforehand
and using them if we cannot find a valid entry point.

Task-number: QTCREATORBUG-17522
Change-Id: I07ef87b2fcdac4f78240da9e57eaa518ff0f4d20
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Stenger
2017-01-04 13:56:20 +01:00
parent 4a634a23cf
commit 0ceea628b0
4 changed files with 47 additions and 6 deletions

View File

@@ -24,8 +24,8 @@
****************************************************************************/ ****************************************************************************/
#include "qttest_utils.h" #include "qttest_utils.h"
#include "qttesttreeitem.h"
#include "../testframeworkmanager.h" #include "../testframeworkmanager.h"
#include "../testtreeitem.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -42,8 +42,7 @@ bool isQTestMacro(const QByteArray &macro)
return valid.contains(macro); return valid.contains(macro);
} }
QHash<QString, QString> testCaseNamesForFiles(const Core::Id &id, QHash<QString, QString> testCaseNamesForFiles(const Core::Id &id, const QStringList &files)
const QStringList &files)
{ {
QHash<QString, QString> result; QHash<QString, QString> result;
TestTreeItem *rootNode = TestFrameworkManager::instance()->rootNodeForTestFramework(id); TestTreeItem *rootNode = TestFrameworkManager::instance()->rootNodeForTestFramework(id);
@@ -63,6 +62,27 @@ QHash<QString, QString> testCaseNamesForFiles(const Core::Id &id,
return result; return result;
} }
QMultiHash<QString, QString> alternativeFiles(const Core::Id &id, const QStringList &files)
{
QMultiHash<QString, QString> result;
TestTreeItem *rootNode = TestFrameworkManager::instance()->rootNodeForTestFramework(id);
QTC_ASSERT(rootNode, return result);
for (int row = 0, rootCount = rootNode->childCount(); row < rootCount; ++row) {
const TestTreeItem *child = rootNode->childItem(row);
const QString &baseFilePath = child->filePath();
for (int childRow = 0, count = child->childCount(); childRow < count; ++childRow) {
auto grandChild = static_cast<const QtTestTreeItem *>(child->childItem(childRow));
const QString &filePath = grandChild->filePath();
if (grandChild->inherited() && baseFilePath != filePath && files.contains(filePath)) {
if (!result.contains(filePath, baseFilePath))
result.insert(filePath, baseFilePath);
}
}
}
return result;
}
} // namespace QTestUtils } // namespace QTestUtils
} // namespace Internal } // namespace Internal
} // namespace Autotest } // namespace Autotest

View File

@@ -35,6 +35,7 @@ namespace QTestUtils {
bool isQTestMacro(const QByteArray &macro); bool isQTestMacro(const QByteArray &macro);
QHash<QString, QString> testCaseNamesForFiles(const Core::Id &id, const QStringList &files); QHash<QString, QString> testCaseNamesForFiles(const Core::Id &id, const QStringList &files);
QMultiHash<QString, QString> alternativeFiles(const Core::Id &id, const QStringList &files);
} // namespace QTestUtils } // namespace QTestUtils
} // namespace Internal } // namespace Internal

View File

@@ -109,14 +109,29 @@ static QString testClass(const CppTools::CppModelManager *modelManager,
static CPlusPlus::Document::Ptr declaringDocument(CPlusPlus::Document::Ptr doc, static CPlusPlus::Document::Ptr declaringDocument(CPlusPlus::Document::Ptr doc,
const CPlusPlus::Snapshot &snapshot, const CPlusPlus::Snapshot &snapshot,
const QString &testCaseName, const QString &testCaseName,
const QStringList &alternativeFiles = {},
unsigned *line = 0, unsigned *column = 0) unsigned *line = 0, unsigned *column = 0)
{ {
CPlusPlus::Document::Ptr declaringDoc = doc; CPlusPlus::Document::Ptr declaringDoc;
CPlusPlus::TypeOfExpression typeOfExpr; CPlusPlus::TypeOfExpression typeOfExpr;
typeOfExpr.init(doc, snapshot); typeOfExpr.init(doc, snapshot);
QList<CPlusPlus::LookupItem> lookupItems = typeOfExpr(testCaseName.toUtf8(), QList<CPlusPlus::LookupItem> lookupItems = typeOfExpr(testCaseName.toUtf8(),
doc->globalNamespace()); doc->globalNamespace());
// fallback for inherited functions
if (lookupItems.size() == 0 && !alternativeFiles.isEmpty()) {
for (const QString &alternativeFile : alternativeFiles) {
if (snapshot.contains(alternativeFile)) {
CPlusPlus::Document::Ptr document = snapshot.document(alternativeFile);
CPlusPlus::TypeOfExpression typeOfExpr; // we need a new one with no bindings
typeOfExpr.init(document, snapshot);
lookupItems = typeOfExpr(testCaseName.toUtf8(), document->globalNamespace());
if (lookupItems.size() != 0)
break;
}
}
}
if (lookupItems.size()) { if (lookupItems.size()) {
if (CPlusPlus::Symbol *symbol = lookupItems.first().declaration()) { if (CPlusPlus::Symbol *symbol = lookupItems.first().declaration()) {
if (CPlusPlus::Class *toeClass = symbol->asClass()) { if (CPlusPlus::Class *toeClass = symbol->asClass()) {
@@ -184,6 +199,7 @@ static bool handleQtTest(QFutureInterface<TestParseResultPtr> futureInterface,
CPlusPlus::Document::Ptr document, CPlusPlus::Document::Ptr document,
const CPlusPlus::Snapshot &snapshot, const CPlusPlus::Snapshot &snapshot,
const QString &oldTestCaseName, const QString &oldTestCaseName,
const QStringList &alternativeFiles,
const Core::Id &id) const Core::Id &id)
{ {
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
@@ -196,7 +212,7 @@ static bool handleQtTest(QFutureInterface<TestParseResultPtr> futureInterface,
unsigned line = 0; unsigned line = 0;
unsigned column = 0; unsigned column = 0;
CPlusPlus::Document::Ptr declaringDoc = declaringDocument(document, snapshot, testCaseName, CPlusPlus::Document::Ptr declaringDoc = declaringDocument(document, snapshot, testCaseName,
&line, &column); alternativeFiles, &line, &column);
if (declaringDoc.isNull()) if (declaringDoc.isNull())
return false; return false;
@@ -263,12 +279,14 @@ static bool handleQtTest(QFutureInterface<TestParseResultPtr> futureInterface,
void QtTestParser::init(const QStringList &filesToParse) void QtTestParser::init(const QStringList &filesToParse)
{ {
m_testCaseNames = QTestUtils::testCaseNamesForFiles(id(), filesToParse); m_testCaseNames = QTestUtils::testCaseNamesForFiles(id(), filesToParse);
m_alternativeFiles = QTestUtils::alternativeFiles(id(), filesToParse);
CppParser::init(filesToParse); CppParser::init(filesToParse);
} }
void QtTestParser::release() void QtTestParser::release()
{ {
m_testCaseNames.clear(); m_testCaseNames.clear();
m_alternativeFiles.clear();
CppParser::release(); CppParser::release();
} }
@@ -279,10 +297,11 @@ bool QtTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureIn
return false; return false;
CPlusPlus::Document::Ptr doc = m_cppSnapshot.find(fileName).value(); CPlusPlus::Document::Ptr doc = m_cppSnapshot.find(fileName).value();
const QString &oldName = m_testCaseNames.value(fileName); const QString &oldName = m_testCaseNames.value(fileName);
const QStringList &alternativeFiles = m_alternativeFiles.values(fileName);
if ((!includesQtTest(doc, m_cppSnapshot) || !qtTestLibDefined(fileName)) && oldName.isEmpty()) if ((!includesQtTest(doc, m_cppSnapshot) || !qtTestLibDefined(fileName)) && oldName.isEmpty())
return false; return false;
return handleQtTest(futureInterface, doc, m_cppSnapshot, oldName, id()); return handleQtTest(futureInterface, doc, m_cppSnapshot, oldName, alternativeFiles, id());
} }
} // namespace Internal } // namespace Internal

View File

@@ -51,6 +51,7 @@ public:
private: private:
QHash<QString, QString> m_testCaseNames; QHash<QString, QString> m_testCaseNames;
QMultiHash<QString, QString> m_alternativeFiles;
}; };
} // namespace Internal } // namespace Internal