1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 // Find classes that derive from css::uno::XAggregation, but which implement queryInterface in
11 // violation of the protocol laid out in the documentation at
12 // udkapi/com/sun/star/uno/XAggregation.idl (which implies that such a class either doesn't actually
13 // make use of the deprecated XAggregation mechanism, which should thus be removed from that class
14 // hierarchy, or that its implementation of queryInterface needs to be fixed).
16 #ifndef LO_CLANG_SHARED_PLUGINS
25 bool isQueryInterface(CXXMethodDecl
const* decl
)
27 auto const id
= decl
->getIdentifier();
28 if (id
== nullptr || id
->getName() != "queryInterface")
32 if (decl
->getNumParams() != 1)
36 if (!loplugin::TypeCheck(decl
->getParamDecl(0)->getType())
51 bool derivesFromXAggregation(CXXRecordDecl
const* decl
, bool checkSelf
)
53 return loplugin::isDerivedFrom(decl
,
54 [](Decl
const* decl
) -> bool {
55 return bool(loplugin::DeclCheck(decl
)
56 .Class("XAggregation")
66 // Return true if decl is an implementation of css::uno::XInterface::queryInterface in a class
67 // derived from css::uno::XAggregation:
68 bool isXAggregationQueryInterface(CXXMethodDecl
const* decl
)
70 return isQueryInterface(decl
) && derivesFromXAggregation(decl
->getParent(), false);
73 bool basesHaveOnlyPureQueryInterface(CXXRecordDecl
const* decl
)
75 for (auto const& b
: decl
->bases())
77 auto const d1
= b
.getType()->getAsCXXRecordDecl();
78 if (!derivesFromXAggregation(d1
, true))
82 for (auto const d2
: d1
->methods())
84 if (!isQueryInterface(d2
))
93 if (!basesHaveOnlyPureQueryInterface(d1
))
101 class UnoAggregation final
: public loplugin::FilteringPlugin
<UnoAggregation
>
104 explicit UnoAggregation(loplugin::InstantiationData
const& data
)
105 : FilteringPlugin(data
)
109 bool shouldVisitTemplateInstantiations() const { return true; }
111 bool preRun() override
{ return compiler
.getLangOpts().CPlusPlus
; }
117 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
121 bool VisitCXXMethodDecl(CXXMethodDecl
const* decl
)
123 if (ignoreLocation(decl
))
127 if (!decl
->isThisDeclarationADefinition())
131 auto const parent
= decl
->getParent();
132 if (parent
->getDescribedClassTemplate() != nullptr)
134 // For class templates with dependent base classes, loplugin::isDerivedFrom as used in
135 // isXAggregationQueryInterface would always return true; work around that by not
136 // looking at any templates at all, which is OK due to
137 // shouldVisitTemplateInstantiations:
140 if (!isXAggregationQueryInterface(decl
))
144 if (decl
->isDeleted())
146 // Whether or not a deleted queryInterface makes sense, just leave those alone:
149 auto const body
= decl
->getBody();
150 assert(body
!= nullptr);
151 // Check whether the implementation forwards to one of the base classes that derive from
153 if (auto const s1
= dyn_cast
<CompoundStmt
>(body
))
157 if (auto const s2
= dyn_cast
<ReturnStmt
>(s1
->body_front()))
159 if (auto const e1
= s2
->getRetValue())
162 = dyn_cast
<CXXMemberCallExpr
>(e1
->IgnoreImplicit()->IgnoreParens()))
165 if (e2
->getImplicitObjectArgument() == nullptr)
167 if (isXAggregationQueryInterface(e2
->getMethodDecl()))
169 // e2 will thus necessarily be a call of a base class's
170 // queryInterface (or a recursive call of the given decl itself,
171 // but which would cause the code to have undefined behavior
172 // anyway, so don't bother to rule that out):
178 else if (isDebugMode())
180 report(DiagnosticsEngine::Warning
,
181 "suspicious implementation of queryInterface containing a return "
182 "statement with no operand",
184 << decl
->getSourceRange();
189 // As a crude approximation (but which appears to work OK), if all of the base classes that
190 // derive from XAggregation only ever declare queryInterface as pure, assume that this is
191 // the base implementation of queryInterface (which will necessarily not match the above
192 // check for a forwarding implementation):
193 if (basesHaveOnlyPureQueryInterface(parent
))
197 if (suppressWarningAt(decl
->getBeginLoc()))
201 report(DiagnosticsEngine::Warning
,
202 "%0 derives from XAggregation, but its implementation of queryInterface does not "
203 "delegate to an appropriate base class queryInterface",
205 << parent
<< decl
->getSourceRange();
210 loplugin::Plugin::Registration
<UnoAggregation
> unoaggregation("unoaggregation");
215 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */