Suppress loplugin:unnecessaryoverride...
...when a class derives from multiple (non-virtual) instances of one base class, and the override disambiguates which of those instances' member to call. That was the case with SwXTextDocument::queryAdapter (sw/source/uibase/uno/unotxdoc.cxx), where SwXTextDocument derives from cppu::OWeakObject through both SwXTextDocumentBaseClass and SfxBaseModel, but calling queryAdapter through a pointer to SwXTextDocumentBaseClass apparently needs to call OWeakObject::queryAdapter on the second, SfxBaseModel-inherited OWeakObject base instance, or else CppunitTest_sw_macros_test fails. Who knows what other instances of similar non-unnecessary overrides have been removed with the help of broken loplugin:unnecessaryoverride, for which there were no tests that started to fail... Turns out .clang-format lacked "ReflowComments: false" to not break the special "// expected-error {{...}}" etc. comments in compilerplugins/clang/test/. Also, use a better location to report loplugin:unnecessaryoverride, to keep clang-format and loplugin:unnecessaryoverride from fighting over how to split lines and where to put the comment in compilerplugins/clang/test/unnecessaryoverride.cxx. Change-Id: I3b24df24369db12f8ec1080d6c9f7b70ff561a16 Reviewed-on: https://gerrit.libreoffice.org/44418 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
This commit is contained in:
@@ -26,6 +26,7 @@ PenaltyBreakFirstLessLess: 120
|
|||||||
PenaltyExcessCharacter: 1000000
|
PenaltyExcessCharacter: 1000000
|
||||||
PenaltyReturnTypeOnItsOwnLine: 60
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
PointerBindsToType: true
|
PointerBindsToType: true
|
||||||
|
ReflowComments: false
|
||||||
SpacesBeforeTrailingComments: 1
|
SpacesBeforeTrailingComments: 1
|
||||||
Cpp11BracedListStyle: false
|
Cpp11BracedListStyle: false
|
||||||
Standard: Cpp11
|
Standard: Cpp11
|
||||||
|
48
compilerplugins/clang/test/unnecessaryoverride.cxx
Normal file
48
compilerplugins/clang/test/unnecessaryoverride.cxx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct Base
|
||||||
|
{
|
||||||
|
virtual ~Base();
|
||||||
|
virtual void f();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SimpleDerived : Base
|
||||||
|
{
|
||||||
|
void
|
||||||
|
f() override // expected-error {{public virtual function just calls public parent [loplugin:unnecessaryoverride]}}
|
||||||
|
{
|
||||||
|
Base::f();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Intermediate1 : Base
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MultiFunctionIntermediate2 : Base
|
||||||
|
{
|
||||||
|
void f() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MultiFunctionDerived : Intermediate1, MultiFunctionIntermediate2
|
||||||
|
{
|
||||||
|
void f() override { Intermediate1::f(); } // no warning
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MultiClassIntermediate2 : Base
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MultiClassDerived : Intermediate1, MultiClassIntermediate2
|
||||||
|
{
|
||||||
|
void f() override { Intermediate1::f(); } // no warning
|
||||||
|
};
|
||||||
|
|
||||||
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
@@ -23,6 +23,47 @@ look for methods where all they do is call their superclass method
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
bool hasMultipleBaseInstances_(
|
||||||
|
CXXRecordDecl const * derived, CXXRecordDecl const * canonicBase,
|
||||||
|
bool & hasAsNonVirtualBase, bool & hasAsVirtualBase)
|
||||||
|
{
|
||||||
|
for (auto i = derived->bases_begin(); i != derived->bases_end(); ++i) {
|
||||||
|
auto const cls = i->getType()->getAsCXXRecordDecl();
|
||||||
|
if (cls == nullptr) {
|
||||||
|
assert(i->getType()->isDependentType());
|
||||||
|
// Conservatively assume "yes" for dependent bases:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (cls->getCanonicalDecl() == canonicBase) {
|
||||||
|
if (i->isVirtual()) {
|
||||||
|
if (hasAsNonVirtualBase) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
hasAsVirtualBase = true;
|
||||||
|
} else {
|
||||||
|
if (hasAsNonVirtualBase || hasAsVirtualBase) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
hasAsNonVirtualBase = true;
|
||||||
|
}
|
||||||
|
} else if (hasMultipleBaseInstances_(
|
||||||
|
cls, canonicBase, hasAsNonVirtualBase, hasAsVirtualBase))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasMultipleBaseInstances(
|
||||||
|
CXXRecordDecl const * derived, CXXRecordDecl const * base)
|
||||||
|
{
|
||||||
|
bool nonVirt = false;
|
||||||
|
bool virt = false;
|
||||||
|
return hasMultipleBaseInstances_(
|
||||||
|
derived, base->getCanonicalDecl(), nonVirt, virt);
|
||||||
|
}
|
||||||
|
|
||||||
class UnnecessaryOverride:
|
class UnnecessaryOverride:
|
||||||
public RecursiveASTVisitor<UnnecessaryOverride>, public loplugin::Plugin
|
public RecursiveASTVisitor<UnnecessaryOverride>, public loplugin::Plugin
|
||||||
{
|
{
|
||||||
@@ -202,12 +243,20 @@ bool UnnecessaryOverride::VisitCXXMethodDecl(const CXXMethodDecl* methodDecl)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we are overriding more than one method, then this is a disambiguating override
|
// 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->isVirtual()) {
|
||||||
if (methodDecl->size_overridden_methods() != 1)
|
if (methodDecl->size_overridden_methods() != 1)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (hasMultipleBaseInstances(
|
||||||
|
methodDecl->getParent(),
|
||||||
|
(*methodDecl->begin_overridden_methods())->getParent()))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// sometimes the disambiguation happens in a base class
|
// sometimes the disambiguation happens in a base class
|
||||||
if (loplugin::isSamePathname(aFileName, SRCDIR "/comphelper/source/property/propertycontainer.cxx"))
|
if (loplugin::isSamePathname(aFileName, SRCDIR "/comphelper/source/property/propertycontainer.cxx"))
|
||||||
@@ -221,10 +270,6 @@ bool UnnecessaryOverride::VisitCXXMethodDecl(const CXXMethodDecl* methodDecl)
|
|||||||
// entertaining template magic
|
// entertaining template magic
|
||||||
if (loplugin::isSamePathname(aFileName, SRCDIR "/sc/source/ui/vba/vbaformatcondition.cxx"))
|
if (loplugin::isSamePathname(aFileName, SRCDIR "/sc/source/ui/vba/vbaformatcondition.cxx"))
|
||||||
return true;
|
return true;
|
||||||
// not sure what is going on here, but removing the override causes a crash
|
|
||||||
if (methodDecl->getQualifiedNameAsString() == "SwXTextDocument::queryAdapter")
|
|
||||||
return true;
|
|
||||||
|
|
||||||
|
|
||||||
const CXXMethodDecl* overriddenMethodDecl = findOverriddenOrSimilarMethodInSuperclasses(methodDecl);
|
const CXXMethodDecl* overriddenMethodDecl = findOverriddenOrSimilarMethodInSuperclasses(methodDecl);
|
||||||
if (!overriddenMethodDecl) {
|
if (!overriddenMethodDecl) {
|
||||||
@@ -317,7 +362,7 @@ bool UnnecessaryOverride::VisitCXXMethodDecl(const CXXMethodDecl* methodDecl)
|
|||||||
|
|
||||||
report(
|
report(
|
||||||
DiagnosticsEngine::Warning, "%0%1 function just calls %2 parent",
|
DiagnosticsEngine::Warning, "%0%1 function just calls %2 parent",
|
||||||
methodDecl->getSourceRange().getBegin())
|
methodDecl->getLocation())
|
||||||
<< methodDecl->getAccess()
|
<< methodDecl->getAccess()
|
||||||
<< (methodDecl->isVirtual() ? " virtual" : "")
|
<< (methodDecl->isVirtual() ? " virtual" : "")
|
||||||
<< overriddenMethodDecl->getAccess()
|
<< overriddenMethodDecl->getAccess()
|
||||||
@@ -327,7 +372,7 @@ bool UnnecessaryOverride::VisitCXXMethodDecl(const CXXMethodDecl* methodDecl)
|
|||||||
report(
|
report(
|
||||||
DiagnosticsEngine::Note,
|
DiagnosticsEngine::Note,
|
||||||
"method declaration here",
|
"method declaration here",
|
||||||
pOther->getLocStart())
|
pOther->getLocation())
|
||||||
<< pOther->getSourceRange();
|
<< pOther->getSourceRange();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@@ -41,6 +41,7 @@ $(eval $(call gb_CompilerTest_add_exception_objects,compilerplugins_clang, \
|
|||||||
compilerplugins/clang/test/salunicodeliteral \
|
compilerplugins/clang/test/salunicodeliteral \
|
||||||
compilerplugins/clang/test/stringconstant \
|
compilerplugins/clang/test/stringconstant \
|
||||||
compilerplugins/clang/test/unnecessarycatchthrow \
|
compilerplugins/clang/test/unnecessarycatchthrow \
|
||||||
|
compilerplugins/clang/test/unnecessaryoverride \
|
||||||
compilerplugins/clang/test/unnecessaryoverride-dtor \
|
compilerplugins/clang/test/unnecessaryoverride-dtor \
|
||||||
compilerplugins/clang/test/unnecessaryparen \
|
compilerplugins/clang/test/unnecessaryparen \
|
||||||
compilerplugins/clang/test/unoany \
|
compilerplugins/clang/test/unoany \
|
||||||
|
Reference in New Issue
Block a user