AutoTest: Speed up Qt Test parser

The look up of function definitions is quite costly. Limit
it to the test data functions as we need them when looking
for data tags.
This limitation reduces the time of a full scan here by
more than 40% compared to without limitation.

Task-number: QTCREATORBUG-29301
Change-Id: Ia692aab8cfcc1c98ca9a2d53c935d7755314f736
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Stenger
2023-09-01 12:49:32 +02:00
parent 792c74b47a
commit 6b6d9dc21e
4 changed files with 48 additions and 21 deletions

View File

@@ -8,7 +8,9 @@
#include "../autotesttr.h"
#include "../itestframework.h"
#include <cplusplus/Symbol.h>
#include <cppeditor/cppmodelmanager.h>
#include <cppeditor/symbolfinder.h>
#include <projectexplorer/projectmanager.h>
@@ -16,8 +18,7 @@
using namespace Utils;
namespace Autotest {
namespace Internal {
namespace Autotest::Internal {
QtTestTreeItem::QtTestTreeItem(ITestFramework *testFramework, const QString &name,
const FilePath &filePath, TestTreeItem::Type type)
@@ -49,9 +50,11 @@ QVariant QtTestTreeItem::data(int column, int role) const
toolTip.append(Tr::tr("<p>Multiple testcases inside a single executable are not officially "
"supported. Depending on the implementation they might get executed "
"or not, but never will be explicitly selectable.</p>"));
} else if (type() == TestFunction) {
// avoid confusion (displaying header file, but ending up inside source)
toolTip = parentItem()->name() + "::" + name();
}
return toolTip;
break;
}
case Qt::CheckStateRole:
switch (type()) {
@@ -69,6 +72,13 @@ QVariant QtTestTreeItem::data(int column, int role) const
default:
return m_multiTest;
}
case LinkRole:
if (type() == GroupNode)
return QVariant();
if (type() == TestDataFunction || type() == TestDataTag)
return TestTreeItem::data(column, role);
// other functions would end up inside declaration - so, find its definition
return linkForTreeItem();
}
return TestTreeItem::data(column, role);
}
@@ -403,6 +413,26 @@ bool QtTestTreeItem::isGroupable() const
return type() == TestCase;
}
QVariant QtTestTreeItem::linkForTreeItem() const
{
QVariant itemLink;
using namespace CPlusPlus;
const Snapshot snapshot = CppEditor::CppModelManager::instance()->snapshot();
const Document::Ptr doc = snapshot.document(filePath());
Symbol *symbol = doc->lastVisibleSymbolAt(line(), this->column() + 1);
if (auto decl = symbol->asDeclaration()) {
static CppEditor::SymbolFinder symbolFinder;
if (Symbol *definition = symbolFinder.findMatchingDefinition(decl, snapshot, true);
definition && definition->fileId()) {
itemLink.setValue(Link(FilePath::fromUtf8(definition->fileName()),
definition->line(), definition->column() - 1));
}
}
if (!itemLink.isValid()) // fallback in case we failed to find the definition
itemLink.setValue(Link(filePath(), line(), this->column()));
return itemLink;
}
TestTreeItem *QtTestTreeItem::findChildByFileNameAndType(const FilePath &file,
const QString &name, Type type) const
{
@@ -438,5 +468,4 @@ QString QtTestTreeItem::nameSuffix() const
return suffix.isEmpty() ? suffix : QString{" [" + suffix + "]"};
}
} // namespace Internal
} // namespace Autotest
} // namespace Autotest::Internal

View File

@@ -5,8 +5,7 @@
#include "../testtreeitem.h"
namespace Autotest {
namespace Internal {
namespace Autotest::Internal {
class QtTestTreeItem : public TestTreeItem
{
@@ -36,6 +35,7 @@ public:
TestTreeItem *createParentGroupNode() const override;
bool isGroupable() const override;
private:
QVariant linkForTreeItem() const;
TestTreeItem *findChildByFileNameAndType(const Utils::FilePath &file, const QString &name,
Type type) const;
TestTreeItem *findChildByNameAndInheritanceAndMultiTest(const QString &name, bool inherited,
@@ -53,5 +53,4 @@ public:
typedef QVector<QtTestCodeLocationAndType> QtTestCodeLocationList;
} // namespace Internal
} // namespace Autotest
} // namespace Autotest::Internal

View File

@@ -14,8 +14,7 @@
using namespace CPlusPlus;
using namespace Utils;
namespace Autotest {
namespace Internal {
namespace Autotest::Internal {
static QStringList specialFunctions({"initTestCase", "cleanupTestCase", "init", "cleanup"});
@@ -49,10 +48,13 @@ bool TestVisitor::visit(Class *symbol)
const QString name = o.prettyName(func->name());
QtTestCodeLocationAndType locationAndType;
if (name.endsWith("_data")) {
// costly.. but we need at least the correct entry for finding data tags
Function *functionDefinition = m_symbolFinder.findMatchingDefinition(
func, m_snapshot, true);
if (functionDefinition && functionDefinition->fileId())
member = functionDefinition;
}
locationAndType.m_filePath = FilePath::fromUtf8(member->fileName());
locationAndType.m_line = member->line();
locationAndType.m_column = member->column() - 1;
@@ -281,5 +283,4 @@ bool TestDataFunctionVisitor::newRowCallFound(CallAST *ast, unsigned *firstToken
return found;
}
} // namespace Internal
} // namespace Autotest
} // namespace Autotest::Internal

View File

@@ -16,8 +16,7 @@
#include <QMap>
#include <QSet>
namespace Autotest {
namespace Internal {
namespace Autotest::Internal {
class TestVisitor : public CPlusPlus::SymbolVisitor
{
@@ -84,5 +83,4 @@ private:
bool m_insideUsingQTest = false;
};
} // namespace Internal
} // namespace Autotest
} // namespace Autotest::Internal