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"
20 #include "functionaddress.hxx"
22 #include "clang/AST/ParentMapContext.h"
25 Find methods that can be declared const.
27 This analysis attempts to implement "logical const" as opposed to "technical const", which means
28 we ignore always-const nature of std::unique_ptr::operator->
30 This is not a sophisticated analysis. It deliberately skips all of the hard cases for now.
31 It is an exercise in getting the most benefit for the least effort.
37 public loplugin::FunctionAddress
<loplugin::FilteringPlugin
<ConstMethod
>>
40 explicit ConstMethod(loplugin::InstantiationData
const & data
): FunctionAddress(data
) {}
42 virtual void run() override
{
43 std::string
fn(handler
.getMainFileName());
44 loplugin::normalizeDotDotInFilePath(fn
);
45 // things I'm not sure about
46 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/svl/unx/source/svdde/ddedummy.cxx")
47 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/svl/source/numbers/zformat.cxx")
48 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/svl/source/numbers/zforscan.cxx")
49 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/svl/source/numbers/zforlist.cxx")
50 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/source/gdi/impgraph.cxx")
51 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/source/image/ImplImage.cxx")
52 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/source/filter/wmf/wmfwr.cxx")
53 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/unx/generic/app/i18n_im.cxx")
54 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/unx/generic/app/randrwrapper.cxx")
55 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/unx/gtk3/gtkinst.cxx")
56 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/unx/gtk3/gtkframe.cxx")
57 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/skia/gdiimpl.cxx")
58 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/qt5/")
59 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/package/source/xstor/owriteablestream.cxx")
60 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/package/source/zippackage/ZipPackage.cxx")
61 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/toolkit/")
62 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/canvas/")
63 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/accessibility/")
64 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/framework/")
65 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/basic/")
66 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/sfx2/")
67 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/xmloff/")
68 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/connectivity/")
69 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/editeng/")
70 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/scripting/")
71 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/ucb/")
72 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/svx/")
73 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/basctl/")
74 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/chart2/")
78 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
80 for (const CXXMethodDecl
*pMethodDecl
: interestingMethodSet
) {
81 if (methodCannotBeConstSet
.find(pMethodDecl
) != methodCannotBeConstSet
.end())
83 auto canonicalDecl
= pMethodDecl
->getCanonicalDecl();
84 if (getFunctionsWithAddressTaken().find((FunctionDecl
const *)canonicalDecl
)
85 != getFunctionsWithAddressTaken().end())
87 // things that I don't think should be logically const
88 std::string fqn
= pMethodDecl
->getQualifiedNameAsString();
89 if (fqn
== "comphelper::EmbeddedObjectContainer::CommitImageSubStorage"
90 || fqn
== "SvtLinguConfig::SetProperty"
91 || fqn
== "SvtLinguConfig::ReplaceSetProperties"
92 || fqn
== "SystemWindow::UpdatePositionData"
93 || fqn
== "OutputDevice::SelectClipRegion"
94 || fqn
== "OutputDevice::BlendBitmap")
96 StringRef aFileName
= getFilenameOfLocation(compiler
.getSourceManager().getSpellingLoc(canonicalDecl
->getBeginLoc()));
97 // leave the kit API alone
98 if (loplugin::isSamePathname(aFileName
, SRCDIR
"/include/LibreOfficeKit/LibreOfficeKit.hxx"))
100 // don't feel like touching this right now
101 if (loplugin::isSamePathname(aFileName
, SRCDIR
"/include/vcl/weld.hxx"))
104 DiagnosticsEngine::Warning
,
105 "this method can be const",
106 pMethodDecl
->getBeginLoc())
107 << pMethodDecl
->getSourceRange();
108 if (canonicalDecl
->getLocation() != pMethodDecl
->getLocation()) {
110 DiagnosticsEngine::Note
,
111 "canonical method declaration here",
112 canonicalDecl
->getBeginLoc())
113 << canonicalDecl
->getSourceRange();
118 bool TraverseCXXMethodDecl(CXXMethodDecl
*);
119 bool TraverseCXXConversionDecl(CXXConversionDecl
*);
120 bool VisitCXXMethodDecl(const CXXMethodDecl
*);
121 bool VisitCXXThisExpr(const CXXThisExpr
*);
124 bool isPointerOrReferenceToConst(const QualType
& qt
);
125 bool isPointerOrReferenceToNonConst(const QualType
& qt
);
126 bool checkIfCanBeConst(const Stmt
*, const CXXMethodDecl
*);
128 std::unordered_set
<const CXXMethodDecl
*> interestingMethodSet
;
129 std::unordered_set
<const CXXMethodDecl
*> methodCannotBeConstSet
;
130 CXXMethodDecl
const * currCXXMethodDecl
;
133 bool ConstMethod::TraverseCXXMethodDecl(CXXMethodDecl
* cxxMethodDecl
)
135 currCXXMethodDecl
= cxxMethodDecl
;
136 bool rv
= RecursiveASTVisitor
<ConstMethod
>::TraverseCXXMethodDecl(cxxMethodDecl
);
137 currCXXMethodDecl
= nullptr;
141 bool ConstMethod::TraverseCXXConversionDecl(CXXConversionDecl
* cxxConversionDecl
)
143 currCXXMethodDecl
= cxxConversionDecl
;
144 bool rv
= RecursiveASTVisitor
<ConstMethod
>::TraverseCXXConversionDecl(cxxConversionDecl
);
145 currCXXMethodDecl
= nullptr;
149 bool ConstMethod::VisitCXXMethodDecl(const CXXMethodDecl
* cxxMethodDecl
)
151 if (ignoreLocation(cxxMethodDecl
) || !cxxMethodDecl
->isThisDeclarationADefinition()) {
154 if (cxxMethodDecl
->isConst())
156 // ignore stuff that forms part of the stable URE interface
157 if (isInUnoIncludeFile(cxxMethodDecl
)) {
160 // TODO ignore template stuff for now
161 if (cxxMethodDecl
->getTemplatedKind() != FunctionDecl::TK_NonTemplate
) {
164 if (cxxMethodDecl
->isDeleted())
166 if (cxxMethodDecl
->isStatic())
168 if (cxxMethodDecl
->isOverloadedOperator())
170 if (isa
<CXXConstructorDecl
>(cxxMethodDecl
))
172 if (isa
<CXXDestructorDecl
>(cxxMethodDecl
))
174 if (cxxMethodDecl
->getParent()->getDescribedClassTemplate() != nullptr ) {
177 // ignore virtual methods
178 if (cxxMethodDecl
->isVirtual() ) {
181 // ignore macro expansions so we can ignore the IMPL_LINK macros from include/tools/link.hxx
182 // TODO make this more precise
183 if (cxxMethodDecl
->getLocation().isMacroID())
186 if (!cxxMethodDecl
->getIdentifier())
188 // if (cxxMethodDecl->getNumParams() > 0)
190 // returning pointers or refs to non-const stuff, and then having the whole method
191 // be const doesn't seem like a good idea
192 auto tc
= loplugin::TypeCheck(cxxMethodDecl
->getReturnType());
193 if (tc
.Pointer().NonConst())
195 if (tc
.LvalueReference().NonConst())
197 // a Get method that returns void is probably doing something that has side-effects
201 // StringRef name = cxxMethodDecl->getName();
202 // if (!name.startswith("get") && !name.startswith("Get")
203 // && !name.startswith("is") && !name.startswith("Is")
204 // && !name.startswith("has") && !name.startswith("Has"))
207 // something lacking in my analysis here
208 if (loplugin::DeclCheck(cxxMethodDecl
).Function("GetDescr").Class("SwRangeRedline").GlobalNamespace())
211 interestingMethodSet
.insert(cxxMethodDecl
);
216 bool ConstMethod::VisitCXXThisExpr( const CXXThisExpr
* cxxThisExpr
)
218 if (!currCXXMethodDecl
)
220 if (ignoreLocation(cxxThisExpr
))
222 // ignore stuff that forms part of the stable URE interface
223 if (isInUnoIncludeFile(cxxThisExpr
->getBeginLoc()))
225 if (interestingMethodSet
.find(currCXXMethodDecl
) == interestingMethodSet
.end())
227 // no need to check again if we have already eliminated this one
228 if (methodCannotBeConstSet
.find(currCXXMethodDecl
) != methodCannotBeConstSet
.end())
230 if (!checkIfCanBeConst(cxxThisExpr
, currCXXMethodDecl
))
231 methodCannotBeConstSet
.insert(currCXXMethodDecl
);
236 // Walk up from a statement that contains a CXXThisExpr, checking if the usage means that the
237 // related CXXMethodDecl can be const.
238 bool ConstMethod::checkIfCanBeConst(const Stmt
* stmt
, const CXXMethodDecl
* cxxMethodDecl
)
240 const Stmt
* parent
= getParentStmt( stmt
);
242 auto parentsRange
= compiler
.getASTContext().getParents(*stmt
);
243 if ( parentsRange
.begin() == parentsRange
.end())
245 auto varDecl
= dyn_cast_or_null
<VarDecl
>(parentsRange
.begin()->get
<Decl
>());
249 DiagnosticsEngine::Warning
,
252 << stmt
->getSourceRange();
255 return varDecl
->getType()->isIntegralOrEnumerationType()
256 || loplugin::TypeCheck(varDecl
->getType()).Pointer().Const()
257 || loplugin::TypeCheck(varDecl
->getType()).LvalueReference().Const();
260 if (auto unaryOperator
= dyn_cast
<UnaryOperator
>(parent
)) {
261 UnaryOperator::Opcode op
= unaryOperator
->getOpcode();
262 if (op
== UO_PreInc
|| op
== UO_PostInc
263 || op
== UO_PreDec
|| op
== UO_PostDec
) {
266 if (op
== UO_Deref
|| op
== UO_AddrOf
) {
267 return checkIfCanBeConst(parent
, cxxMethodDecl
);
270 } else if (auto binaryOp
= dyn_cast
<BinaryOperator
>(parent
)) {
271 BinaryOperator::Opcode op
= binaryOp
->getOpcode();
272 if (binaryOp
->getRHS() == stmt
) {
275 if (op
== BO_Assign
|| op
== BO_PtrMemD
|| op
== BO_PtrMemI
|| op
== BO_MulAssign
276 || op
== BO_DivAssign
|| op
== BO_RemAssign
|| op
== BO_AddAssign
277 || op
== BO_SubAssign
|| op
== BO_ShlAssign
|| op
== BO_ShrAssign
278 || op
== BO_AndAssign
|| op
== BO_XorAssign
|| op
== BO_OrAssign
) {
281 // // for pointer arithmetic need to check parent
282 // if (binaryOp->getType()->isPointerType()) {
283 // return checkIfCanBeConst(parent, cxxMethodDecl);
286 } else if (auto constructExpr
= dyn_cast
<CXXConstructExpr
>(parent
)) {
287 const CXXConstructorDecl
* constructorDecl
= constructExpr
->getConstructor();
288 for (unsigned i
= 0; i
< constructExpr
->getNumArgs(); ++i
) {
289 if (constructExpr
->getArg(i
) == stmt
) {
290 return isPointerOrReferenceToConst(constructorDecl
->getParamDecl(i
)->getType());
293 return false; // TODO ??
294 } else if (auto operatorCallExpr
= dyn_cast
<CXXOperatorCallExpr
>(parent
)) {
295 const CXXMethodDecl
* calleeMethodDecl
= dyn_cast_or_null
<CXXMethodDecl
>(operatorCallExpr
->getDirectCallee());
296 if (calleeMethodDecl
) {
298 if (calleeMethodDecl
->getNumParams() == 0) {
299 // some classes like std::unique_ptr do not do a very good job with their operator-> which is always const
300 if (operatorCallExpr
->getOperator() == OO_Arrow
|| operatorCallExpr
->getOperator() == OO_Star
) {
301 return checkIfCanBeConst(parent
, cxxMethodDecl
);
303 return calleeMethodDecl
->isConst();
305 // some classes like std::unique_ptr do not do a very good job with their operator[] which is always const
306 if (calleeMethodDecl
->getNumParams() == 1 && operatorCallExpr
->getArg(0) == stmt
) {
307 if (operatorCallExpr
->getOperator() == OO_Subscript
) {
312 if (operatorCallExpr
->getArg(0) == stmt
) {
313 return calleeMethodDecl
->isConst();
315 unsigned const n
= std::min(
316 operatorCallExpr
->getNumArgs(),
317 calleeMethodDecl
->getNumParams());
318 for (unsigned i
= 1; i
< n
; ++i
)
319 if (operatorCallExpr
->getArg(i
) == stmt
) {
320 return isPointerOrReferenceToConst(calleeMethodDecl
->getParamDecl(i
- 1)->getType());
323 const Expr
* callee
= operatorCallExpr
->getCallee()->IgnoreParenImpCasts();
324 const DeclRefExpr
* dr
= dyn_cast
<DeclRefExpr
>(callee
);
325 const FunctionDecl
* calleeFunctionDecl
= nullptr;
327 calleeFunctionDecl
= dyn_cast
<FunctionDecl
>(dr
->getDecl());
329 if (calleeFunctionDecl
) {
330 for (unsigned i
= 0; i
< operatorCallExpr
->getNumArgs(); ++i
) {
331 if (operatorCallExpr
->getArg(i
) == stmt
) {
332 return isPointerOrReferenceToConst(calleeFunctionDecl
->getParamDecl(i
)->getType());
337 return false; // TODO ???
338 } else if (auto callExpr
= dyn_cast
<CallExpr
>(parent
)) {
339 QualType functionType
= callExpr
->getCallee()->getType();
340 if (functionType
->isFunctionPointerType()) {
341 functionType
= functionType
->getPointeeType();
343 if (const FunctionProtoType
* prototype
= functionType
->getAs
<FunctionProtoType
>()) {
344 // TODO could do better
345 if (prototype
->isVariadic()) {
348 if (callExpr
->getCallee() == stmt
) {
351 for (unsigned i
= 0; i
< callExpr
->getNumArgs(); ++i
) {
352 if (callExpr
->getArg(i
) == stmt
) {
353 return isPointerOrReferenceToConst(prototype
->getParamType(i
));
357 const FunctionDecl
* calleeFunctionDecl
= callExpr
->getDirectCallee();
358 if (calleeFunctionDecl
)
360 if (auto memberCallExpr
= dyn_cast
<CXXMemberCallExpr
>(parent
)) {
361 const MemberExpr
* memberExpr
= dyn_cast
<MemberExpr
>(stmt
);
362 if (memberExpr
&& memberCallExpr
->getImplicitObjectArgument() == memberExpr
->getBase())
364 const CXXMethodDecl
* calleeMethodDecl
= dyn_cast
<CXXMethodDecl
>(calleeFunctionDecl
);
365 // some classes like std::unique_ptr do not do a very good job with their get() which is always const
366 if (calleeMethodDecl
->getIdentifier() && calleeMethodDecl
->getName() == "get") {
367 return checkIfCanBeConst(parent
, cxxMethodDecl
);
369 // VclPtr<T>'s implicit conversion to T*
370 if (isa
<CXXConversionDecl
>(calleeMethodDecl
)) {
371 if (loplugin::DeclCheck(calleeMethodDecl
->getParent()).Class("OWeakObject").Namespace("cppu").GlobalNamespace())
373 return checkIfCanBeConst(parent
, cxxMethodDecl
);
375 return calleeMethodDecl
->isConst();
378 // TODO could do better
379 if (calleeFunctionDecl
->isVariadic()) {
382 if (callExpr
->getCallee() == stmt
) {
385 for (unsigned i
= 0; i
< callExpr
->getNumArgs(); ++i
) {
386 if (i
>= calleeFunctionDecl
->getNumParams()) // can happen in template code
388 if (callExpr
->getArg(i
) == stmt
) {
389 return isPointerOrReferenceToConst(calleeFunctionDecl
->getParamDecl(i
)->getType());
393 return false; // TODO ????
394 // } else if (auto callExpr = dyn_cast<ObjCMessageExpr>(parent)) {
395 // if (callExpr->getInstanceReceiver() == stmt) {
398 // if (auto const method = callExpr->getMethodDecl()) {
399 // // TODO could do better
400 // if (method->isVariadic()) {
403 // assert(method->param_size() == callExpr->getNumArgs());
404 // for (unsigned i = 0; i < callExpr->getNumArgs(); ++i) {
405 // if (callExpr->getArg(i) == stmt) {
406 // return isPointerOrReferenceToConst(
407 // method->param_begin()[i]->getType());
411 // return false; // TODO ????
412 } else if (isa
<CXXReinterpretCastExpr
>(parent
)) {
414 } else if (isa
<ImplicitCastExpr
>(parent
)) {
415 return checkIfCanBeConst(parent
, cxxMethodDecl
);
416 } else if (isa
<CXXStaticCastExpr
>(parent
)) {
417 return checkIfCanBeConst(parent
, cxxMethodDecl
);
418 } else if (isa
<CXXDynamicCastExpr
>(parent
)) {
419 return checkIfCanBeConst(parent
, cxxMethodDecl
);
420 } else if (isa
<CXXFunctionalCastExpr
>(parent
)) {
421 return checkIfCanBeConst(parent
, cxxMethodDecl
);
422 } else if (isa
<CXXConstCastExpr
>(parent
)) {
424 } else if (isa
<CStyleCastExpr
>(parent
)) {
425 return checkIfCanBeConst(parent
, cxxMethodDecl
);
426 // } else if (isa<CastExpr>(parent)) { // all other cast expression subtypes
427 // if (auto e = dyn_cast<ExplicitCastExpr>(parent)) {
428 // if (loplugin::TypeCheck(e->getTypeAsWritten()).Void()) {
429 // if (auto const sub = dyn_cast<DeclRefExpr>(
430 // e->getSubExpr()->IgnoreParenImpCasts()))
432 // if (sub->getDecl() == cxxMethodDecl) {
438 // return checkIfCanBeConst(parent, cxxMethodDecl);
439 } else if (isa
<MemberExpr
>(parent
)) {
440 return checkIfCanBeConst(parent
, cxxMethodDecl
);
441 } else if (auto arraySubscriptExpr
= dyn_cast
<ArraySubscriptExpr
>(parent
)) {
442 if (arraySubscriptExpr
->getIdx() == stmt
)
444 return checkIfCanBeConst(parent
, cxxMethodDecl
);
445 } else if (isa
<ParenExpr
>(parent
)) {
446 return checkIfCanBeConst(parent
, cxxMethodDecl
);
447 } else if (auto declStmt
= dyn_cast
<DeclStmt
>(parent
)) {
448 for (Decl
const * decl
: declStmt
->decls())
449 if (auto varDecl
= dyn_cast
<VarDecl
>(decl
)) {
450 if (varDecl
->getInit() == stmt
) {
451 auto tc
= loplugin::TypeCheck(varDecl
->getType());
452 if (tc
.LvalueReference() && !tc
.LvalueReference().Const())
454 if (tc
.Pointer() && !tc
.Pointer().Const())
460 } else if (isa
<ReturnStmt
>(parent
)) {
461 return !isPointerOrReferenceToNonConst(cxxMethodDecl
->getReturnType());
462 } else if (isa
<InitListExpr
>(parent
)) {
463 return false; // TODO could be improved
464 } else if (isa
<IfStmt
>(parent
)) {
466 } else if (isa
<WhileStmt
>(parent
)) {
468 } else if (isa
<ForStmt
>(parent
)) {
470 } else if (isa
<CompoundStmt
>(parent
)) {
472 } else if (isa
<SwitchStmt
>(parent
)) {
474 } else if (isa
<DoStmt
>(parent
)) {
476 } else if (isa
<CXXDeleteExpr
>(parent
)) {
478 // } else if (isa<VAArgExpr>(parent)) {
480 } else if (isa
<CXXDependentScopeMemberExpr
>(parent
)) {
482 } else if (isa
<MaterializeTemporaryExpr
>(parent
)) {
483 return checkIfCanBeConst(parent
, cxxMethodDecl
);
484 } else if (auto conditionalExpr
= dyn_cast
<ConditionalOperator
>(parent
)) {
485 if (conditionalExpr
->getCond() == stmt
)
487 return checkIfCanBeConst(parent
, cxxMethodDecl
);
488 // } else if (isa<UnaryExprOrTypeTraitExpr>(parent)) {
489 // return false; // ???
490 } else if (isa
<CXXNewExpr
>(parent
)) {
491 // for (auto pa : cxxNewExpr->placement_arguments())
494 return true; // because the Stmt must be a parameter to the expression, probably an array length
495 // } else if (auto lambdaExpr = dyn_cast<LambdaExpr>(parent)) {
496 //// for (auto it = lambdaExpr->capture_begin(); it != lambdaExpr->capture_end(); ++it)
498 //// if (it->capturesVariable() && it->getCapturedVar() == cxxMethodDecl)
499 //// return it->getCaptureKind() != LCK_ByRef;
502 // } else if (isa<CXXTypeidExpr>(parent)) {
504 } else if (isa
<ParenListExpr
>(parent
)) {
506 } else if (isa
<CXXUnresolvedConstructExpr
>(parent
)) {
508 // } else if (isa<UnresolvedMemberExpr>(parent)) {
510 // } else if (isa<PackExpansionExpr>(parent)) {
512 } else if (isa
<ExprWithCleanups
>(parent
)) {
513 return checkIfCanBeConst(parent
, cxxMethodDecl
);
514 // } else if (isa<CaseStmt>(parent)) {
516 // } else if (isa<CXXPseudoDestructorExpr>(parent)) {
518 // } else if (isa<CXXDependentScopeMemberExpr>(parent)) {
520 // } else if (isa<ObjCIvarRefExpr>(parent)) {
521 // return checkIfCanBeConst(parent, cxxMethodDecl);
522 } else if (isa
<CXXTemporaryObjectExpr
>(parent
)) {
524 } else if (isa
<CXXBindTemporaryExpr
>(parent
)) {
529 // if (cxxMethodDecl)
530 // cxxMethodDecl->dump();
532 DiagnosticsEngine::Warning
,
533 "oh dear, what can the matter be?",
534 parent
->getBeginLoc())
535 << parent
->getSourceRange();
539 bool ConstMethod::isPointerOrReferenceToConst(const QualType
& qt
) {
540 auto const type
= loplugin::TypeCheck(qt
);
541 if (type
.Pointer()) {
542 return bool(type
.Pointer().Const());
543 } else if (type
.LvalueReference()) {
544 return bool(type
.LvalueReference().Const());
549 bool ConstMethod::isPointerOrReferenceToNonConst(const QualType
& qt
) {
550 auto const type
= loplugin::TypeCheck(qt
);
551 if (type
.Pointer()) {
552 return !bool(type
.Pointer().Const());
553 } else if (type
.LvalueReference()) {
554 return !bool(type
.LvalueReference().Const());
559 loplugin::Plugin::Registration
< ConstMethod
> X("constmethod", false);
563 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */