1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
12 #include <unordered_set>
13 #include <unordered_map>
16 #include "config_clang.h"
21 #include "functionaddress.hxx"
23 #if CLANG_VERSION >= 110000
24 #include "clang/AST/ParentMapContext.h"
28 Find methods that can be declared const.
30 This analysis attempts to implement "logical const" as opposed to "technical const", which means
31 we ignore always-const nature of std::unique_ptr::operator->
33 This is not a sophisticated analysis. It deliberately skips all of the hard cases for now.
34 It is an exercise in getting the most benefit for the least effort.
40 public loplugin::FunctionAddress
<loplugin::FilteringPlugin
<ConstMethod
>>
43 explicit ConstMethod(loplugin::InstantiationData
const & data
): FunctionAddress(data
) {}
45 virtual void run() override
{
46 std::string
fn(handler
.getMainFileName());
47 loplugin::normalizeDotDotInFilePath(fn
);
48 // things I'm not sure about
49 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/svl/unx/source/svdde/ddedummy.cxx")
50 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/svl/source/numbers/zformat.cxx")
51 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/svl/source/numbers/zforscan.cxx")
52 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/svl/source/numbers/zforlist.cxx")
53 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/source/gdi/impgraph.cxx")
54 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/source/image/ImplImage.cxx")
55 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/source/filter/wmf/wmfwr.cxx")
56 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/unx/generic/app/i18n_im.cxx")
57 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/unx/generic/app/randrwrapper.cxx")
58 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/unx/gtk3/gtkinst.cxx")
59 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/unx/gtk3/gtkframe.cxx")
60 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/skia/gdiimpl.cxx")
61 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/qt5/")
62 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/package/source/xstor/owriteablestream.cxx")
63 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/package/source/zippackage/ZipPackage.cxx")
64 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/toolkit/")
65 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/canvas/")
66 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/accessibility/")
67 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/framework/")
68 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/basic/")
69 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/sfx2/")
70 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/xmloff/")
71 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/connectivity/")
72 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/editeng/")
73 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/scripting/")
74 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/ucb/")
75 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/svx/")
76 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/basctl/")
77 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/chart2/")
81 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
83 for (const CXXMethodDecl
*pMethodDecl
: interestingMethodSet
) {
84 if (methodCannotBeConstSet
.find(pMethodDecl
) != methodCannotBeConstSet
.end())
86 auto canonicalDecl
= pMethodDecl
->getCanonicalDecl();
87 if (getFunctionsWithAddressTaken().find((FunctionDecl
const *)canonicalDecl
)
88 != getFunctionsWithAddressTaken().end())
90 // things that I don't think should be logically const
91 std::string fqn
= pMethodDecl
->getQualifiedNameAsString();
92 if (fqn
== "comphelper::EmbeddedObjectContainer::CommitImageSubStorage"
93 || fqn
== "SvtLinguConfig::SetProperty"
94 || fqn
== "SvtLinguConfig::ReplaceSetProperties"
95 || fqn
== "SystemWindow::UpdatePositionData"
96 || fqn
== "OutputDevice::SelectClipRegion"
97 || fqn
== "OutputDevice::BlendBitmap")
99 StringRef aFileName
= getFilenameOfLocation(compiler
.getSourceManager().getSpellingLoc(compat::getBeginLoc(canonicalDecl
)));
100 // leave the kit API alone
101 if (loplugin::isSamePathname(aFileName
, SRCDIR
"/include/LibreOfficeKit/LibreOfficeKit.hxx"))
103 // don't feel like touching this right now
104 if (loplugin::isSamePathname(aFileName
, SRCDIR
"/include/vcl/weld.hxx"))
107 DiagnosticsEngine::Warning
,
108 "this method can be const",
109 compat::getBeginLoc(pMethodDecl
))
110 << pMethodDecl
->getSourceRange();
111 if (canonicalDecl
->getLocation() != pMethodDecl
->getLocation()) {
113 DiagnosticsEngine::Note
,
114 "canonical method declaration here",
115 compat::getBeginLoc(canonicalDecl
))
116 << canonicalDecl
->getSourceRange();
121 bool TraverseCXXMethodDecl(CXXMethodDecl
*);
122 bool TraverseCXXConversionDecl(CXXConversionDecl
*);
123 bool VisitCXXMethodDecl(const CXXMethodDecl
*);
124 bool VisitCXXThisExpr(const CXXThisExpr
*);
127 bool isPointerOrReferenceToConst(const QualType
& qt
);
128 bool isPointerOrReferenceToNonConst(const QualType
& qt
);
129 bool checkIfCanBeConst(const Stmt
*, const CXXMethodDecl
*);
131 std::unordered_set
<const CXXMethodDecl
*> interestingMethodSet
;
132 std::unordered_set
<const CXXMethodDecl
*> methodCannotBeConstSet
;
133 CXXMethodDecl
const * currCXXMethodDecl
;
136 bool ConstMethod::TraverseCXXMethodDecl(CXXMethodDecl
* cxxMethodDecl
)
138 currCXXMethodDecl
= cxxMethodDecl
;
139 bool rv
= RecursiveASTVisitor
<ConstMethod
>::TraverseCXXMethodDecl(cxxMethodDecl
);
140 currCXXMethodDecl
= nullptr;
144 bool ConstMethod::TraverseCXXConversionDecl(CXXConversionDecl
* cxxConversionDecl
)
146 currCXXMethodDecl
= cxxConversionDecl
;
147 bool rv
= RecursiveASTVisitor
<ConstMethod
>::TraverseCXXConversionDecl(cxxConversionDecl
);
148 currCXXMethodDecl
= nullptr;
152 bool ConstMethod::VisitCXXMethodDecl(const CXXMethodDecl
* cxxMethodDecl
)
154 if (ignoreLocation(cxxMethodDecl
) || !cxxMethodDecl
->isThisDeclarationADefinition()) {
157 if (cxxMethodDecl
->isConst())
159 // ignore stuff that forms part of the stable URE interface
160 if (isInUnoIncludeFile(cxxMethodDecl
)) {
163 // TODO ignore template stuff for now
164 if (cxxMethodDecl
->getTemplatedKind() != FunctionDecl::TK_NonTemplate
) {
167 if (cxxMethodDecl
->isDeleted())
169 if (cxxMethodDecl
->isStatic())
171 if (cxxMethodDecl
->isOverloadedOperator())
173 if (isa
<CXXConstructorDecl
>(cxxMethodDecl
))
175 if (isa
<CXXDestructorDecl
>(cxxMethodDecl
))
177 if (cxxMethodDecl
->getParent()->getDescribedClassTemplate() != nullptr ) {
180 // ignore virtual methods
181 if (cxxMethodDecl
->isVirtual() ) {
184 // ignore macro expansions so we can ignore the IMPL_LINK macros from include/tools/link.hxx
185 // TODO make this more precise
186 if (cxxMethodDecl
->getLocation().isMacroID())
189 if (!cxxMethodDecl
->getIdentifier())
191 // if (cxxMethodDecl->getNumParams() > 0)
193 // returning pointers or refs to non-const stuff, and then having the whole method
194 // be const doesn't seem like a good idea
195 auto tc
= loplugin::TypeCheck(cxxMethodDecl
->getReturnType());
196 if (tc
.Pointer().NonConst())
198 if (tc
.LvalueReference().NonConst())
200 // a Get method that returns void is probably doing something that has side-effects
204 // StringRef name = cxxMethodDecl->getName();
205 // if (!name.startswith("get") && !name.startswith("Get")
206 // && !name.startswith("is") && !name.startswith("Is")
207 // && !name.startswith("has") && !name.startswith("Has"))
210 // something lacking in my analysis here
211 if (loplugin::DeclCheck(cxxMethodDecl
).Function("GetDescr").Class("SwRangeRedline").GlobalNamespace())
214 interestingMethodSet
.insert(cxxMethodDecl
);
219 bool ConstMethod::VisitCXXThisExpr( const CXXThisExpr
* cxxThisExpr
)
221 if (!currCXXMethodDecl
)
223 if (ignoreLocation(cxxThisExpr
))
225 // ignore stuff that forms part of the stable URE interface
226 if (isInUnoIncludeFile(compat::getBeginLoc(cxxThisExpr
)))
228 if (interestingMethodSet
.find(currCXXMethodDecl
) == interestingMethodSet
.end())
230 // no need to check again if we have already eliminated this one
231 if (methodCannotBeConstSet
.find(currCXXMethodDecl
) != methodCannotBeConstSet
.end())
233 if (!checkIfCanBeConst(cxxThisExpr
, currCXXMethodDecl
))
234 methodCannotBeConstSet
.insert(currCXXMethodDecl
);
239 // Walk up from a statement that contains a CXXThisExpr, checking if the usage means that the
240 // related CXXMethodDecl can be const.
241 bool ConstMethod::checkIfCanBeConst(const Stmt
* stmt
, const CXXMethodDecl
* cxxMethodDecl
)
243 const Stmt
* parent
= getParentStmt( stmt
);
245 auto parentsRange
= compiler
.getASTContext().getParents(*stmt
);
246 if ( parentsRange
.begin() == parentsRange
.end())
248 auto varDecl
= dyn_cast_or_null
<VarDecl
>(parentsRange
.begin()->get
<Decl
>());
252 DiagnosticsEngine::Warning
,
254 compat::getBeginLoc(stmt
))
255 << stmt
->getSourceRange();
258 return varDecl
->getType()->isIntegralOrEnumerationType()
259 || loplugin::TypeCheck(varDecl
->getType()).Pointer().Const()
260 || loplugin::TypeCheck(varDecl
->getType()).LvalueReference().Const();
263 if (auto unaryOperator
= dyn_cast
<UnaryOperator
>(parent
)) {
264 UnaryOperator::Opcode op
= unaryOperator
->getOpcode();
265 if (op
== UO_PreInc
|| op
== UO_PostInc
266 || op
== UO_PreDec
|| op
== UO_PostDec
) {
269 if (op
== UO_Deref
|| op
== UO_AddrOf
) {
270 return checkIfCanBeConst(parent
, cxxMethodDecl
);
273 } else if (auto binaryOp
= dyn_cast
<BinaryOperator
>(parent
)) {
274 BinaryOperator::Opcode op
= binaryOp
->getOpcode();
275 if (binaryOp
->getRHS() == stmt
) {
278 if (op
== BO_Assign
|| op
== BO_PtrMemD
|| op
== BO_PtrMemI
|| op
== BO_MulAssign
279 || op
== BO_DivAssign
|| op
== BO_RemAssign
|| op
== BO_AddAssign
280 || op
== BO_SubAssign
|| op
== BO_ShlAssign
|| op
== BO_ShrAssign
281 || op
== BO_AndAssign
|| op
== BO_XorAssign
|| op
== BO_OrAssign
) {
284 // // for pointer arithmetic need to check parent
285 // if (binaryOp->getType()->isPointerType()) {
286 // return checkIfCanBeConst(parent, cxxMethodDecl);
289 } else if (auto constructExpr
= dyn_cast
<CXXConstructExpr
>(parent
)) {
290 const CXXConstructorDecl
* constructorDecl
= constructExpr
->getConstructor();
291 for (unsigned i
= 0; i
< constructExpr
->getNumArgs(); ++i
) {
292 if (constructExpr
->getArg(i
) == stmt
) {
293 return isPointerOrReferenceToConst(constructorDecl
->getParamDecl(i
)->getType());
296 return false; // TODO ??
297 } else if (auto operatorCallExpr
= dyn_cast
<CXXOperatorCallExpr
>(parent
)) {
298 const CXXMethodDecl
* calleeMethodDecl
= dyn_cast_or_null
<CXXMethodDecl
>(operatorCallExpr
->getDirectCallee());
299 if (calleeMethodDecl
) {
301 if (calleeMethodDecl
->getNumParams() == 0) {
302 // some classes like std::unique_ptr do not do a very good job with their operator-> which is always const
303 if (operatorCallExpr
->getOperator() == OO_Arrow
|| operatorCallExpr
->getOperator() == OO_Star
) {
304 return checkIfCanBeConst(parent
, cxxMethodDecl
);
306 return calleeMethodDecl
->isConst();
308 // some classes like std::unique_ptr do not do a very good job with their operator[] which is always const
309 if (calleeMethodDecl
->getNumParams() == 1 && operatorCallExpr
->getArg(0) == stmt
) {
310 if (operatorCallExpr
->getOperator() == OO_Subscript
) {
315 if (operatorCallExpr
->getArg(0) == stmt
) {
316 return calleeMethodDecl
->isConst();
318 unsigned const n
= std::min(
319 operatorCallExpr
->getNumArgs(),
320 calleeMethodDecl
->getNumParams());
321 for (unsigned i
= 1; i
< n
; ++i
)
322 if (operatorCallExpr
->getArg(i
) == stmt
) {
323 return isPointerOrReferenceToConst(calleeMethodDecl
->getParamDecl(i
- 1)->getType());
326 const Expr
* callee
= operatorCallExpr
->getCallee()->IgnoreParenImpCasts();
327 const DeclRefExpr
* dr
= dyn_cast
<DeclRefExpr
>(callee
);
328 const FunctionDecl
* calleeFunctionDecl
= nullptr;
330 calleeFunctionDecl
= dyn_cast
<FunctionDecl
>(dr
->getDecl());
332 if (calleeFunctionDecl
) {
333 for (unsigned i
= 0; i
< operatorCallExpr
->getNumArgs(); ++i
) {
334 if (operatorCallExpr
->getArg(i
) == stmt
) {
335 return isPointerOrReferenceToConst(calleeFunctionDecl
->getParamDecl(i
)->getType());
340 return false; // TODO ???
341 } else if (auto callExpr
= dyn_cast
<CallExpr
>(parent
)) {
342 QualType functionType
= callExpr
->getCallee()->getType();
343 if (functionType
->isFunctionPointerType()) {
344 functionType
= functionType
->getPointeeType();
346 if (const FunctionProtoType
* prototype
= functionType
->getAs
<FunctionProtoType
>()) {
347 // TODO could do better
348 if (prototype
->isVariadic()) {
351 if (callExpr
->getCallee() == stmt
) {
354 for (unsigned i
= 0; i
< callExpr
->getNumArgs(); ++i
) {
355 if (callExpr
->getArg(i
) == stmt
) {
356 return isPointerOrReferenceToConst(prototype
->getParamType(i
));
360 const FunctionDecl
* calleeFunctionDecl
= callExpr
->getDirectCallee();
361 if (calleeFunctionDecl
)
363 if (auto memberCallExpr
= dyn_cast
<CXXMemberCallExpr
>(parent
)) {
364 const MemberExpr
* memberExpr
= dyn_cast
<MemberExpr
>(stmt
);
365 if (memberExpr
&& memberCallExpr
->getImplicitObjectArgument() == memberExpr
->getBase())
367 const CXXMethodDecl
* calleeMethodDecl
= dyn_cast
<CXXMethodDecl
>(calleeFunctionDecl
);
368 // some classes like std::unique_ptr do not do a very good job with their get() which is always const
369 if (calleeMethodDecl
->getIdentifier() && calleeMethodDecl
->getName() == "get") {
370 return checkIfCanBeConst(parent
, cxxMethodDecl
);
372 // VclPtr<T>'s implicit conversion to T*
373 if (isa
<CXXConversionDecl
>(calleeMethodDecl
)) {
374 if (loplugin::DeclCheck(calleeMethodDecl
->getParent()).Class("OWeakObject").Namespace("cppu").GlobalNamespace())
376 return checkIfCanBeConst(parent
, cxxMethodDecl
);
378 return calleeMethodDecl
->isConst();
381 // TODO could do better
382 if (calleeFunctionDecl
->isVariadic()) {
385 if (callExpr
->getCallee() == stmt
) {
388 for (unsigned i
= 0; i
< callExpr
->getNumArgs(); ++i
) {
389 if (i
>= calleeFunctionDecl
->getNumParams()) // can happen in template code
391 if (callExpr
->getArg(i
) == stmt
) {
392 return isPointerOrReferenceToConst(calleeFunctionDecl
->getParamDecl(i
)->getType());
396 return false; // TODO ????
397 // } else if (auto callExpr = dyn_cast<ObjCMessageExpr>(parent)) {
398 // if (callExpr->getInstanceReceiver() == stmt) {
401 // if (auto const method = callExpr->getMethodDecl()) {
402 // // TODO could do better
403 // if (method->isVariadic()) {
406 // assert(method->param_size() == callExpr->getNumArgs());
407 // for (unsigned i = 0; i < callExpr->getNumArgs(); ++i) {
408 // if (callExpr->getArg(i) == stmt) {
409 // return isPointerOrReferenceToConst(
410 // method->param_begin()[i]->getType());
414 // return false; // TODO ????
415 } else if (isa
<CXXReinterpretCastExpr
>(parent
)) {
417 } else if (isa
<ImplicitCastExpr
>(parent
)) {
418 return checkIfCanBeConst(parent
, cxxMethodDecl
);
419 } else if (isa
<CXXStaticCastExpr
>(parent
)) {
420 return checkIfCanBeConst(parent
, cxxMethodDecl
);
421 } else if (isa
<CXXDynamicCastExpr
>(parent
)) {
422 return checkIfCanBeConst(parent
, cxxMethodDecl
);
423 } else if (isa
<CXXFunctionalCastExpr
>(parent
)) {
424 return checkIfCanBeConst(parent
, cxxMethodDecl
);
425 } else if (isa
<CXXConstCastExpr
>(parent
)) {
427 } else if (isa
<CStyleCastExpr
>(parent
)) {
428 return checkIfCanBeConst(parent
, cxxMethodDecl
);
429 // } else if (isa<CastExpr>(parent)) { // all other cast expression subtypes
430 // if (auto e = dyn_cast<ExplicitCastExpr>(parent)) {
431 // if (loplugin::TypeCheck(e->getTypeAsWritten()).Void()) {
432 // if (auto const sub = dyn_cast<DeclRefExpr>(
433 // e->getSubExpr()->IgnoreParenImpCasts()))
435 // if (sub->getDecl() == cxxMethodDecl) {
441 // return checkIfCanBeConst(parent, cxxMethodDecl);
442 } else if (isa
<MemberExpr
>(parent
)) {
443 return checkIfCanBeConst(parent
, cxxMethodDecl
);
444 } else if (auto arraySubscriptExpr
= dyn_cast
<ArraySubscriptExpr
>(parent
)) {
445 if (arraySubscriptExpr
->getIdx() == stmt
)
447 return checkIfCanBeConst(parent
, cxxMethodDecl
);
448 } else if (isa
<ParenExpr
>(parent
)) {
449 return checkIfCanBeConst(parent
, cxxMethodDecl
);
450 } else if (auto declStmt
= dyn_cast
<DeclStmt
>(parent
)) {
451 for (Decl
const * decl
: declStmt
->decls())
452 if (auto varDecl
= dyn_cast
<VarDecl
>(decl
)) {
453 if (varDecl
->getInit() == stmt
) {
454 auto tc
= loplugin::TypeCheck(varDecl
->getType());
455 if (tc
.LvalueReference() && !tc
.LvalueReference().Const())
457 if (tc
.Pointer() && !tc
.Pointer().Const())
463 } else if (isa
<ReturnStmt
>(parent
)) {
464 return !isPointerOrReferenceToNonConst(cxxMethodDecl
->getReturnType());
465 } else if (isa
<InitListExpr
>(parent
)) {
466 return false; // TODO could be improved
467 } else if (isa
<IfStmt
>(parent
)) {
469 } else if (isa
<WhileStmt
>(parent
)) {
471 } else if (isa
<ForStmt
>(parent
)) {
473 } else if (isa
<CompoundStmt
>(parent
)) {
475 } else if (isa
<SwitchStmt
>(parent
)) {
477 } else if (isa
<DoStmt
>(parent
)) {
479 } else if (isa
<CXXDeleteExpr
>(parent
)) {
481 // } else if (isa<VAArgExpr>(parent)) {
483 } else if (isa
<CXXDependentScopeMemberExpr
>(parent
)) {
485 } else if (isa
<MaterializeTemporaryExpr
>(parent
)) {
486 return checkIfCanBeConst(parent
, cxxMethodDecl
);
487 } else if (auto conditionalExpr
= dyn_cast
<ConditionalOperator
>(parent
)) {
488 if (conditionalExpr
->getCond() == stmt
)
490 return checkIfCanBeConst(parent
, cxxMethodDecl
);
491 // } else if (isa<UnaryExprOrTypeTraitExpr>(parent)) {
492 // return false; // ???
493 } else if (isa
<CXXNewExpr
>(parent
)) {
494 // for (auto pa : cxxNewExpr->placement_arguments())
497 return true; // because the Stmt must be a parameter to the expression, probably an array length
498 // } else if (auto lambdaExpr = dyn_cast<LambdaExpr>(parent)) {
499 //// for (auto it = lambdaExpr->capture_begin(); it != lambdaExpr->capture_end(); ++it)
501 //// if (it->capturesVariable() && it->getCapturedVar() == cxxMethodDecl)
502 //// return it->getCaptureKind() != LCK_ByRef;
505 // } else if (isa<CXXTypeidExpr>(parent)) {
507 } else if (isa
<ParenListExpr
>(parent
)) {
509 } else if (isa
<CXXUnresolvedConstructExpr
>(parent
)) {
511 // } else if (isa<UnresolvedMemberExpr>(parent)) {
513 // } else if (isa<PackExpansionExpr>(parent)) {
515 } else if (isa
<ExprWithCleanups
>(parent
)) {
516 return checkIfCanBeConst(parent
, cxxMethodDecl
);
517 // } else if (isa<CaseStmt>(parent)) {
519 // } else if (isa<CXXPseudoDestructorExpr>(parent)) {
521 // } else if (isa<CXXDependentScopeMemberExpr>(parent)) {
523 // } else if (isa<ObjCIvarRefExpr>(parent)) {
524 // return checkIfCanBeConst(parent, cxxMethodDecl);
525 } else if (isa
<CXXTemporaryObjectExpr
>(parent
)) {
527 } else if (isa
<CXXBindTemporaryExpr
>(parent
)) {
532 // if (cxxMethodDecl)
533 // cxxMethodDecl->dump();
535 DiagnosticsEngine::Warning
,
536 "oh dear, what can the matter be?",
537 compat::getBeginLoc(parent
))
538 << parent
->getSourceRange();
542 bool ConstMethod::isPointerOrReferenceToConst(const QualType
& qt
) {
543 auto const type
= loplugin::TypeCheck(qt
);
544 if (type
.Pointer()) {
545 return bool(type
.Pointer().Const());
546 } else if (type
.LvalueReference()) {
547 return bool(type
.LvalueReference().Const());
552 bool ConstMethod::isPointerOrReferenceToNonConst(const QualType
& qt
) {
553 auto const type
= loplugin::TypeCheck(qt
);
554 if (type
.Pointer()) {
555 return !bool(type
.Pointer().Const());
556 } else if (type
.LvalueReference()) {
557 return !bool(type
.LvalueReference().Const());
562 loplugin::Plugin::Registration
< ConstMethod
> X("constmethod", false);
566 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */