diff options
author | Christian Stenger <christian.stenger@qt.io> | 2021-06-04 14:28:03 +0200 |
---|---|---|
committer | Christian Stenger <christian.stenger@qt.io> | 2021-06-07 12:05:37 +0000 |
commit | 9db6569c43bd2acfb453b5e67f13d7f0ee4448a6 (patch) | |
tree | 941c842f26d35875a1115529c1cdfe58405087c4 /src | |
parent | 684c5f75293634bac7a315ca62bf917e93af28f9 (diff) | |
download | qt-creator-9db6569c43bd2acfb453b5e67f13d7f0ee4448a6.tar.gz |
AutoTest: Take precompiled headers into account
Test frameworks might be added to the precompiled
headers. This in turn would make some pre-checks
whether a file has to be processed or not fail.
Fixes: QTCREATORBUG-25821
Change-Id: Iff69c1a83889cb6f79a3e3f9b2e59c5383989ccd
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: David Schulz <david.schulz@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/autotest/boost/boosttestparser.cpp | 4 | ||||
-rw-r--r-- | src/plugins/autotest/catch/catchtestparser.cpp | 19 | ||||
-rw-r--r-- | src/plugins/autotest/gtest/gtestparser.cpp | 19 | ||||
-rw-r--r-- | src/plugins/autotest/itestparser.cpp | 37 | ||||
-rw-r--r-- | src/plugins/autotest/itestparser.h | 10 | ||||
-rw-r--r-- | src/plugins/autotest/qtest/qttestparser.cpp | 24 | ||||
-rw-r--r-- | src/plugins/autotest/quick/quicktestparser.cpp | 42 |
7 files changed, 143 insertions, 12 deletions
diff --git a/src/plugins/autotest/boost/boosttestparser.cpp b/src/plugins/autotest/boost/boosttestparser.cpp index 53a1443430..c285d49b39 100644 --- a/src/plugins/autotest/boost/boosttestparser.cpp +++ b/src/plugins/autotest/boost/boosttestparser.cpp @@ -84,7 +84,9 @@ static bool includesBoostTest(const CPlusPlus::Document::Ptr &doc, return true; } - return false; + return CppParser::precompiledHeaderContains(snapshot, + Utils::FilePath::fromString(doc->fileName()), + boostTestHpp); } static bool hasBoostTestMacros(const CPlusPlus::Document::Ptr &doc) diff --git a/src/plugins/autotest/catch/catchtestparser.cpp b/src/plugins/autotest/catch/catchtestparser.cpp index a95e1f2905..933fda35fd 100644 --- a/src/plugins/autotest/catch/catchtestparser.cpp +++ b/src/plugins/autotest/catch/catchtestparser.cpp @@ -86,6 +86,12 @@ static bool includesCatchHeader(const CPlusPlus::Document::Ptr &doc, } } + for (const QString &catchHeader : catchHeaders) { + if (CppParser::precompiledHeaderContains(snapshot, + Utils::FilePath::fromString(doc->fileName()), + catchHeader)) + return true; + } return false; } @@ -109,13 +115,24 @@ bool CatchTestParser::processDocument(QFutureInterface<TestParseResultPtr> futur const Utils::FilePath &fileName) { CPlusPlus::Document::Ptr doc = document(fileName); - if (doc.isNull() || !includesCatchHeader(doc, m_cppSnapshot) || !hasCatchNames(doc)) + if (doc.isNull() || !includesCatchHeader(doc, m_cppSnapshot)) return false; const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); const QString &filePath = doc->fileName(); const QByteArray &fileContent = getFileContent(fileName); + if (!hasCatchNames(doc)) { + const QRegularExpression regex("\\b(SCENARIO|(TEMPLATE_(PRODUCT_)?)?TEST_CASE(_METHOD)?|" + "TEMPLATE_TEST_CASE(_METHOD)?_SIG|" + "TEMPLATE_PRODUCT_TEST_CASE(_METHOD)?_SIG|" + "TEMPLATE_LIST_TEST_CASE_METHOD|METHOD_AS_TEST_CASE|" + "REGISTER_TEST_CASE)"); + if (!regex.match(QString::fromUtf8(fileContent)).hasMatch()) + return false; + } + + const QList<CppTools::ProjectPart::Ptr> projectParts = modelManager->projectPart(fileName); if (projectParts.isEmpty()) // happens if shutting down while parsing return false; diff --git a/src/plugins/autotest/gtest/gtestparser.cpp b/src/plugins/autotest/gtest/gtestparser.cpp index 4975bc66da..35f00e2c94 100644 --- a/src/plugins/autotest/gtest/gtestparser.cpp +++ b/src/plugins/autotest/gtest/gtestparser.cpp @@ -32,6 +32,9 @@ #include <cpptools/cppmodelmanager.h> #include <cpptools/projectpart.h> +#include <QRegularExpression> +#include <QRegularExpressionMatch> + namespace Autotest { namespace Internal { @@ -69,7 +72,9 @@ static bool includesGTest(const CPlusPlus::Document::Ptr &doc, return true; } - return false; + return CppParser::precompiledHeaderContains(snapshot, + Utils::FilePath::fromString(doc->fileName()), + gtestH); } static bool hasGTestNames(const CPlusPlus::Document::Ptr &document) @@ -91,12 +96,18 @@ bool GTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInt const Utils::FilePath &fileName) { CPlusPlus::Document::Ptr doc = document(fileName); - if (doc.isNull() || !includesGTest(doc, m_cppSnapshot) || !hasGTestNames(doc)) + if (doc.isNull() || !includesGTest(doc, m_cppSnapshot)) return false; - const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); - const QString &filePath = doc->fileName(); const QByteArray &fileContent = getFileContent(fileName); + if (!hasGTestNames(doc)) { + const QRegularExpression regex("\\b(TEST(_[FP])?|TYPED_TEST(_P)?|(GTEST_TEST))"); + if (!regex.match(QString::fromUtf8(fileContent)).hasMatch()) + return false; + } + + const QString &filePath = doc->fileName(); + const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); CPlusPlus::Document::Ptr document = m_cppSnapshot.preprocessedDocument(fileContent, fileName); document->check(); CPlusPlus::AST *ast = document->translationUnit()->ast(); diff --git a/src/plugins/autotest/itestparser.cpp b/src/plugins/autotest/itestparser.cpp index 740f029e4c..cd0f2591dd 100644 --- a/src/plugins/autotest/itestparser.cpp +++ b/src/plugins/autotest/itestparser.cpp @@ -28,6 +28,10 @@ #include <coreplugin/editormanager/editormanager.h> #include <cpptools/cppmodelmanager.h> #include <utils/textfileformat.h> +#include <utils/algorithm.h> + +#include <QRegularExpression> +#include <QRegularExpressionMatch> namespace Autotest { @@ -69,6 +73,39 @@ QByteArray CppParser::getFileContent(const Utils::FilePath &filePath) const return fileContent; } +bool precompiledHeaderContains(const CPlusPlus::Snapshot &snapshot, + const Utils::FilePath &filePath, + const std::function<bool(const QString &)> &checker) +{ + const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); + const QList<CppTools::ProjectPart::Ptr> projectParts = modelManager->projectPart(filePath); + if (projectParts.isEmpty()) + return false; + const QStringList precompiledHeaders = projectParts.first()->precompiledHeaders; + auto headerContains = [&](const QString &header){ + return Utils::anyOf(snapshot.allIncludesForDocument(header), checker); + }; + return Utils::anyOf(precompiledHeaders, headerContains); +} + +bool CppParser::precompiledHeaderContains(const CPlusPlus::Snapshot &snapshot, + const Utils::FilePath &filePath, + const QString &headerFilePath) +{ + return Autotest::precompiledHeaderContains(snapshot, filePath, [&](const QString &include) { + return include.endsWith(headerFilePath); + }); +} + +bool CppParser::precompiledHeaderContains(const CPlusPlus::Snapshot &snapshot, + const Utils::FilePath &filePath, + const QRegularExpression &headerFileRegex) +{ + return Autotest::precompiledHeaderContains(snapshot, filePath, [&](const QString &include) { + return headerFileRegex.match(include).hasMatch(); + }); +} + void CppParser::release() { m_cppSnapshot = CPlusPlus::Snapshot(); diff --git a/src/plugins/autotest/itestparser.h b/src/plugins/autotest/itestparser.h index e089c030d4..a3cb0cb8b4 100644 --- a/src/plugins/autotest/itestparser.h +++ b/src/plugins/autotest/itestparser.h @@ -33,6 +33,10 @@ #include <QFutureInterface> +QT_BEGIN_NAMESPACE +class QRegularExpression; +QT_END_NAMESPACE + namespace Autotest { class ITestFramework; @@ -85,6 +89,12 @@ public: CPlusPlus::Document::Ptr document(const Utils::FilePath &fileName); + static bool precompiledHeaderContains(const CPlusPlus::Snapshot &snapshot, + const Utils::FilePath &filePath, + const QString &headerFilePath); + static bool precompiledHeaderContains(const CPlusPlus::Snapshot &snapshot, + const Utils::FilePath &filePath, + const QRegularExpression &headerFileRegex); protected: CPlusPlus::Snapshot m_cppSnapshot; CppTools::WorkingCopy m_workingCopy; diff --git a/src/plugins/autotest/qtest/qttestparser.cpp b/src/plugins/autotest/qtest/qttestparser.cpp index 387b6e0879..a42d341eff 100644 --- a/src/plugins/autotest/qtest/qttestparser.cpp +++ b/src/plugins/autotest/qtest/qttestparser.cpp @@ -32,6 +32,8 @@ #include <cplusplus/TypeOfExpression.h> #include <utils/algorithm.h> +#include <QRegularExpressionMatchIterator> + namespace Autotest { namespace Internal { @@ -78,6 +80,14 @@ static bool includesQtTest(const CPlusPlus::Document::Ptr &doc, const CPlusPlus: return true; } } + + for (const QString &prefix : expectedHeaderPrefixes) { + if (CppParser::precompiledHeaderContains(snapshot, + Utils::FilePath::fromString(doc->fileName()), + QString("%1/qtest.h").arg(prefix))) { + return true; + } + } return false; } @@ -120,7 +130,19 @@ TestCases QtTestParser::testCases(const CppTools::CppModelManager *modelManager, CPlusPlus::AST *ast = document->translationUnit()->ast(); TestAstVisitor astVisitor(document, m_cppSnapshot); astVisitor.accept(ast); - return astVisitor.testCases(); + if (!astVisitor.testCases().isEmpty()) + return astVisitor.testCases(); + + // check pch usage - might give false positives, but we can't do better without cost + TestCases result; + const QRegularExpression regex("\\bQTEST_(APPLESS_|GUILESS_)?MAIN" + "\\s*\\(\\s*([[:alnum:]]+)\\s*\\)"); + QRegularExpressionMatchIterator it = regex.globalMatch(QString::fromUtf8(fileContent)); + while (it.hasNext()) { + const QRegularExpressionMatch match = it.next(); + result.append({match.captured(2), false}); + } + return result; } static CPlusPlus::Document::Ptr declaringDocument(CPlusPlus::Document::Ptr doc, diff --git a/src/plugins/autotest/quick/quicktestparser.cpp b/src/plugins/autotest/quick/quicktestparser.cpp index fdd045bb31..598f8a2e79 100644 --- a/src/plugins/autotest/quick/quicktestparser.cpp +++ b/src/plugins/autotest/quick/quicktestparser.cpp @@ -87,6 +87,14 @@ static bool includesQtQuickTest(const CPlusPlus::Document::Ptr &doc, return true; } } + + for (const QString &prefix : expectedHeaderPrefixes) { + if (CppParser::precompiledHeaderContains(snapshot, + Utils::FilePath::fromString(doc->fileName()), + QString("%1/quicktest.h").arg(prefix))) { + return true; + } + } return false; } @@ -115,6 +123,7 @@ static QString quickTestSrcDir(const CppTools::CppModelManager *cppMM, QString QuickTestParser::quickTestName(const CPlusPlus::Document::Ptr &doc) const { const QList<CPlusPlus::Document::MacroUse> macros = doc->macroUses(); + const Utils::FilePath filePath = Utils::FilePath::fromString(doc->fileName()); for (const CPlusPlus::Document::MacroUse ¯o : macros) { if (!macro.isFunctionLike()) @@ -122,22 +131,45 @@ QString QuickTestParser::quickTestName(const CPlusPlus::Document::Ptr &doc) cons const QByteArray name = macro.macro().name(); if (QuickTestUtils::isQuickTestMacro(name)) { CPlusPlus::Document::Block arg = macro.arguments().at(0); - return QLatin1String(getFileContent(Utils::FilePath::fromString(doc->fileName())) + return QLatin1String(getFileContent(filePath) .mid(int(arg.bytesBegin()), int(arg.bytesEnd() - arg.bytesBegin()))); } } + + const QByteArray &fileContent = getFileContent(filePath); // check for using quick_test_main() directly - const QString fileName = doc->fileName(); - const QByteArray &fileContent = getFileContent(Utils::FilePath::fromString(fileName)); - CPlusPlus::Document::Ptr document = m_cppSnapshot.preprocessedDocument(fileContent, fileName); + CPlusPlus::Document::Ptr document = m_cppSnapshot.preprocessedDocument(fileContent, filePath); if (document.isNull()) return QString(); document->check(); CPlusPlus::AST *ast = document->translationUnit()->ast(); QuickTestAstVisitor astVisitor(document, m_cppSnapshot); astVisitor.accept(ast); - return astVisitor.testBaseName(); + if (!astVisitor.testBaseName().isEmpty()) + return astVisitor.testBaseName(); + + // check for precompiled headers + static QStringList expectedHeaderPrefixes + = Utils::HostOsInfo::isMacHost() + ? QStringList({"QtQuickTest.framework/Headers", "QtQuickTest"}) + : QStringList({"QtQuickTest"}); + bool pchIncludes = false; + for (const QString &prefix : expectedHeaderPrefixes) { + if (CppParser::precompiledHeaderContains(m_cppSnapshot, filePath, + QString("%1/quicktest.h").arg(prefix))) { + pchIncludes = true; + break; + } + } + + if (pchIncludes) { + const QRegularExpression regex("\\bQUICK_TEST_(MAIN|OPENGL_MAIN|MAIN_WITH_SETUP)"); + const QRegularExpressionMatch match = regex.match(QString::fromUtf8(fileContent)); + if (match.hasMatch()) + return match.captured(); // we do not care for the name, just return something non-empty + } + return {}; } QList<Document::Ptr> QuickTestParser::scanDirectoryForQuickTestQmlFiles(const QString &srcDir) |