| 82 | } |
| 83 | |
| 84 | void CTestSuite::loadDeclarations(const IndexedString& document, const KDevelop::ReferencedTopDUContext& ref) |
| 85 | { |
| 86 | DUChainReadLocker locker(DUChain::lock()); |
| 87 | TopDUContext* topContext = DUChainUtils::contentContextFromProxyContext(ref.data()); |
| 88 | if (!topContext) { |
| 89 | qCDebug(CMAKE_TESTING) << "No top context in" << document.str(); |
| 90 | return; |
| 91 | } |
| 92 | |
| 93 | Declaration* testClass = nullptr; |
| 94 | const auto mainId = Identifier(QStringLiteral("main")); |
| 95 | const auto mainDeclarations = topContext->findLocalDeclarations(mainId); |
| 96 | DUContext* tmpInternalContext; |
| 97 | for (Declaration* declaration : mainDeclarations) { |
| 98 | if (!declaration->isDefinition() || !(tmpInternalContext = declaration->internalContext())) { |
| 99 | continue; |
| 100 | } |
| 101 | RangeInRevision contextRange = tmpInternalContext->range(); |
| 102 | qCDebug(CMAKE_TESTING) << "Found a definition for a function 'main()' at" << contextRange; |
| 103 | |
| 104 | /* |
| 105 | * This function tries to deduce the test class from the main function definition of |
| 106 | * the test source file. To do so, the cursor is set before the end of the internal |
| 107 | * context. Going backwards from there, the first variable declaration of a class |
| 108 | * type with private slots is assumed to be the test class. |
| 109 | * This method finds test classes passed to QTEST_MAIN or QTEST_GUILESS_MAIN, but |
| 110 | * also some classes which are used in manual implementations with a similar structure |
| 111 | * as in the Qt macros. |
| 112 | * If no such class is found, the main function definition is linked to the test suite |
| 113 | * and no test cases are added to the test suite. |
| 114 | */ |
| 115 | |
| 116 | --contextRange.end.column; // set cursor before the end of the definition |
| 117 | const auto innerContext = topContext->findContextAt(contextRange.end, true); |
| 118 | if (!innerContext) { |
| 119 | continue; |
| 120 | } |
| 121 | const auto mainDeclarations = innerContext->localDeclarations(topContext); |
| 122 | for (auto it = mainDeclarations.rbegin(); it != mainDeclarations.rend(); ++it) { |
| 123 | qCDebug(CMAKE_TESTING) << "Main declaration" << (*it)->toString(); |
| 124 | |
| 125 | auto type = (*it)->abstractType(); |
| 126 | // Strip pointer and reference types to finally get to the structure type of the test class |
| 127 | while (type && (type->whichType() == AbstractType::TypePointer || type->whichType() == AbstractType::TypeReference)) { |
| 128 | if (const auto ptype = type.dynamicCast<PointerType>()) { |
| 129 | type = ptype->baseType(); |
| 130 | } else if (const auto rtype = type.dynamicCast<ReferenceType>()) { |
| 131 | type = rtype->baseType(); |
| 132 | } else { |
| 133 | type = nullptr; |
| 134 | } |
| 135 | } |
| 136 | const auto structureType = type.dynamicCast<StructureType>(); |
| 137 | if (!structureType) { |
| 138 | continue; |
| 139 | } |
| 140 | |
| 141 | testClass = structureType->declaration(topContext); |
no test coverage detected