--------------------------------------------------------------------------- Check that all struct members are used ---------------------------------------------------------------------------
| 1518 | // Check that all struct members are used |
| 1519 | //--------------------------------------------------------------------------- |
| 1520 | void CheckUnusedVarImpl::checkStructMemberUsage() |
| 1521 | { |
| 1522 | if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("unusedStructMember") && !mSettings.isPremiumEnabled("unusedVariable")) |
| 1523 | return; |
| 1524 | |
| 1525 | logChecker("CheckUnusedVar::checkStructMemberUsage"); // style |
| 1526 | |
| 1527 | const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); |
| 1528 | |
| 1529 | for (const Scope &scope : symbolDatabase->scopeList) { |
| 1530 | if (scope.type != ScopeType::eStruct && scope.type != ScopeType::eClass && scope.type != ScopeType::eUnion) |
| 1531 | continue; |
| 1532 | |
| 1533 | if (scope.bodyStart->fileIndex() != 0 || scope.className.empty()) |
| 1534 | continue; |
| 1535 | |
| 1536 | if (scope.classDef->isExpandedMacro()) |
| 1537 | continue; |
| 1538 | |
| 1539 | // Packed struct => possibly used by lowlevel code. Struct members might be required by hardware. |
| 1540 | if (scope.bodyEnd->isAttributePacked()) |
| 1541 | continue; |
| 1542 | if (mTokenizer->isPacked(scope.bodyStart)) |
| 1543 | continue; |
| 1544 | |
| 1545 | // Bail out for template struct, members might be used in non-matching instantiations |
| 1546 | if (scope.className.find('<') != std::string::npos) |
| 1547 | continue; |
| 1548 | |
| 1549 | // bail out if struct is inherited |
| 1550 | const bool isInherited = std::any_of(symbolDatabase->scopeList.cbegin(), symbolDatabase->scopeList.cend(), [&](const Scope& derivedScope) { |
| 1551 | const Type* dType = derivedScope.definedType; |
| 1552 | return dType && std::any_of(dType->derivedFrom.cbegin(), dType->derivedFrom.cend(), [&](const Type::BaseInfo& derivedFrom) { |
| 1553 | return derivedFrom.type == scope.definedType && derivedFrom.access != AccessControl::Private; |
| 1554 | }); |
| 1555 | }); |
| 1556 | |
| 1557 | // bail out for extern/global struct |
| 1558 | bool bailout = false; |
| 1559 | for (const Variable* var : symbolDatabase->variableList()) { |
| 1560 | if (var && (var->isExtern() || (var->isGlobal() && !var->isStatic())) && var->typeEndToken()->str() == scope.className) { |
| 1561 | bailout = true; |
| 1562 | break; |
| 1563 | } |
| 1564 | if (bailout) |
| 1565 | break; |
| 1566 | } |
| 1567 | if (bailout) |
| 1568 | continue; |
| 1569 | |
| 1570 | // Bail out if some data is casted to struct.. |
| 1571 | const std::string castPattern("( struct| " + scope.className + " * ) &| %name%"); |
| 1572 | if (Token::findmatch(scope.bodyEnd, castPattern.c_str())) |
| 1573 | continue; |
| 1574 | |
| 1575 | // (struct S){..} |
| 1576 | const std::string initPattern("( struct| " + scope.className + " ) {"); |
| 1577 | if (Token::findmatch(scope.bodyEnd, initPattern.c_str())) |
no test coverage detected