| 1999 | //--------------------------------------------------------------------------- |
| 2000 | |
| 2001 | void CheckClassImpl::virtualDestructor() |
| 2002 | { |
| 2003 | // This error should only be given if: |
| 2004 | // * base class doesn't have virtual destructor |
| 2005 | // * derived class has non-empty destructor (only c++03, in c++11 it's UB see paragraph 3 in [expr.delete]) |
| 2006 | // * base class is deleted |
| 2007 | // unless inconclusive in which case: |
| 2008 | // * A class with any virtual functions should have a destructor that is either public and virtual or protected |
| 2009 | const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); |
| 2010 | |
| 2011 | std::list<const Function *> inconclusiveErrors; |
| 2012 | |
| 2013 | logChecker("CheckClass::virtualDestructor"); |
| 2014 | |
| 2015 | for (const Scope * scope : mSymbolDatabase->classAndStructScopes) { |
| 2016 | |
| 2017 | // Skip base classes (unless inconclusive) |
| 2018 | if (scope->definedType->derivedFrom.empty()) { |
| 2019 | if (printInconclusive) { |
| 2020 | const Function *destructor = scope->getDestructor(); |
| 2021 | if (destructor && !destructor->hasVirtualSpecifier() && destructor->access == AccessControl::Public) { |
| 2022 | if (std::any_of(scope->functionList.cbegin(), scope->functionList.cend(), [](const Function& func) { |
| 2023 | return func.hasVirtualSpecifier(); |
| 2024 | })) |
| 2025 | inconclusiveErrors.push_back(destructor); |
| 2026 | } |
| 2027 | } |
| 2028 | continue; |
| 2029 | } |
| 2030 | |
| 2031 | // Check if destructor is empty and non-empty .. |
| 2032 | if (mSettings.standards.cpp <= Standards::CPP03) { |
| 2033 | // Find the destructor |
| 2034 | const Function *destructor = scope->getDestructor(); |
| 2035 | |
| 2036 | // Check for destructor with implementation |
| 2037 | if (!destructor || !destructor->hasBody()) |
| 2038 | continue; |
| 2039 | |
| 2040 | // Empty destructor |
| 2041 | if (destructor->token->linkAt(3) == destructor->token->tokAt(4)) |
| 2042 | continue; |
| 2043 | } |
| 2044 | |
| 2045 | const Token *derived = scope->classDef; |
| 2046 | const Token *derivedClass = derived->next(); |
| 2047 | |
| 2048 | // Iterate through each base class... |
| 2049 | for (const Type::BaseInfo & j : scope->definedType->derivedFrom) { |
| 2050 | // Check if base class is public and exists in database |
| 2051 | if (j.access != AccessControl::Private && j.type) { |
| 2052 | const Type *derivedFrom = j.type; |
| 2053 | const Scope *derivedFromScope = derivedFrom->classScope; |
| 2054 | if (!derivedFromScope) |
| 2055 | continue; |
| 2056 | |
| 2057 | // Check for this pattern: |
| 2058 | // 1. Base class pointer is given the address of derived class instance |