forked from qt-creator/qt-creator
Rework the parsing and fixing detection of changes
Additionally * fixed some deletion of pointers * const correctness * small refactorings for readability * better separation of responsibilities
This commit is contained in:
committed by
Christian Stenger
parent
eca8e2faba
commit
345b4de47a
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#include <projectexplorer/session.h>
|
#include <projectexplorer/session.h>
|
||||||
|
|
||||||
|
#include <utils/textfileformat.h>
|
||||||
|
|
||||||
namespace Autotest {
|
namespace Autotest {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -40,17 +42,18 @@ TestCodeParser::TestCodeParser(TestTreeModel *parent)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestCodeParser::~TestCodeParser()
|
||||||
|
{
|
||||||
|
clearMaps();
|
||||||
|
}
|
||||||
|
|
||||||
void TestCodeParser::updateTestTree()
|
void TestCodeParser::updateTestTree()
|
||||||
{
|
{
|
||||||
qDebug("updating TestTreeModel");
|
qDebug("updating TestTreeModel");
|
||||||
m_model->beginResetModel();
|
|
||||||
qDeleteAll(m_cppDocMap);
|
clearMaps();
|
||||||
m_cppDocMap.clear();
|
m_model->removeAllAutoTests();
|
||||||
QModelIndex autoTestRootIndex = m_model->index(0, 0);
|
const ProjectExplorer::SessionManager *session = ProjectExplorer::SessionManager::instance();
|
||||||
TestTreeItem *autoTestRootItem = static_cast<TestTreeItem *>(autoTestRootIndex.internalPointer());
|
|
||||||
autoTestRootItem->removeChildren();
|
|
||||||
m_model->endResetModel();
|
|
||||||
ProjectExplorer::SessionManager *session = ProjectExplorer::SessionManager::instance();
|
|
||||||
if (!session || !session->hasProjects())
|
if (!session || !session->hasProjects())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -62,12 +65,30 @@ void TestCodeParser::updateTestTree()
|
|||||||
|
|
||||||
/****** scan for QTest related stuff helpers ******/
|
/****** scan for QTest related stuff helpers ******/
|
||||||
|
|
||||||
|
static QByteArray getFileContent(QString filePath)
|
||||||
|
{
|
||||||
|
QByteArray fileContent;
|
||||||
|
CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
|
||||||
|
CppTools::WorkingCopy wc = cppMM->workingCopy();
|
||||||
|
if (wc.contains(filePath)) {
|
||||||
|
fileContent = wc.source(filePath);
|
||||||
|
} else {
|
||||||
|
QString error;
|
||||||
|
const QTextCodec *codec = Core::EditorManager::defaultTextCodec();
|
||||||
|
if (Utils::TextFileFormat::readFileUTF8(filePath, codec, &fileContent, &error)
|
||||||
|
!= Utils::TextFileFormat::ReadSuccess) {
|
||||||
|
qDebug() << "Failed to read file" << filePath << ":" << error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fileContent;
|
||||||
|
}
|
||||||
|
|
||||||
static bool includesQtTest(const CPlusPlus::Document::Ptr &doc,
|
static bool includesQtTest(const CPlusPlus::Document::Ptr &doc,
|
||||||
const CppTools::CppModelManager *cppMM)
|
const CppTools::CppModelManager *cppMM)
|
||||||
{
|
{
|
||||||
QList<CPlusPlus::Document::Include> includes = doc->resolvedIncludes();
|
const QList<CPlusPlus::Document::Include> includes = doc->resolvedIncludes();
|
||||||
|
|
||||||
foreach (CPlusPlus::Document::Include inc, includes) {
|
foreach (const CPlusPlus::Document::Include inc, includes) {
|
||||||
// TODO this short cut works only for #include <QtTest>
|
// TODO this short cut works only for #include <QtTest>
|
||||||
// bad, as there could be much more different approaches
|
// bad, as there could be much more different approaches
|
||||||
if (inc.unresolvedFileName() == QLatin1String("QtTest")
|
if (inc.unresolvedFileName() == QLatin1String("QtTest")
|
||||||
@@ -78,8 +99,8 @@ static bool includesQtTest(const CPlusPlus::Document::Ptr &doc,
|
|||||||
|
|
||||||
if (cppMM) {
|
if (cppMM) {
|
||||||
CPlusPlus::Snapshot snapshot = cppMM->snapshot();
|
CPlusPlus::Snapshot snapshot = cppMM->snapshot();
|
||||||
QSet<QString> includes = snapshot.allIncludesForDocument(doc->fileName());
|
const QSet<QString> allIncludes = snapshot.allIncludesForDocument(doc->fileName());
|
||||||
foreach (QString include, includes) {
|
foreach (const QString include, allIncludes) {
|
||||||
if (include.endsWith(QLatin1String("QtTest/qtest.h"))) {
|
if (include.endsWith(QLatin1String("QtTest/qtest.h"))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -91,11 +112,9 @@ static bool includesQtTest(const CPlusPlus::Document::Ptr &doc,
|
|||||||
static bool qtTestLibDefined(const CppTools::CppModelManager *cppMM,
|
static bool qtTestLibDefined(const CppTools::CppModelManager *cppMM,
|
||||||
const QString &fileName)
|
const QString &fileName)
|
||||||
{
|
{
|
||||||
QList<CppTools::ProjectPart::Ptr> parts = cppMM->projectPart(fileName);
|
const QList<CppTools::ProjectPart::Ptr> parts = cppMM->projectPart(fileName);
|
||||||
if (parts.size() > 0) {
|
if (parts.size() > 0)
|
||||||
QByteArray projDefines = parts.at(0)->projectDefines;
|
return parts.at(0)->projectDefines.contains("#define QT_TESTLIB_LIB 1");
|
||||||
return projDefines.contains("#define QT_TESTLIB_LIB 1");
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,33 +122,16 @@ static QString testClass(const CPlusPlus::Document::Ptr &doc)
|
|||||||
{
|
{
|
||||||
static QByteArray qtTestMacros[] = {"QTEST_MAIN", "QTEST_APPLESS_MAIN", "QTEST_GUILESS_MAIN"};
|
static QByteArray qtTestMacros[] = {"QTEST_MAIN", "QTEST_APPLESS_MAIN", "QTEST_GUILESS_MAIN"};
|
||||||
QString tC;
|
QString tC;
|
||||||
QList<CPlusPlus::Document::MacroUse> macros = doc->macroUses();
|
const QList<CPlusPlus::Document::MacroUse> macros = doc->macroUses();
|
||||||
|
|
||||||
foreach (CPlusPlus::Document::MacroUse macro, macros) {
|
foreach (const CPlusPlus::Document::MacroUse macro, macros) {
|
||||||
if (!macro.isFunctionLike())
|
if (!macro.isFunctionLike())
|
||||||
continue;
|
continue;
|
||||||
QByteArray name = macro.macro().name();
|
const QByteArray name = macro.macro().name();
|
||||||
if (name == qtTestMacros[0] || name == qtTestMacros[1] || name == qtTestMacros[2]) {
|
if (name == qtTestMacros[0] || name == qtTestMacros[1] || name == qtTestMacros[2]) {
|
||||||
CPlusPlus::Document::Block arg = macro.arguments().at(0);
|
CPlusPlus::Document::Block arg = macro.arguments().at(0);
|
||||||
CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
|
tC = QLatin1String(getFileContent(doc->fileName()).mid(arg.bytesBegin(),
|
||||||
|
arg.bytesEnd() - arg.bytesBegin()));
|
||||||
// TODO high costs....?!
|
|
||||||
CppTools::WorkingCopy wc = cppMM->workingCopy();
|
|
||||||
if (wc.contains(doc->fileName())) {
|
|
||||||
QByteArray src = wc.source(doc->fileName());
|
|
||||||
tC = QLatin1String(src.mid(arg.bytesBegin(), arg.bytesEnd() - arg.bytesBegin()));
|
|
||||||
} else {
|
|
||||||
QFile current(doc->fileName());
|
|
||||||
if (current.exists() && current.open(QFile::ReadOnly)) {
|
|
||||||
CPlusPlus::Document::Block arg = macro.arguments().at(0);
|
|
||||||
if (current.seek(arg.bytesBegin())) {
|
|
||||||
QByteArray res = current.read(arg.bytesEnd() - arg.bytesBegin());
|
|
||||||
if (!res.isEmpty())
|
|
||||||
tC = QLatin1String(res);
|
|
||||||
}
|
|
||||||
current.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,53 +143,64 @@ static QString testClass(const CPlusPlus::Document::Ptr &doc)
|
|||||||
void TestCodeParser::checkDocumentForTestCode(CPlusPlus::Document::Ptr doc)
|
void TestCodeParser::checkDocumentForTestCode(CPlusPlus::Document::Ptr doc)
|
||||||
{
|
{
|
||||||
const QString file = doc->fileName();
|
const QString file = doc->fileName();
|
||||||
CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
|
const CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
|
||||||
|
|
||||||
if (includesQtTest(doc, cppMM) && qtTestLibDefined(cppMM, file)) {
|
if (includesQtTest(doc, cppMM) && qtTestLibDefined(cppMM, file)) {
|
||||||
QString tc = testClass(doc);
|
QString tc(testClass(doc));
|
||||||
if (tc.isEmpty()) {
|
if (tc.isEmpty()) {
|
||||||
// one might have used an approach without macros or defined own macros
|
// one might have used an approach without macros or defined own macros
|
||||||
QString src = QLatin1String(doc->utf8Source()); // does not work anymore - src is always ""
|
const CPlusPlus::Snapshot snapshot = cppMM->snapshot();
|
||||||
if (src.contains(QLatin1String("QTest::qExec"))) {
|
const QByteArray fileContent = getFileContent(file);
|
||||||
qDebug() << "Src\n===============\n" << src << "\n=============\n";
|
doc = snapshot.preprocessedDocument(fileContent, file);
|
||||||
// TODO extract the class name by using the AST - using regex is too problematic as this
|
doc->check();
|
||||||
// does not take comments and typedefs or whatever into account....
|
CPlusPlus::AST *ast = doc->translationUnit()->ast();
|
||||||
qDebug() << "Currently not supported approach... (self-defined macro / QTest::qExec() call/...)";
|
TestAstVisitor astVisitor(doc);
|
||||||
}
|
astVisitor.accept(ast);
|
||||||
} else {
|
tc = astVisitor.className();
|
||||||
QModelIndex autoTestRootIndex = m_model->index(0, 0);
|
}
|
||||||
|
if (!tc.isEmpty()) {
|
||||||
|
// construct the new/modified TestTreeItem
|
||||||
|
const QModelIndex autoTestRootIndex = m_model->index(0, 0);
|
||||||
TestTreeItem *autoTestRootItem = static_cast<TestTreeItem *>(autoTestRootIndex.internalPointer());
|
TestTreeItem *autoTestRootItem = static_cast<TestTreeItem *>(autoTestRootIndex.internalPointer());
|
||||||
TestTreeItem *ttItem = new TestTreeItem(tc, file, TestTreeItem::TEST_CLASS,
|
TestTreeItem *ttItem = new TestTreeItem(tc, file, TestTreeItem::TEST_CLASS,
|
||||||
autoTestRootItem);
|
autoTestRootItem);
|
||||||
|
QString declFileName;
|
||||||
CPlusPlus::TypeOfExpression toe;
|
CPlusPlus::TypeOfExpression toe;
|
||||||
toe.init(doc, cppMM->snapshot());
|
toe.init(doc, cppMM->snapshot());
|
||||||
CPlusPlus::Document::Ptr declaringDoc = doc;
|
CPlusPlus::Document::Ptr declaringDoc = doc;
|
||||||
QList<CPlusPlus::LookupItem> toeItems = toe(tc.toUtf8(), doc->globalNamespace());
|
const QList<CPlusPlus::LookupItem> toeItems = toe(tc.toUtf8(), doc->globalNamespace());
|
||||||
if (toeItems.size()) {
|
if (toeItems.size()) {
|
||||||
CPlusPlus::Class *toeClass = toeItems.first().declaration()->asClass();
|
CPlusPlus::Class *toeClass = toeItems.first().declaration()->asClass();
|
||||||
QString declFileName = QLatin1String(toeClass->fileId()->chars(),
|
declFileName = QLatin1String(toeClass->fileId()->chars(),
|
||||||
toeClass->fileId()->size());
|
toeClass->fileId()->size());
|
||||||
declaringDoc = cppMM->snapshot().document(declFileName);
|
declaringDoc = cppMM->snapshot().document(declFileName);
|
||||||
ttItem->setFilePath(declFileName);
|
ttItem->setFilePath(declFileName);
|
||||||
ttItem->setLine(toeClass->line());
|
ttItem->setLine(toeClass->line());
|
||||||
ttItem->setColumn(toeClass->column() - 1);
|
ttItem->setColumn(toeClass->column() - 1);
|
||||||
}
|
}
|
||||||
if (declaringDoc.isNull())
|
if (declaringDoc.isNull()) {
|
||||||
|
delete ttItem;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
TestVisitor myVisitor(tc);
|
TestVisitor myVisitor(tc);
|
||||||
myVisitor.accept(declaringDoc->globalNamespace());
|
myVisitor.accept(declaringDoc->globalNamespace());
|
||||||
QMap<QString, TestCodeLocation> privSlots = myVisitor.privateSlots();
|
const QMap<QString, TestCodeLocation> privSlots = myVisitor.privateSlots();
|
||||||
foreach (const QString privS, privSlots.keys()) {
|
foreach (const QString privS, privSlots.keys()) {
|
||||||
TestCodeLocation location = privSlots.value(privS);
|
const TestCodeLocation location = privSlots.value(privS);
|
||||||
TestTreeItem *ttSub = new TestTreeItem(privS, location.m_fileName,
|
TestTreeItem *ttSub = new TestTreeItem(privS, location.m_fileName,
|
||||||
TestTreeItem::TEST_FUNCTION, ttItem);
|
TestTreeItem::TEST_FUNCTION, ttItem);
|
||||||
ttSub->setLine(location.m_line);
|
ttSub->setLine(location.m_line);
|
||||||
ttSub->setColumn(location.m_column);
|
ttSub->setColumn(location.m_column);
|
||||||
ttItem->appendChild(ttSub);
|
ttItem->appendChild(ttSub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO refactoring?
|
||||||
|
// update model and internal map
|
||||||
|
TestInfo *info;
|
||||||
|
int count;
|
||||||
if (m_cppDocMap.contains(file)) {
|
if (m_cppDocMap.contains(file)) {
|
||||||
TestInfo *info = m_cppDocMap[file];
|
info = m_cppDocMap[file];
|
||||||
int count = autoTestRootItem->childCount();
|
count = autoTestRootItem->childCount();
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
TestTreeItem *currentItem = autoTestRootItem->child(i);
|
TestTreeItem *currentItem = autoTestRootItem->child(i);
|
||||||
if (currentItem->filePath() == file) {
|
if (currentItem->filePath() == file) {
|
||||||
@@ -199,13 +212,40 @@ void TestCodeParser::checkDocumentForTestCode(CPlusPlus::Document::Ptr doc)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
info = m_cppDocMap[declFileName];
|
||||||
|
count = autoTestRootItem->childCount();
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
TestTreeItem *currentItem = autoTestRootItem->child(i);
|
||||||
|
if (currentItem->filePath() == declFileName) {
|
||||||
|
m_model->modifyAutoTestSubtree(i, ttItem);
|
||||||
|
TestInfo *ti = new TestInfo(tc, privSlots.keys(),
|
||||||
|
doc->revision(),
|
||||||
|
doc->editorRevision());
|
||||||
|
ti->setReferencingFile(file);
|
||||||
|
m_cppDocMap.insert(declFileName, ti);
|
||||||
|
delete info;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
delete ttItem;
|
delete ttItem;
|
||||||
} else {
|
} else {
|
||||||
m_model->beginInsertRows(autoTestRootIndex, autoTestRootItem->childCount(), autoTestRootItem->childCount());
|
m_model->addAutoTest(ttItem);
|
||||||
autoTestRootItem->appendChild(ttItem);
|
|
||||||
m_model->endInsertRows();
|
|
||||||
m_cppDocMap.insert(file, new TestInfo(tc, privSlots.keys(),
|
m_cppDocMap.insert(file, new TestInfo(tc, privSlots.keys(),
|
||||||
doc->revision(), doc->editorRevision()));
|
doc->revision(), doc->editorRevision()));
|
||||||
|
TestInfo *ti = new TestInfo(tc, privSlots.keys(),
|
||||||
|
doc->revision(), doc->editorRevision());
|
||||||
|
ti->setReferencingFile(file);
|
||||||
|
m_cppDocMap.insert(declFileName, ti);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// could not find the class to test, but QTest is included and QT_TESTLIB_LIB defined
|
||||||
|
// maybe file is only a referenced file
|
||||||
|
if (m_cppDocMap.contains(file)) {
|
||||||
|
const TestInfo *info = m_cppDocMap[file];
|
||||||
|
CPlusPlus::Snapshot snapshot = cppMM->snapshot();
|
||||||
|
if (snapshot.contains(info->referencingFile())) {
|
||||||
|
checkDocumentForTestCode(snapshot.find(info->referencingFile()).value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,24 +255,22 @@ void TestCodeParser::onDocumentUpdated(CPlusPlus::Document::Ptr doc)
|
|||||||
{
|
{
|
||||||
if (!m_currentProject)
|
if (!m_currentProject)
|
||||||
return;
|
return;
|
||||||
QString fileName = doc->fileName();
|
const QString fileName = doc->fileName();
|
||||||
if (!m_cppDocMap.contains(fileName)) {
|
if (m_cppDocMap.contains(fileName)) {
|
||||||
if (!m_currentProject->files(ProjectExplorer::Project::AllFiles).contains(fileName)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (m_cppDocMap[fileName]->revision() == doc->revision()
|
if (m_cppDocMap[fileName]->revision() == doc->revision()
|
||||||
&& m_cppDocMap[fileName]->editorRevision() == doc->editorRevision()) {
|
&& m_cppDocMap[fileName]->editorRevision() == doc->editorRevision()) {
|
||||||
qDebug("Skipped due revision equality"); // added to verify if this ever happens..
|
qDebug("Skipped due revision equality"); // added to verify if this ever happens..
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (!m_currentProject->files(ProjectExplorer::Project::AllFiles).contains(fileName)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
checkDocumentForTestCode(doc);
|
checkDocumentForTestCode(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestCodeParser::removeFiles(const QStringList &files)
|
void TestCodeParser::removeFiles(const QStringList &files)
|
||||||
{
|
{
|
||||||
foreach (QString file, files) {
|
foreach (const QString file, files) {
|
||||||
if (m_cppDocMap.contains(file)) {
|
if (m_cppDocMap.contains(file)) {
|
||||||
TestInfo *info = m_cppDocMap.value(file);
|
TestInfo *info = m_cppDocMap.value(file);
|
||||||
m_cppDocMap.remove(file);
|
m_cppDocMap.remove(file);
|
||||||
@@ -244,11 +282,11 @@ void TestCodeParser::removeFiles(const QStringList &files)
|
|||||||
|
|
||||||
void TestCodeParser::scanForTests()
|
void TestCodeParser::scanForTests()
|
||||||
{
|
{
|
||||||
QStringList list = m_currentProject->files(ProjectExplorer::Project::AllFiles);
|
const QStringList list = m_currentProject->files(ProjectExplorer::Project::AllFiles);
|
||||||
CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
|
CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
|
||||||
CPlusPlus::Snapshot snapshot = cppMM->snapshot();
|
CPlusPlus::Snapshot snapshot = cppMM->snapshot();
|
||||||
|
|
||||||
foreach (QString file, list) {
|
foreach (const QString file, list) {
|
||||||
if (snapshot.contains(file)) {
|
if (snapshot.contains(file)) {
|
||||||
CPlusPlus::Document::Ptr doc = snapshot.find(file).value();
|
CPlusPlus::Document::Ptr doc = snapshot.find(file).value();
|
||||||
checkDocumentForTestCode(doc);
|
checkDocumentForTestCode(doc);
|
||||||
@@ -256,5 +294,15 @@ void TestCodeParser::scanForTests()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestCodeParser::clearMaps()
|
||||||
|
{
|
||||||
|
QMap<QString, TestInfo *>::iterator it = m_cppDocMap.begin();
|
||||||
|
while (it != m_cppDocMap.end()) {
|
||||||
|
delete it.value();
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
m_cppDocMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Autotest
|
} // namespace Autotest
|
||||||
|
@@ -39,6 +39,7 @@ class TestCodeParser : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit TestCodeParser(TestTreeModel *parent = 0);
|
explicit TestCodeParser(TestTreeModel *parent = 0);
|
||||||
|
virtual ~TestCodeParser();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
@@ -51,6 +52,7 @@ public slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void scanForTests();
|
void scanForTests();
|
||||||
|
void clearMaps();
|
||||||
|
|
||||||
TestTreeModel *m_model;
|
TestTreeModel *m_model;
|
||||||
QMap<QString, TestInfo*> m_cppDocMap;
|
QMap<QString, TestInfo*> m_cppDocMap;
|
||||||
|
@@ -39,12 +39,15 @@ public:
|
|||||||
void setRevision(unsigned revision) { m_revision = revision; }
|
void setRevision(unsigned revision) { m_revision = revision; }
|
||||||
unsigned editorRevision() const { return m_editorRevision; }
|
unsigned editorRevision() const { return m_editorRevision; }
|
||||||
void setEditorRevision(unsigned editorRevision) { m_editorRevision = editorRevision; }
|
void setEditorRevision(unsigned editorRevision) { m_editorRevision = editorRevision; }
|
||||||
|
const QString referencingFile() const { return m_referencingFile; }
|
||||||
|
void setReferencingFile(const QString &refFile) {m_referencingFile = refFile; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_className;
|
QString m_className;
|
||||||
QStringList m_functions;
|
QStringList m_functions;
|
||||||
unsigned m_revision;
|
unsigned m_revision;
|
||||||
unsigned m_editorRevision;
|
unsigned m_editorRevision;
|
||||||
|
QString m_referencingFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -86,7 +86,9 @@ void TestRunner::runTests()
|
|||||||
ProjectExplorer::Internal::ProjectExplorerSettings pes = pep->projectExplorerSettings();
|
ProjectExplorer::Internal::ProjectExplorerSettings pes = pep->projectExplorerSettings();
|
||||||
if (pes.buildBeforeDeploy) {
|
if (pes.buildBeforeDeploy) {
|
||||||
if (!project->hasActiveBuildSettings()) {
|
if (!project->hasActiveBuildSettings()) {
|
||||||
qDebug() << "no active build settings...???"; // let it configure?
|
TestResultsPane::instance()->addTestResult(
|
||||||
|
TestResult(QString(), QString(), QString(), ResultType::MESSAGE_FATAL,
|
||||||
|
tr("*** Project is not configured - canceling Test Run ***")));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
buildProject(project);
|
buildProject(project);
|
||||||
|
@@ -263,29 +263,30 @@ static void addProjectInformation(TestConfiguration *config, const QString &file
|
|||||||
project = projParts.at(0)->project; // necessary to grab this here? or should this be the current active startup project anyway?
|
project = projParts.at(0)->project; // necessary to grab this here? or should this be the current active startup project anyway?
|
||||||
}
|
}
|
||||||
if (project) {
|
if (project) {
|
||||||
ProjectExplorer::Target *target = project->activeTarget();
|
if (auto target = project->activeTarget()) {
|
||||||
ProjectExplorer::BuildTargetInfoList appTargets = target->applicationTargets();
|
ProjectExplorer::BuildTargetInfoList appTargets = target->applicationTargets();
|
||||||
foreach (ProjectExplorer::BuildTargetInfo bti, appTargets.list) {
|
foreach (ProjectExplorer::BuildTargetInfo bti, appTargets.list) {
|
||||||
if (bti.isValid() && bti.projectFilePath.toString() == proFile) {
|
if (bti.isValid() && bti.projectFilePath.toString() == proFile) {
|
||||||
targetFile = bti.targetFilePath.toString();
|
targetFile = bti.targetFilePath.toString();
|
||||||
targetName = bti.targetName;
|
targetName = bti.targetName;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<ProjectExplorer::RunConfiguration *> rcs = target->runConfigurations();
|
|
||||||
foreach (ProjectExplorer::RunConfiguration *rc, rcs) {
|
|
||||||
if (ProjectExplorer::LocalApplicationRunConfiguration *localRunConfiguration
|
|
||||||
= qobject_cast<ProjectExplorer::LocalApplicationRunConfiguration *>(rc)) {
|
|
||||||
if (localRunConfiguration->executable() == targetFile) {
|
|
||||||
workDir = Utils::FileUtils::normalizePathName(
|
|
||||||
localRunConfiguration->workingDirectory());
|
|
||||||
ProjectExplorer::EnvironmentAspect *envAsp
|
|
||||||
= localRunConfiguration->extraAspect<ProjectExplorer::EnvironmentAspect>();
|
|
||||||
env = envAsp->environment();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<ProjectExplorer::RunConfiguration *> rcs = target->runConfigurations();
|
||||||
|
foreach (ProjectExplorer::RunConfiguration *rc, rcs) {
|
||||||
|
if (ProjectExplorer::LocalApplicationRunConfiguration *localRunConfiguration
|
||||||
|
= qobject_cast<ProjectExplorer::LocalApplicationRunConfiguration *>(rc)) {
|
||||||
|
if (localRunConfiguration->executable() == targetFile) {
|
||||||
|
workDir = Utils::FileUtils::normalizePathName(
|
||||||
|
localRunConfiguration->workingDirectory());
|
||||||
|
ProjectExplorer::EnvironmentAspect *envAsp
|
||||||
|
= localRunConfiguration->extraAspect<ProjectExplorer::EnvironmentAspect>();
|
||||||
|
env = envAsp->environment();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
config->setTargetFile(targetFile);
|
config->setTargetFile(targetFile);
|
||||||
@@ -438,5 +439,19 @@ void TestTreeModel::removeAutoTestSubtreeByFilePath(const QString &file)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestTreeModel::addAutoTest(TestTreeItem *newItem)
|
||||||
|
{
|
||||||
|
beginInsertRows(index(0, 0), m_autoTestRootItem->childCount(), m_autoTestRootItem->childCount());
|
||||||
|
m_autoTestRootItem->appendChild(newItem);
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTreeModel::removeAllAutoTests()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_autoTestRootItem->removeChildren();
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Autotest
|
} // namespace Autotest
|
||||||
|
@@ -61,13 +61,15 @@ public:
|
|||||||
QList<TestConfiguration *> getAllTestCases() const;
|
QList<TestConfiguration *> getAllTestCases() const;
|
||||||
QList<TestConfiguration *> getSelectedTests() const;
|
QList<TestConfiguration *> getSelectedTests() const;
|
||||||
|
|
||||||
|
void modifyAutoTestSubtree(int row, TestTreeItem *newItem);
|
||||||
|
void removeAutoTestSubtreeByFilePath(const QString &file);
|
||||||
|
void addAutoTest(TestTreeItem *newItem);
|
||||||
|
void removeAllAutoTests();
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void modifyAutoTestSubtree(int row, TestTreeItem *newItem);
|
|
||||||
void removeAutoTestSubtreeByFilePath(const QString &file);
|
|
||||||
explicit TestTreeModel(QObject *parent = 0);
|
explicit TestTreeModel(QObject *parent = 0);
|
||||||
|
|
||||||
TestTreeItem *m_rootItem;
|
TestTreeItem *m_rootItem;
|
||||||
@@ -75,7 +77,6 @@ private:
|
|||||||
// TestTreeItem *m_quickTestRootItem;
|
// TestTreeItem *m_quickTestRootItem;
|
||||||
TestCodeParser *m_parser;
|
TestCodeParser *m_parser;
|
||||||
|
|
||||||
friend class TestCodeParser;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -18,9 +18,13 @@
|
|||||||
|
|
||||||
#include "testvisitor.h"
|
#include "testvisitor.h"
|
||||||
|
|
||||||
|
#include <cplusplus/FullySpecifiedType.h>
|
||||||
#include <cplusplus/LookupContext.h>
|
#include <cplusplus/LookupContext.h>
|
||||||
#include <cplusplus/Overview.h>
|
#include <cplusplus/Overview.h>
|
||||||
#include <cplusplus/Symbols.h>
|
#include <cplusplus/Symbols.h>
|
||||||
|
#include <cplusplus/TypeOfExpression.h>
|
||||||
|
|
||||||
|
#include <cpptools/cppmodelmanager.h>
|
||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
|
||||||
@@ -57,7 +61,7 @@ bool TestVisitor::visit(CPlusPlus::Class *symbol)
|
|||||||
|
|
||||||
if (auto func = type->asFunctionType()) {
|
if (auto func = type->asFunctionType()) {
|
||||||
if (func->isSlot() && member->isPrivate()) {
|
if (func->isSlot() && member->isPrivate()) {
|
||||||
QString name = o.prettyName(func->name());
|
const QString name = o.prettyName(func->name());
|
||||||
if (!ignoredFunctions.contains(name) && !name.endsWith(QLatin1String("_data"))) {
|
if (!ignoredFunctions.contains(name) && !name.endsWith(QLatin1String("_data"))) {
|
||||||
TestCodeLocation location;
|
TestCodeLocation location;
|
||||||
location.m_fileName = QLatin1String(member->fileName());
|
location.m_fileName = QLatin1String(member->fileName());
|
||||||
@@ -71,5 +75,54 @@ bool TestVisitor::visit(CPlusPlus::Class *symbol)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestAstVisitor::TestAstVisitor(CPlusPlus::Document::Ptr doc)
|
||||||
|
: ASTVisitor(doc->translationUnit()),
|
||||||
|
m_currentDoc(doc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TestAstVisitor::~TestAstVisitor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestAstVisitor::visit(CPlusPlus::CallAST *ast)
|
||||||
|
{
|
||||||
|
if (!m_currentScope || m_currentDoc.isNull())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (auto expressionAST = ast->base_expression) {
|
||||||
|
if (auto idExpressionAST = expressionAST->asIdExpression()) {
|
||||||
|
if (auto qualifiedNameAST = idExpressionAST->name->asQualifiedName()) {
|
||||||
|
const CPlusPlus::Overview o;
|
||||||
|
const QString prettyName = o.prettyName(qualifiedNameAST->name);
|
||||||
|
if (prettyName == QLatin1String("QTest::qExec")) {
|
||||||
|
if (auto expressionListAST = ast->expression_list) {
|
||||||
|
// first argument is the one we need
|
||||||
|
if (auto argumentExpressionAST = expressionListAST->value) {
|
||||||
|
CPlusPlus::TypeOfExpression toe;
|
||||||
|
CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
|
||||||
|
toe.init(m_currentDoc, cppMM->snapshot());
|
||||||
|
QList<CPlusPlus::LookupItem> toeItems
|
||||||
|
= toe(argumentExpressionAST, m_currentDoc, m_currentScope);
|
||||||
|
|
||||||
|
if (toeItems.size()) {
|
||||||
|
if (auto pointerType = toeItems.first().type()->asPointerType())
|
||||||
|
m_className = o.prettyType(pointerType->elementType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestAstVisitor::visit(CPlusPlus::CompoundStatementAST *ast)
|
||||||
|
{
|
||||||
|
m_currentScope = ast->symbol->asScope();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Autotest
|
} // namespace Autotest
|
||||||
|
@@ -19,6 +19,9 @@
|
|||||||
#ifndef TESTVISITOR_H
|
#ifndef TESTVISITOR_H
|
||||||
#define TESTVISITOR_H
|
#define TESTVISITOR_H
|
||||||
|
|
||||||
|
#include <cplusplus/ASTVisitor.h>
|
||||||
|
#include <cplusplus/CppDocument.h>
|
||||||
|
#include <cplusplus/Scope.h>
|
||||||
#include <cplusplus/SymbolVisitor.h>
|
#include <cplusplus/SymbolVisitor.h>
|
||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
@@ -48,6 +51,24 @@ private:
|
|||||||
QMap<QString, TestCodeLocation> m_privSlots;
|
QMap<QString, TestCodeLocation> m_privSlots;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TestAstVisitor : public CPlusPlus::ASTVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TestAstVisitor(CPlusPlus::Document::Ptr doc);
|
||||||
|
virtual ~TestAstVisitor();
|
||||||
|
|
||||||
|
bool visit(CPlusPlus::CallAST *ast);
|
||||||
|
bool visit(CPlusPlus::CompoundStatementAST *ast);
|
||||||
|
|
||||||
|
QString className() const { return m_className; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_className;
|
||||||
|
CPlusPlus::Scope *m_currentScope;
|
||||||
|
CPlusPlus::Document::Ptr m_currentDoc;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Autotest
|
} // namespace Autotest
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user