| 3419 | } |
| 3420 | |
| 3421 | void CheckClassImpl::checkUselessOverride() |
| 3422 | { |
| 3423 | if (!mSettings.severity.isEnabled(Severity::style) && !mSettings.isPremiumEnabled("uselessOverride")) |
| 3424 | return; |
| 3425 | |
| 3426 | logChecker("CheckClass::checkUselessOverride"); // style |
| 3427 | |
| 3428 | for (const Scope* classScope : mSymbolDatabase->classAndStructScopes) { |
| 3429 | if (!classScope->definedType || classScope->definedType->derivedFrom.size() != 1) |
| 3430 | continue; |
| 3431 | for (const Function& func : classScope->functionList) { |
| 3432 | if (!func.functionScope) |
| 3433 | continue; |
| 3434 | if (func.hasFinalSpecifier()) |
| 3435 | continue; |
| 3436 | const Function* baseFunc = func.getOverriddenFunction(); |
| 3437 | if (!baseFunc || baseFunc->isPure() || baseFunc->access != func.access) |
| 3438 | continue; |
| 3439 | if (std::any_of(classScope->functionList.begin(), classScope->functionList.end(), [&func](const Function& f) { // check for overloads |
| 3440 | if (&f == &func) |
| 3441 | return false; |
| 3442 | return f.name() == func.name(); |
| 3443 | })) |
| 3444 | continue; |
| 3445 | if (func.token->isExpandedMacro() || baseFunc->token->isExpandedMacro()) |
| 3446 | continue; |
| 3447 | if (baseFunc->functionScope) { |
| 3448 | bool isSameCode = compareTokenRanges(baseFunc->argDef, baseFunc->argDef->link(), func.argDef, func.argDef->link()); // function arguments |
| 3449 | if (isSameCode) { |
| 3450 | isSameCode = compareTokenRanges(baseFunc->functionScope->bodyStart, baseFunc->functionScope->bodyEnd, // function body |
| 3451 | func.functionScope->bodyStart, func.functionScope->bodyEnd); |
| 3452 | |
| 3453 | if (isSameCode) { |
| 3454 | // bailout for shadowed members |
| 3455 | if (!classScope->definedType || |
| 3456 | !getDuplInheritedMembersRecursive(classScope->definedType, classScope->definedType, /*skipPrivate*/ false).empty() || |
| 3457 | !getDuplInheritedMemberFunctionsRecursive(classScope->definedType, classScope->definedType, /*skipPrivate*/ false).empty()) |
| 3458 | continue; |
| 3459 | uselessOverrideError(baseFunc, &func, true); |
| 3460 | continue; |
| 3461 | } |
| 3462 | } |
| 3463 | } |
| 3464 | if (const Token* const call = getSingleFunctionCall(func.functionScope)) { |
| 3465 | if (call->function() != baseFunc) |
| 3466 | continue; |
| 3467 | if (Token::simpleMatch(call->astParent(), ".")) |
| 3468 | continue; |
| 3469 | std::vector<const Token*> callArgs = getArguments(call); |
| 3470 | if (func.argumentList.size() != callArgs.size() || |
| 3471 | !std::equal(func.argumentList.begin(), func.argumentList.end(), callArgs.begin(), [](const Variable& v, const Token* t) { |
| 3472 | return v.nameToken() && v.nameToken()->str() == t->str(); |
| 3473 | })) |
| 3474 | continue; |
| 3475 | uselessOverrideError(baseFunc, &func); |
| 3476 | } |
| 3477 | } |
| 3478 | } |
no test coverage detected