From 5d7f2d7444e3542cfece720aa6f81be741eb6d26 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Fri, 1 Jan 2021 19:19:10 +0100 Subject: [PATCH] AutoTest: Use working copy of own parser In TestCodeParser::syncTestFrameworks(), a parser is created for every test framework. As a result, the last parser being created would "win" the global s_parserInstance variable, which is not predictable and probably not intended. So turn CppParser::getFileContent() into a non- static method, avoiding the global variable altogether. Change-Id: I9f7560f1185bc4a3bc7b2b36e89280351998465e Reviewed-by: Christian Stenger --- .../autotest/boost/boosttestparser.cpp | 29 ++++----- .../autotest/catch/catchtestparser.cpp | 23 +++---- src/plugins/autotest/gtest/gtestparser.cpp | 27 +++----- src/plugins/autotest/itestparser.cpp | 9 +-- src/plugins/autotest/itestparser.h | 2 +- src/plugins/autotest/qtest/qttestparser.cpp | 64 ++++++++----------- src/plugins/autotest/qtest/qttestparser.h | 6 ++ .../autotest/quick/quicktestparser.cpp | 13 ++-- src/plugins/autotest/quick/quicktestparser.h | 1 + 9 files changed, 71 insertions(+), 103 deletions(-) diff --git a/src/plugins/autotest/boost/boosttestparser.cpp b/src/plugins/autotest/boost/boosttestparser.cpp index 1fafc3f250a..9d9476c5720 100644 --- a/src/plugins/autotest/boost/boosttestparser.cpp +++ b/src/plugins/autotest/boost/boosttestparser.cpp @@ -115,11 +115,13 @@ static BoostTestParseResult *createParseResult(const QString &name, const QStrin } -static bool handleBoostTest(QFutureInterface futureInterface, - const CPlusPlus::Document::Ptr &doc, - const CPlusPlus::Snapshot &snapshot, - ITestBase *base) +bool BoostTestParser::processDocument(QFutureInterface futureInterface, + const QString &fileName) { + CPlusPlus::Document::Ptr doc = document(fileName); + if (doc.isNull() || !includesBoostTest(doc, m_cppSnapshot) || !hasBoostTestMacros(doc)) + return false; + const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); const QString &filePath = doc->fileName(); @@ -128,9 +130,9 @@ static bool handleBoostTest(QFutureInterface futureInterface return false; const CppTools::ProjectPart::Ptr projectPart = projectParts.first(); const auto projectFile = projectPart->projectFile; - const QByteArray &fileContent = CppParser::getFileContent(filePath); + const QByteArray &fileContent = getFileContent(filePath); - BoostCodeParser codeParser(fileContent, projectPart->languageFeatures, doc, snapshot); + BoostCodeParser codeParser(fileContent, projectPart->languageFeatures, doc, m_cppSnapshot); const BoostTestCodeLocationList foundTests = codeParser.findTests(); if (foundTests.isEmpty()) return false; @@ -140,7 +142,7 @@ static bool handleBoostTest(QFutureInterface futureInterface BoostTestInfo firstSuite = suitesStates.first(); QStringList suites = firstSuite.fullName.split('/'); BoostTestParseResult *topLevelSuite = createParseResult(suites.first(), filePath, - projectFile, base, + projectFile, framework(), TestTreeItem::TestSuite, firstSuite); BoostTestParseResult *currentSuite = topLevelSuite; @@ -149,7 +151,7 @@ static bool handleBoostTest(QFutureInterface futureInterface firstSuite = suitesStates.first(); suites = firstSuite.fullName.split('/'); BoostTestParseResult *suiteResult = createParseResult(suites.last(), filePath, - projectFile, base, + projectFile, framework(), TestTreeItem::TestSuite, firstSuite); currentSuite->children.append(suiteResult); @@ -162,7 +164,7 @@ static bool handleBoostTest(QFutureInterface futureInterface locationAndType.m_suitesState.last().fullName + "::" + locationAndType.m_name, locationAndType.m_state, locationAndType.m_line}; BoostTestParseResult *funcResult = createParseResult(locationAndType.m_name, filePath, - projectFile, base, + projectFile, framework(), locationAndType.m_type, tmpInfo); currentSuite->children.append(funcResult); @@ -172,14 +174,5 @@ static bool handleBoostTest(QFutureInterface futureInterface return true; } -bool BoostTestParser::processDocument(QFutureInterface futureInterface, - const QString &fileName) -{ - CPlusPlus::Document::Ptr doc = document(fileName); - if (doc.isNull() || !includesBoostTest(doc, m_cppSnapshot) || !hasBoostTestMacros(doc)) - return false; - return handleBoostTest(futureInterface, doc, m_cppSnapshot, framework()); -} - } // namespace Internal } // namespace Autotest diff --git a/src/plugins/autotest/catch/catchtestparser.cpp b/src/plugins/autotest/catch/catchtestparser.cpp index d5816b1bf87..1ed01000111 100644 --- a/src/plugins/autotest/catch/catchtestparser.cpp +++ b/src/plugins/autotest/catch/catchtestparser.cpp @@ -96,13 +96,15 @@ static bool hasCatchNames(const CPlusPlus::Document::Ptr &document) return false; } -static bool handleCatchDocument(QFutureInterface futureInterface, - const CPlusPlus::Document::Ptr &doc, - ITestBase *base) +bool CatchTestParser::processDocument(QFutureInterface futureInterface, const QString &fileName) { + CPlusPlus::Document::Ptr doc = document(fileName); + if (doc.isNull() || !includesCatchHeader(doc, m_cppSnapshot) || !hasCatchNames(doc)) + return false; + const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); const QString &filePath = doc->fileName(); - const QByteArray &fileContent = CppParser::getFileContent(filePath); + const QByteArray &fileContent = getFileContent(filePath); const QList projectParts = modelManager->projectPart(filePath); if (projectParts.isEmpty()) // happens if shutting down while parsing @@ -114,7 +116,7 @@ static bool handleCatchDocument(QFutureInterface futureInter CatchCodeParser codeParser(fileContent, projectPart->languageFeatures); const CatchTestCodeLocationList foundTests = codeParser.findTests(); - CatchParseResult *parseResult = new CatchParseResult(base); + CatchParseResult *parseResult = new CatchParseResult(framework()); parseResult->itemType = TestTreeItem::TestSuite; parseResult->fileName = filePath; parseResult->name = filePath; @@ -122,7 +124,7 @@ static bool handleCatchDocument(QFutureInterface futureInter parseResult->proFile = projectParts.first()->projectFile; for (const CatchTestCodeLocationAndType & testLocation : foundTests) { - CatchParseResult *testCase = new CatchParseResult(base); + CatchParseResult *testCase = new CatchParseResult(framework()); testCase->fileName = filePath; testCase->name = testLocation.m_name; testCase->proFile = proFile; @@ -139,15 +141,6 @@ static bool handleCatchDocument(QFutureInterface futureInter return !foundTests.isEmpty(); } -bool CatchTestParser::processDocument(QFutureInterface futureInterface, const QString &fileName) -{ - CPlusPlus::Document::Ptr doc = document(fileName); - if (doc.isNull() || !includesCatchHeader(doc, m_cppSnapshot) || !hasCatchNames(doc)) - return false; - - return handleCatchDocument(futureInterface, doc, framework()); -} - TestTreeItem *CatchParseResult::createTestTreeItem() const { if (itemType == TestTreeItem::Root) diff --git a/src/plugins/autotest/gtest/gtestparser.cpp b/src/plugins/autotest/gtest/gtestparser.cpp index 2af311e89c1..d22842b0f1a 100644 --- a/src/plugins/autotest/gtest/gtestparser.cpp +++ b/src/plugins/autotest/gtest/gtestparser.cpp @@ -87,15 +87,17 @@ static bool hasGTestNames(const CPlusPlus::Document::Ptr &document) return false; } -static bool handleGTest(QFutureInterface futureInterface, - const CPlusPlus::Document::Ptr &doc, - const CPlusPlus::Snapshot &snapshot, - ITestBase *base) +bool GTestParser::processDocument(QFutureInterface futureInterface, + const QString &fileName) { + CPlusPlus::Document::Ptr doc = document(fileName); + if (doc.isNull() || !includesGTest(doc, m_cppSnapshot) || !hasGTestNames(doc)) + return false; + const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); const QString &filePath = doc->fileName(); - const QByteArray &fileContent = CppParser::getFileContent(filePath); - CPlusPlus::Document::Ptr document = snapshot.preprocessedDocument(fileContent, filePath); + const QByteArray &fileContent = getFileContent(filePath); + CPlusPlus::Document::Ptr document = m_cppSnapshot.preprocessedDocument(fileContent, filePath); document->check(); CPlusPlus::AST *ast = document->translationUnit()->ast(); GTestVisitor visitor(document); @@ -111,7 +113,7 @@ static bool handleGTest(QFutureInterface futureInterface, for (auto it = result.cbegin(); it != result.cend(); ++it) { const GTestCaseSpec &testSpec = it.key(); - GTestParseResult *parseResult = new GTestParseResult(base); + GTestParseResult *parseResult = new GTestParseResult(framework()); parseResult->itemType = TestTreeItem::TestSuite; parseResult->fileName = filePath; parseResult->name = testSpec.testCaseName; @@ -121,7 +123,7 @@ static bool handleGTest(QFutureInterface futureInterface, parseResult->proFile = proFile; for (const GTestCodeLocationAndType &location : it.value()) { - GTestParseResult *testSet = new GTestParseResult(base); + GTestParseResult *testSet = new GTestParseResult(framework()); testSet->name = location.m_name; testSet->fileName = filePath; testSet->line = location.m_line; @@ -138,14 +140,5 @@ static bool handleGTest(QFutureInterface futureInterface, return !result.isEmpty(); } -bool GTestParser::processDocument(QFutureInterface futureInterface, - const QString &fileName) -{ - CPlusPlus::Document::Ptr doc = document(fileName); - if (doc.isNull() || !includesGTest(doc, m_cppSnapshot) || !hasGTestNames(doc)) - return false; - return handleGTest(futureInterface, doc, m_cppSnapshot, framework()); -} - } // namespace Internal } // namespace Autotest diff --git a/src/plugins/autotest/itestparser.cpp b/src/plugins/autotest/itestparser.cpp index 335c56cbab6..51ab6f6b3b2 100644 --- a/src/plugins/autotest/itestparser.cpp +++ b/src/plugins/autotest/itestparser.cpp @@ -31,12 +31,9 @@ namespace Autotest { -static CppParser *s_parserInstance = nullptr; - CppParser::CppParser(ITestFramework *framework) : ITestParser(framework) { - s_parserInstance = this; } void CppParser::init(const QStringList &filesToParse, bool fullParse) @@ -55,11 +52,11 @@ bool CppParser::selectedForBuilding(const QString &fileName) return !projParts.isEmpty() && projParts.at(0)->selectedForBuilding; } -QByteArray CppParser::getFileContent(const QString &filePath) +QByteArray CppParser::getFileContent(const QString &filePath) const { QByteArray fileContent; - if (s_parserInstance->m_workingCopy.contains(filePath)) { - fileContent = s_parserInstance->m_workingCopy.source(filePath); + if (m_workingCopy.contains(filePath)) { + fileContent = m_workingCopy.source(filePath); } else { QString error; const QTextCodec *codec = Core::EditorManager::defaultTextCodec(); diff --git a/src/plugins/autotest/itestparser.h b/src/plugins/autotest/itestparser.h index d8a217bf5f6..02a60f45806 100644 --- a/src/plugins/autotest/itestparser.h +++ b/src/plugins/autotest/itestparser.h @@ -80,7 +80,7 @@ public: explicit CppParser(ITestFramework *framework); void init(const QStringList &filesToParse, bool fullParse) override; static bool selectedForBuilding(const QString &fileName); - static QByteArray getFileContent(const QString &filePath); + QByteArray getFileContent(const QString &filePath) const; void release() override; CPlusPlus::Document::Ptr document(const QString &fileName); diff --git a/src/plugins/autotest/qtest/qttestparser.cpp b/src/plugins/autotest/qtest/qttestparser.cpp index 71012c7deaa..259995ef7f0 100644 --- a/src/plugins/autotest/qtest/qttestparser.cpp +++ b/src/plugins/autotest/qtest/qttestparser.cpp @@ -25,7 +25,6 @@ #include "qttestparser.h" #include "qttestframework.h" -#include "qttesttreeitem.h" #include "qttestvisitors.h" #include "qttest_utils.h" @@ -94,10 +93,9 @@ static bool qtTestLibDefined(const QString &fileName) return false; } -static QString testClass(const CppTools::CppModelManager *modelManager, - const CPlusPlus::Snapshot &snapshot, const QString &fileName) +QString QtTestParser::testClass(const CppTools::CppModelManager *modelManager, const QString &fileName) const { - const QByteArray &fileContent = CppParser::getFileContent(fileName); + const QByteArray &fileContent = getFileContent(fileName); CPlusPlus::Document::Ptr document = modelManager->document(fileName); if (document.isNull()) return QString(); @@ -115,10 +113,10 @@ static QString testClass(const CppTools::CppModelManager *modelManager, } } // check if one has used a self-defined macro or QTest::qExec() directly - document = snapshot.preprocessedDocument(fileContent, fileName); + document = m_cppSnapshot.preprocessedDocument(fileContent, fileName); document->check(); CPlusPlus::AST *ast = document->translationUnit()->ast(); - TestAstVisitor astVisitor(document, snapshot); + TestAstVisitor astVisitor(document, m_cppSnapshot); astVisitor.accept(ast); return astVisitor.className(); } @@ -181,11 +179,10 @@ static QSet filesWithDataFunctionDefinitions( return result; } -static QHash checkForDataTags(const QString &fileName, - const CPlusPlus::Snapshot &snapshot) +QHash QtTestParser::checkForDataTags(const QString &fileName) const { - const QByteArray fileContent = CppParser::getFileContent(fileName); - CPlusPlus::Document::Ptr document = snapshot.preprocessedDocument(fileContent, fileName); + const QByteArray fileContent = getFileContent(fileName); + CPlusPlus::Document::Ptr document = m_cppSnapshot.preprocessedDocument(fileContent, fileName); document->check(); CPlusPlus::AST *ast = document->translationUnit()->ast(); TestDataFunctionVisitor visitor(document); @@ -280,28 +277,31 @@ static bool isQObject(const CPlusPlus::Document::Ptr &declaringDoc) || file.endsWith("QtCore/qobject.h") || file.endsWith("kernel/qobject.h"); } -static bool handleQtTest(QFutureInterface futureInterface, - CPlusPlus::Document::Ptr document, - const CPlusPlus::Snapshot &snapshot, - const QString &oldTestCaseName, - const QStringList &alternativeFiles, - ITestBase *base) +bool QtTestParser::processDocument(QFutureInterface futureInterface, + const QString &fileName) { + CPlusPlus::Document::Ptr doc = document(fileName); + if (doc.isNull()) + return false; + const QString &oldTestCaseName = m_testCaseNames.value(fileName); + if ((!includesQtTest(doc, m_cppSnapshot) || !qtTestLibDefined(fileName)) && oldTestCaseName.isEmpty()) + return false; + const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); - const QString &fileName = document->fileName(); - QString testCaseName(testClass(modelManager, snapshot, fileName)); + QString testCaseName(testClass(modelManager, fileName)); // we might be in a reparse without the original entry point with the QTest::qExec() if (testCaseName.isEmpty()) testCaseName = oldTestCaseName; if (!testCaseName.isEmpty()) { int line = 0; int column = 0; - CPlusPlus::Document::Ptr declaringDoc = declaringDocument(document, snapshot, testCaseName, + const QStringList &alternativeFiles = m_alternativeFiles.values(fileName); + CPlusPlus::Document::Ptr declaringDoc = declaringDocument(doc, m_cppSnapshot, testCaseName, alternativeFiles, &line, &column); if (declaringDoc.isNull()) return false; - TestVisitor visitor(testCaseName, snapshot); + TestVisitor visitor(testCaseName, m_cppSnapshot); visitor.accept(declaringDoc->globalNamespace()); if (!visitor.resultValid()) return false; @@ -310,7 +310,7 @@ static bool handleQtTest(QFutureInterface futureInterface, // 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); + visitor.baseClasses(), testFunctions, declaringDoc, m_cppSnapshot); // handle tests that are not runnable without more information (plugin unit test of QC) if (testFunctions.isEmpty() && testCaseName == "QObject" && isQObject(declaringDoc)) @@ -320,9 +320,9 @@ static bool handleQtTest(QFutureInterface futureInterface, QHash dataTags; for (const QString &file : files) - Utils::addToHash(&dataTags, checkForDataTags(file, snapshot)); + Utils::addToHash(&dataTags, checkForDataTags(file)); - QtTestParseResult *parseResult = new QtTestParseResult(base); + QtTestParseResult *parseResult = new QtTestParseResult(framework()); parseResult->itemType = TestTreeItem::TestCase; parseResult->fileName = declaringDoc->fileName(); parseResult->name = testCaseName; @@ -339,7 +339,7 @@ static bool handleQtTest(QFutureInterface futureInterface, const QtTestCodeLocationAndType &location = it.value(); QString functionName = it.key(); functionName = functionName.mid(functionName.lastIndexOf(':') + 1); - QtTestParseResult *func = new QtTestParseResult(base); + QtTestParseResult *func = new QtTestParseResult(framework()); func->itemType = location.m_type; func->name = testCaseName + "::" + functionName; func->displayName = functionName; @@ -350,7 +350,7 @@ static bool handleQtTest(QFutureInterface futureInterface, const QtTestCodeLocationList &tagLocations = tagLocationsFor(func, dataTags); for (const QtTestCodeLocationAndType &tag : tagLocations) { - QtTestParseResult *dataTag = new QtTestParseResult(base); + QtTestParseResult *dataTag = new QtTestParseResult(framework()); dataTag->itemType = tag.m_type; dataTag->name = tag.m_name; dataTag->displayName = tag.m_name; @@ -386,19 +386,5 @@ void QtTestParser::release() CppParser::release(); } -bool QtTestParser::processDocument(QFutureInterface futureInterface, - const QString &fileName) -{ - CPlusPlus::Document::Ptr doc = document(fileName); - if (doc.isNull()) - return false; - const QString &oldName = m_testCaseNames.value(fileName); - const QStringList &alternativeFiles = m_alternativeFiles.values(fileName); - if ((!includesQtTest(doc, m_cppSnapshot) || !qtTestLibDefined(fileName)) && oldName.isEmpty()) - return false; - - return handleQtTest(futureInterface, doc, m_cppSnapshot, oldName, alternativeFiles, framework()); -} - } // namespace Internal } // namespace Autotest diff --git a/src/plugins/autotest/qtest/qttestparser.h b/src/plugins/autotest/qtest/qttestparser.h index 435bd7fe5f9..6c9906c530a 100644 --- a/src/plugins/autotest/qtest/qttestparser.h +++ b/src/plugins/autotest/qtest/qttestparser.h @@ -27,6 +27,10 @@ #include "../itestparser.h" +#include "qttesttreeitem.h" + +namespace CppTools { class CppModelManager; } + namespace Autotest { namespace Internal { @@ -52,6 +56,8 @@ public: const QString &fileName) override; private: + QString testClass(const CppTools::CppModelManager *modelManager, const QString &fileName) const; + QHash checkForDataTags(const QString &fileName) const; QHash m_testCaseNames; QMultiHash m_alternativeFiles; }; diff --git a/src/plugins/autotest/quick/quicktestparser.cpp b/src/plugins/autotest/quick/quicktestparser.cpp index 151d2f35c85..828fa77ad62 100644 --- a/src/plugins/autotest/quick/quicktestparser.cpp +++ b/src/plugins/autotest/quick/quicktestparser.cpp @@ -112,8 +112,7 @@ static QString quickTestSrcDir(const CppTools::CppModelManager *cppMM, return QString(); } -static QString quickTestName(const CPlusPlus::Document::Ptr &doc, - const CPlusPlus::Snapshot &snapshot) +QString QuickTestParser::quickTestName(const CPlusPlus::Document::Ptr &doc) const { const QList macros = doc->macroUses(); @@ -123,20 +122,20 @@ static QString quickTestName(const CPlusPlus::Document::Ptr &doc, const QByteArray name = macro.macro().name(); if (QuickTestUtils::isQuickTestMacro(name)) { CPlusPlus::Document::Block arg = macro.arguments().at(0); - return QLatin1String(CppParser::getFileContent(doc->fileName()) + return QLatin1String(getFileContent(doc->fileName()) .mid(int(arg.bytesBegin()), int(arg.bytesEnd() - arg.bytesBegin()))); } } // check for using quick_test_main() directly const QString fileName = doc->fileName(); - const QByteArray &fileContent = CppParser::getFileContent(fileName); - CPlusPlus::Document::Ptr document = snapshot.preprocessedDocument(fileContent, fileName); + const QByteArray &fileContent = getFileContent(fileName); + CPlusPlus::Document::Ptr document = m_cppSnapshot.preprocessedDocument(fileContent, fileName); if (document.isNull()) return QString(); document->check(); CPlusPlus::AST *ast = document->translationUnit()->ast(); - QuickTestAstVisitor astVisitor(document, snapshot); + QuickTestAstVisitor astVisitor(document, m_cppSnapshot); astVisitor.accept(ast); return astVisitor.testBaseName(); } @@ -233,7 +232,7 @@ bool QuickTestParser::handleQtQuickTest(QFutureInterface fut ITestFramework *framework) { const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); - if (quickTestName(document, m_cppSnapshot).isEmpty()) + if (quickTestName(document).isEmpty()) return false; const QString cppFileName = document->fileName(); diff --git a/src/plugins/autotest/quick/quicktestparser.h b/src/plugins/autotest/quick/quicktestparser.h index f185a17acdf..0c4652d3d0c 100644 --- a/src/plugins/autotest/quick/quicktestparser.h +++ b/src/plugins/autotest/quick/quicktestparser.h @@ -56,6 +56,7 @@ private: CPlusPlus::Document::Ptr document, ITestFramework *framework); void handleDirectoryChanged(const QString &directory); void doUpdateWatchPaths(const QStringList &directories); + QString quickTestName(const CPlusPlus::Document::Ptr &doc) const; QList scanDirectoryForQuickTestQmlFiles(const QString &srcDir); QmlJS::Snapshot m_qmlSnapshot; QHash m_proFilesForQmlFiles;