diff --git a/src/plugins/autotest/quick/quicktestparser.cpp b/src/plugins/autotest/quick/quicktestparser.cpp index 14e04c8a2fb..72592b32a0b 100644 --- a/src/plugins/autotest/quick/quicktestparser.cpp +++ b/src/plugins/autotest/quick/quicktestparser.cpp @@ -190,33 +190,33 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterface &testFunctions = qmlVisitor.testFunctions(); + const QVector &testCases = qmlVisitor.testCases(); - for (const QuickTestCaseSpec &it : testFunctions) { - const QString testCaseName = it.m_caseName; - const QString functionName = it.m_functionName; - const TestCodeLocationAndType &loc = it.m_functionLocationAndType; + for (const QuickTestCaseSpec &testCase : testCases) { + const QString testCaseName = testCase.m_caseName; QuickTestParseResult *parseResult = new QuickTestParseResult(id); parseResult->proFile = proFile; parseResult->itemType = TestTreeItem::TestCase; if (!testCaseName.isEmpty()) { - parseResult->fileName = it.m_name; + parseResult->fileName = testCase.m_locationAndType.m_name; parseResult->name = testCaseName; - parseResult->line = it.m_line; - parseResult->column = it.m_column; + parseResult->line = testCase.m_locationAndType.m_line; + parseResult->column = testCase.m_locationAndType.m_column; } - QuickTestParseResult *funcResult = new QuickTestParseResult(id); - funcResult->name = functionName; - funcResult->displayName = functionName; - funcResult->itemType = loc.m_type; - funcResult->fileName = loc.m_name; - funcResult->line = loc.m_line; - funcResult->column = loc.m_column; - funcResult->proFile = proFile; + for (auto function : testCase.m_functions) { + QuickTestParseResult *funcResult = new QuickTestParseResult(id); + funcResult->name = function.m_functionName; + funcResult->displayName = function.m_functionName; + funcResult->itemType = function.m_locationAndType.m_type; + funcResult->fileName = function.m_locationAndType.m_name; + funcResult->line = function.m_locationAndType.m_line; + funcResult->column = function.m_locationAndType.m_column; + funcResult->proFile = proFile; - parseResult->children.append(funcResult); + parseResult->children.append(funcResult); + } futureInterface.reportResult(TestParseResultPtr(parseResult)); } diff --git a/src/plugins/autotest/quick/quicktestvisitors.cpp b/src/plugins/autotest/quick/quicktestvisitors.cpp index 7243530700a..f60b59b3684 100644 --- a/src/plugins/autotest/quick/quicktestvisitors.cpp +++ b/src/plugins/autotest/quick/quicktestvisitors.cpp @@ -86,34 +86,29 @@ static bool isDerivedFromTestCase(QmlJS::AST::UiQualifiedId *id, const QmlJS::Do bool TestQmlVisitor::visit(QmlJS::AST::UiObjectDefinition *ast) { const QStringRef name = ast->qualifiedTypeNameId->name; - m_objectStack.push(name.toString()); + m_objectIsTestStack.push(false); if (name != "TestCase") { - m_insideTestCase = false; if (!isDerivedFromTestCase(ast->qualifiedTypeNameId, m_currentDoc, m_snapshot)) return true; } else if (!documentImportsQtTest(m_currentDoc.data())) { return true; // find nested TestCase items as well } - m_typeIsTestCase = true; - m_insideTestCase = true; + m_objectIsTestStack.top() = true; const auto sourceLocation = ast->firstSourceLocation(); QuickTestCaseSpec currentSpec; - currentSpec.m_name = m_currentDoc->fileName(); - currentSpec.m_line = sourceLocation.startLine; - currentSpec.m_column = sourceLocation.startColumn - 1; - currentSpec.m_type = TestTreeItem::TestCase; - m_testCases.push(currentSpec); + currentSpec.m_locationAndType.m_name = m_currentDoc->fileName(); + currentSpec.m_locationAndType.m_line = sourceLocation.startLine; + currentSpec.m_locationAndType.m_column = sourceLocation.startColumn - 1; + currentSpec.m_locationAndType.m_type = TestTreeItem::TestCase; + m_caseParseStack.push(currentSpec); return true; } void TestQmlVisitor::endVisit(QmlJS::AST::UiObjectDefinition *) { - if (!m_objectStack.isEmpty() && m_objectStack.pop() == "TestCase") { - if (!m_testCases.isEmpty()) - m_testCases.pop(); - m_insideTestCase = !m_objectStack.isEmpty() && m_objectStack.top() == "TestCase"; - } + if (!m_objectIsTestStack.isEmpty() && m_objectIsTestStack.pop() && !m_caseParseStack.isEmpty()) + m_testCases << m_caseParseStack.pop(); } bool TestQmlVisitor::visit(QmlJS::AST::ExpressionStatement *ast) @@ -124,7 +119,7 @@ bool TestQmlVisitor::visit(QmlJS::AST::ExpressionStatement *ast) bool TestQmlVisitor::visit(QmlJS::AST::UiScriptBinding *ast) { - if (m_insideTestCase) + if (m_objectIsTestStack.top()) m_expectTestCaseName = ast->qualifiedId->name == "name"; return m_expectTestCaseName; } @@ -137,6 +132,9 @@ void TestQmlVisitor::endVisit(QmlJS::AST::UiScriptBinding *) bool TestQmlVisitor::visit(QmlJS::AST::FunctionDeclaration *ast) { + if (m_caseParseStack.isEmpty()) + return false; + const QStringRef name = ast->name; if (name.startsWith("test_") || name.startsWith("benchmark_") @@ -154,13 +152,8 @@ bool TestQmlVisitor::visit(QmlJS::AST::FunctionDeclaration *ast) else locationAndType.m_type = TestTreeItem::TestFunction; - if (m_testCases.isEmpty()) // invalid qml code - return false; - - QuickTestCaseSpec testCaseWithFunc = m_testCases.top(); - testCaseWithFunc.m_functionName = name.toString(); - testCaseWithFunc.m_functionLocationAndType = locationAndType; - m_testFunctions.append(testCaseWithFunc); + m_caseParseStack.top().m_functions.append( + QuickTestFunctionSpec{name.toString(), locationAndType}); } return false; } @@ -168,8 +161,8 @@ bool TestQmlVisitor::visit(QmlJS::AST::FunctionDeclaration *ast) bool TestQmlVisitor::visit(QmlJS::AST::StringLiteral *ast) { if (m_expectTestCaseName) { - QTC_ASSERT(!m_testCases.isEmpty(), return false); - m_testCases.top().m_caseName = ast->value.toString(); + QTC_ASSERT(!m_caseParseStack.isEmpty(), return false); + m_caseParseStack.top().m_caseName = ast->value.toString(); m_expectTestCaseName = false; } return false; diff --git a/src/plugins/autotest/quick/quicktestvisitors.h b/src/plugins/autotest/quick/quicktestvisitors.h index b4245a5abc5..e4af8661c2f 100644 --- a/src/plugins/autotest/quick/quicktestvisitors.h +++ b/src/plugins/autotest/quick/quicktestvisitors.h @@ -37,12 +37,19 @@ namespace Autotest { namespace Internal { -class QuickTestCaseSpec : public TestCodeLocationAndType +class QuickTestFunctionSpec +{ +public: + QString m_functionName; + TestCodeLocationAndType m_locationAndType; +}; + +class QuickTestCaseSpec { public: QString m_caseName; - QString m_functionName; - TestCodeLocationAndType m_functionLocationAndType; + TestCodeLocationAndType m_locationAndType; + QVector m_functions; }; class TestQmlVisitor : public QmlJS::AST::Visitor @@ -58,17 +65,15 @@ public: bool visit(QmlJS::AST::FunctionDeclaration *ast) override; bool visit(QmlJS::AST::StringLiteral *ast) override; - QVector testFunctions() const { return m_testFunctions; } - bool isValid() const { return m_typeIsTestCase; } + QVector testCases() const { return m_testCases; } + bool isValid() const { return !m_testCases.isEmpty(); } private: QmlJS::Document::Ptr m_currentDoc; QmlJS::Snapshot m_snapshot; - QStack m_testCases; - QVector m_testFunctions; - QStack m_objectStack; - bool m_typeIsTestCase = false; - bool m_insideTestCase = false; + QStack m_caseParseStack; + QVector m_testCases; + QStack m_objectIsTestStack; bool m_expectTestCaseName = false; };