tdf#153972 Fix color filter when cells have no content
[LibreOffice.git] / compilerplugins / clang / constmethod.cxx
blobda5a64aea9b44d1074cf61073740eaf0b2e2d658
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <algorithm>
11 #include <string>
12 #include <unordered_set>
13 #include <unordered_map>
14 #include <iostream>
16 #include "config_clang.h"
18 #include "plugin.hxx"
19 #include "compat.hxx"
20 #include "check.hxx"
21 #include "functionaddress.hxx"
23 #if CLANG_VERSION >= 110000
24 #include "clang/AST/ParentMapContext.h"
25 #endif
27 /**
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.
36 namespace
39 class ConstMethod:
40 public loplugin::FunctionAddress<loplugin::FilteringPlugin<ConstMethod>>
42 public:
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/")
79 return;
81 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
83 for (const CXXMethodDecl *pMethodDecl : interestingMethodSet) {
84 if (methodCannotBeConstSet.find(pMethodDecl) != methodCannotBeConstSet.end())
85 continue;
86 auto canonicalDecl = pMethodDecl->getCanonicalDecl();
87 if (getFunctionsWithAddressTaken().find((FunctionDecl const *)canonicalDecl)
88 != getFunctionsWithAddressTaken().end())
89 continue;
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")
98 continue;
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"))
102 continue;
103 // don't feel like touching this right now
104 if (loplugin::isSamePathname(aFileName, SRCDIR "/include/vcl/weld.hxx"))
105 continue;
106 report(
107 DiagnosticsEngine::Warning,
108 "this method can be const",
109 compat::getBeginLoc(pMethodDecl))
110 << pMethodDecl->getSourceRange();
111 if (canonicalDecl->getLocation() != pMethodDecl->getLocation()) {
112 report(
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 *);
126 private:
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;
141 return rv;
144 bool ConstMethod::TraverseCXXConversionDecl(CXXConversionDecl * cxxConversionDecl)
146 currCXXMethodDecl = cxxConversionDecl;
147 bool rv = RecursiveASTVisitor<ConstMethod>::TraverseCXXConversionDecl(cxxConversionDecl);
148 currCXXMethodDecl = nullptr;
149 return rv;
152 bool ConstMethod::VisitCXXMethodDecl(const CXXMethodDecl * cxxMethodDecl)
154 if (ignoreLocation(cxxMethodDecl) || !cxxMethodDecl->isThisDeclarationADefinition()) {
155 return true;
157 if (cxxMethodDecl->isConst())
158 return true;
159 // ignore stuff that forms part of the stable URE interface
160 if (isInUnoIncludeFile(cxxMethodDecl)) {
161 return true;
163 // TODO ignore template stuff for now
164 if (cxxMethodDecl->getTemplatedKind() != FunctionDecl::TK_NonTemplate) {
165 return true;
167 if (cxxMethodDecl->isDeleted())
168 return true;
169 if (cxxMethodDecl->isStatic())
170 return true;
171 if (cxxMethodDecl->isOverloadedOperator())
172 return true;
173 if (isa<CXXConstructorDecl>(cxxMethodDecl))
174 return true;
175 if (isa<CXXDestructorDecl>(cxxMethodDecl))
176 return true;
177 if (cxxMethodDecl->getParent()->getDescribedClassTemplate() != nullptr ) {
178 return true;
180 // ignore virtual methods
181 if (cxxMethodDecl->isVirtual() ) {
182 return true;
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())
187 return true;
189 if (!cxxMethodDecl->getIdentifier())
190 return true;
191 // if (cxxMethodDecl->getNumParams() > 0)
192 // return true;
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())
197 return true;
198 if (tc.LvalueReference().NonConst())
199 return true;
200 // a Get method that returns void is probably doing something that has side-effects
201 if (tc.Void())
202 return true;
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"))
208 // return true;
210 // something lacking in my analysis here
211 if (loplugin::DeclCheck(cxxMethodDecl).Function("GetDescr").Class("SwRangeRedline").GlobalNamespace())
212 return true;
214 interestingMethodSet.insert(cxxMethodDecl);
216 return true;
219 bool ConstMethod::VisitCXXThisExpr( const CXXThisExpr* cxxThisExpr )
221 if (!currCXXMethodDecl)
222 return true;
223 if (ignoreLocation(cxxThisExpr))
224 return true;
225 // ignore stuff that forms part of the stable URE interface
226 if (isInUnoIncludeFile(compat::getBeginLoc(cxxThisExpr)))
227 return true;
228 if (interestingMethodSet.find(currCXXMethodDecl) == interestingMethodSet.end())
229 return true;
230 // no need to check again if we have already eliminated this one
231 if (methodCannotBeConstSet.find(currCXXMethodDecl) != methodCannotBeConstSet.end())
232 return true;
233 if (!checkIfCanBeConst(cxxThisExpr, currCXXMethodDecl))
234 methodCannotBeConstSet.insert(currCXXMethodDecl);
236 return true;
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 );
244 if (!parent) {
245 auto parentsRange = compiler.getASTContext().getParents(*stmt);
246 if ( parentsRange.begin() == parentsRange.end())
247 return true;
248 auto varDecl = dyn_cast_or_null<VarDecl>(parentsRange.begin()->get<Decl>());
249 if (!varDecl)
251 report(
252 DiagnosticsEngine::Warning,
253 "no parent?",
254 compat::getBeginLoc(stmt))
255 << stmt->getSourceRange();
256 return false;
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) {
267 return false;
269 if (op == UO_Deref || op == UO_AddrOf) {
270 return checkIfCanBeConst(parent, cxxMethodDecl);
272 return true;
273 } else if (auto binaryOp = dyn_cast<BinaryOperator>(parent)) {
274 BinaryOperator::Opcode op = binaryOp->getOpcode();
275 if (binaryOp->getRHS() == stmt) {
276 return true;
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) {
282 return false;
284 // // for pointer arithmetic need to check parent
285 // if (binaryOp->getType()->isPointerType()) {
286 // return checkIfCanBeConst(parent, cxxMethodDecl);
287 // }
288 return true;
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) {
300 // unary operator
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) {
311 return false;
314 // binary operator
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());
325 } else {
326 const Expr* callee = operatorCallExpr->getCallee()->IgnoreParenImpCasts();
327 const DeclRefExpr* dr = dyn_cast<DeclRefExpr>(callee);
328 const FunctionDecl* calleeFunctionDecl = nullptr;
329 if (dr) {
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()) {
349 return false;
351 if (callExpr->getCallee() == stmt) {
352 return true;
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())
375 return false;
376 return checkIfCanBeConst(parent, cxxMethodDecl);
378 return calleeMethodDecl->isConst();
381 // TODO could do better
382 if (calleeFunctionDecl->isVariadic()) {
383 return false;
385 if (callExpr->getCallee() == stmt) {
386 return true;
388 for (unsigned i = 0; i < callExpr->getNumArgs(); ++i) {
389 if (i >= calleeFunctionDecl->getNumParams()) // can happen in template code
390 return false;
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) {
399 // return true;
400 // }
401 // if (auto const method = callExpr->getMethodDecl()) {
402 // // TODO could do better
403 // if (method->isVariadic()) {
404 // return false;
405 // }
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());
411 // }
412 // }
413 // }
414 // return false; // TODO ????
415 } else if (isa<CXXReinterpretCastExpr>(parent)) {
416 return false;
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)) {
426 return false;
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()))
434 // {
435 // if (sub->getDecl() == cxxMethodDecl) {
436 // return false;
437 // }
438 // }
439 // }
440 // }
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)
446 return true;
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())
456 return false;
457 if (tc.Pointer() && !tc.Pointer().Const())
458 return false;
459 return true;
462 // fall through
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)) {
468 return true;
469 } else if (isa<WhileStmt>(parent)) {
470 return true;
471 } else if (isa<ForStmt>(parent)) {
472 return true;
473 } else if (isa<CompoundStmt>(parent)) {
474 return true;
475 } else if (isa<SwitchStmt>(parent)) {
476 return true;
477 } else if (isa<DoStmt>(parent)) {
478 return true;
479 } else if (isa<CXXDeleteExpr>(parent)) {
480 return false;
481 // } else if (isa<VAArgExpr>(parent)) {
482 // return false;
483 } else if (isa<CXXDependentScopeMemberExpr>(parent)) {
484 return false;
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)
489 return true;
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())
495 // if (pa == stmt)
496 // return false;
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)
500 //// {
501 //// if (it->capturesVariable() && it->getCapturedVar() == cxxMethodDecl)
502 //// return it->getCaptureKind() != LCK_ByRef;
503 //// }
504 // return true;
505 // } else if (isa<CXXTypeidExpr>(parent)) {
506 // return true;
507 } else if (isa<ParenListExpr>(parent)) {
508 return true;
509 } else if (isa<CXXUnresolvedConstructExpr>(parent)) {
510 return false;
511 // } else if (isa<UnresolvedMemberExpr>(parent)) {
512 // return false;
513 // } else if (isa<PackExpansionExpr>(parent)) {
514 // return false;
515 } else if (isa<ExprWithCleanups>(parent)) {
516 return checkIfCanBeConst(parent, cxxMethodDecl);
517 // } else if (isa<CaseStmt>(parent)) {
518 // return true;
519 // } else if (isa<CXXPseudoDestructorExpr>(parent)) {
520 // return false;
521 // } else if (isa<CXXDependentScopeMemberExpr>(parent)) {
522 // return false;
523 // } else if (isa<ObjCIvarRefExpr>(parent)) {
524 // return checkIfCanBeConst(parent, cxxMethodDecl);
525 } else if (isa<CXXTemporaryObjectExpr>(parent)) {
526 return true;
527 } else if (isa<CXXBindTemporaryExpr>(parent)) {
528 return true;
530 if (parent)
531 parent->dump();
532 // if (cxxMethodDecl)
533 // cxxMethodDecl->dump();
534 report(
535 DiagnosticsEngine::Warning,
536 "oh dear, what can the matter be?",
537 compat::getBeginLoc(parent))
538 << parent->getSourceRange();
539 return false;
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());
549 return false;
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());
559 return false;
562 loplugin::Plugin::Registration< ConstMethod > X("constmethod", false);
566 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */