/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
if (isa<CXXDestructorDecl>(methodDecl)
&& !isInUnoIncludeFile(methodDecl))
{ // the code is this method is only __compiled__ if OSL_DEBUG_LEVEL > 1 if (loplugin::isSamePathname(aFileName, SRCDIR "/tools/source/stream/strmunx.cxx")) returntrue;
// Warn about unnecessarily user-declared destructors. // A destructor is deemed unnecessary if: // * it is public; // * its class is only defined in the .cxx file (i.e., the virtual // destructor is neither used to control the place of vtable // emission, nor is its definition depending on types that may still // be incomplete); // or // the destructor is inline, the class definition is complete, // and the class has no superclasses // * it either does not have an explicit exception specification, or has // a non-dependent explicit exception specification that is compatible // with a non-dependent exception specification the destructor would // have if it did not have an explicit one (TODO); // * it is either defined as defaulted or with an empty body. // Removing the user-declared destructor may cause the class to get an // implicitly declared move constructor and/or move assignment operator; // that is considered acceptable: If any subobject cannot be moved, the // implicitly declared function will be defined as deleted (which is in // practice not much different from not having it declared), and // otherwise offering movability is likely even an improvement over not // offering it due to a "pointless" user-declared destructor. // Similarly, removing the user-declared destructor may cause the // implicit definition of a copy constructor and/or copy assignment // operator to change from being an obsolete feature to being a standard // feature. That difference is not taken into account here. auto cls = methodDecl->getParent(); if (methodDecl->getAccess() != AS_public)
{ returntrue;
} if (!compiler.getSourceManager().isInMainFile(
methodDecl->getCanonicalDecl()->getLocation())
&& !( methodDecl->isInlined()))
{ returntrue;
} // if it's virtual, but it has a base-class with a non-virtual destructor if (methodDecl->isVirtual())
{ bool baseWithVirtualDtor = false; for (auto baseSpecifier = cls->bases_begin(); baseSpecifier != cls->bases_end(); ++baseSpecifier)
{ const RecordType* baseRecordType = baseSpecifier->getType()->getAs<RecordType>(); if (baseRecordType)
{ const CXXRecordDecl* baseRecordDecl = dyn_cast<CXXRecordDecl>(baseRecordType->getDecl()); if (baseRecordDecl && baseRecordDecl->getDestructor()
&& baseRecordDecl->getDestructor()->isVirtual())
{
baseWithVirtualDtor = true; break;
}
}
} if (!baseWithVirtualDtor)
{ returntrue;
}
} if (methodDecl->isExplicitlyDefaulted()) { if (methodDecl->getPreviousDecl() != nullptr) { returntrue;
}
} else { if (!methodDecl->doesThisDeclarationHaveABody()
|| methodDecl->isLateTemplateParsed())
{ returntrue;
} auto stmt = dyn_cast<CompoundStmt>(methodDecl->getBody()); if (stmt == nullptr || stmt->size() != 0) { returntrue;
}
} //TODO: exception specification if (!(cls->hasUserDeclaredCopyConstructor()
|| cls->hasUserDeclaredCopyAssignment()
|| cls->hasUserDeclaredMoveConstructor()
|| cls->hasUserDeclaredMoveAssignment()))
{
} if ((cls->needsImplicitMoveConstructor()
&& !(cls->hasUserDeclaredCopyConstructor()
|| cls->hasUserDeclaredCopyAssignment()
|| cls->hasUserDeclaredMoveAssignment()))
|| (cls->needsImplicitMoveAssignment()
&& !(cls->hasUserDeclaredCopyConstructor()
|| cls->hasUserDeclaredCopyAssignment()
|| cls->hasUserDeclaredMoveConstructor())))
{
report(DiagnosticsEngine::Fatal, "TODO", methodDecl->getLocation()); returntrue;
}
report(
DiagnosticsEngine::Warning, "unnecessary user-declared destructor",
methodDecl->getLocation())
<< methodDecl->getSourceRange(); auto cd = methodDecl->getCanonicalDecl(); if (cd->getLocation() != methodDecl->getLocation()) {
report(DiagnosticsEngine::Note, "declared here", cd->getLocation())
<< cd->getSourceRange();
} returntrue;
}
if (!methodDecl->doesThisDeclarationHaveABody()
|| methodDecl->isLateTemplateParsed())
{ returntrue;
}
// If overriding more than one base member function, or one base member // function that is available in multiple (non-virtual) base class // instances, then this is a disambiguating override: if (methodDecl->isVirtual()) { if (methodDecl->size_overridden_methods() != 1)
{ returntrue;
} if (hasMultipleBaseInstances(
methodDecl->getParent(),
(*methodDecl->begin_overridden_methods())->getParent()))
{ returntrue;
}
}
const CXXMethodDecl* overriddenMethodDecl = findOverriddenOrSimilarMethodInSuperclasses(methodDecl); if (!overriddenMethodDecl) { returntrue;
}
// Check for differences in default parameters: unsignedconst numParams = methodDecl->getNumParams();
assert(overriddenMethodDecl->getNumParams() == numParams); for (unsigned i = 0; i != numParams; ++i) { if (checkIdenticalDefaultArguments(
methodDecl->getParamDecl(i)->getDefaultArg(),
overriddenMethodDecl->getParamDecl(i)->getDefaultArg())
!= IdenticalDefaultArgumentsResult::Yes)
{ returntrue;
}
}
if (methodDecl->getReturnType().getCanonicalType()
!= overriddenMethodDecl->getReturnType().getCanonicalType())
{ returntrue;
}
//TODO: check for identical exception specifications
// In something like // // Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery( // const rtl::OUString& sql) // throw(SQLException, RuntimeException, std::exception) // { // return OCommonStatement::executeQuery( sql ); // } // // look down through all the // // ReturnStmt // `-ExprWithCleanups // `-CXXConstructExpr // `-MaterializeTemporaryExpr // `-ImplicitCastExpr // `-CXXBindTemporaryExpr // `-CXXMemberCallExpr // // where the fact that the overriding and overridden function have identical // return types makes us confident that all we need to check here is whether // there's an (arbitrary, one-argument) CXXConstructorExpr and // CXXBindTemporaryExpr in between: if (auto ctorExpr = dyn_cast<CXXConstructExpr>(returnExpr)) { if (ctorExpr->getNumArgs() == 1) { auto tempExpr1 = ctorExpr->getArg(0)->IgnoreImplicit(); if (auto tempExpr2 = dyn_cast<CXXBindTemporaryExpr>(tempExpr1))
{
returnExpr = tempExpr2->getSubExpr();
} elseif (auto tempExpr2 = dyn_cast<CXXMemberCallExpr>(tempExpr1))
{
returnExpr = tempExpr2;
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.