Move setting of LD_LIBRARY_PATH closer to invocation of cppunittester
[LibreOffice.git] / compilerplugins / clang / store / constparams.cxx
blobdac7322d013094404390ebb766b41cc5c2edd523
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 #include "clang/AST/ParentMapContext.h"
25 /**
26 Find pointer and reference params that can be declared const.
28 This is not a sophisticated analysis. It deliberately skips all of the hard cases for now.
29 It is an exercise in getting the most benefit for the least effort.
31 namespace
34 class ConstParams:
35 public loplugin::FunctionAddress<loplugin::FilteringPlugin<ConstParams>>
37 public:
38 explicit ConstParams(loplugin::InstantiationData const & data): FunctionAddress(data) {}
40 virtual void run() override {
41 std::string fn(handler.getMainFileName());
42 loplugin::normalizeDotDotInFilePath(fn);
43 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sal/")
44 || fn == SRCDIR "/jurt/source/pipe/staticsalhack.cxx"
45 || loplugin::hasPathnamePrefix(fn, SRCDIR "/bridges/")
46 || loplugin::hasPathnamePrefix(fn, SRCDIR "/binaryurp/")
47 || loplugin::hasPathnamePrefix(fn, SRCDIR "/stoc/")
48 || loplugin::hasPathnamePrefix(fn, WORKDIR "/YaccTarget/unoidl/source/sourceprovider-parser.cxx")
49 // some weird calling through a function pointer
50 || loplugin::hasPathnamePrefix(fn, SRCDIR "/svtools/source/table/defaultinputhandler.cxx")
51 || loplugin::hasPathnamePrefix(fn, SRCDIR "/sdext/source/pdfimport/test/pdfunzip.cxx")
52 // windows only
53 || loplugin::hasPathnamePrefix(fn, SRCDIR "/basic/source/sbx/sbxdec.cxx")
54 || loplugin::hasPathnamePrefix(fn, SRCDIR "/sfx2/source/doc/syspath.cxx")
55 // ignore this for now
56 || loplugin::hasPathnamePrefix(fn, SRCDIR "/libreofficekit")
57 // FunctionAddress not working well enough here
58 || loplugin::hasPathnamePrefix(fn, SRCDIR "/pyuno/source/module/pyuno_struct.cxx")
59 || loplugin::hasPathnamePrefix(fn, SRCDIR "/pyuno/source/module/pyuno.cxx")
60 || loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/filter/ascii/ascatr.cxx")
61 // TODO this plugin doesn't handle it well when we take the address of a pointer
62 || loplugin::hasPathnamePrefix(fn, SRCDIR "/svl/source/misc/sharedstringpool.cxx")
63 || loplugin::hasPathnamePrefix(fn, SRCDIR "/registry/source/regkey.cxx")
64 || loplugin::hasPathnamePrefix(fn, SRCDIR "/cppu/source/uno/lbenv.cxx")
65 || loplugin::hasPathnamePrefix(fn, SRCDIR "/cppuhelper/source/implbase_ex.cxx")
67 return;
69 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
71 for (const ParmVarDecl *pParmVarDecl : interestingParamSet) {
72 auto functionDecl = parmToFunction[pParmVarDecl];
73 auto canonicalDecl = functionDecl->getCanonicalDecl();
74 if (getFunctionsWithAddressTaken().find(canonicalDecl)
75 != getFunctionsWithAddressTaken().end())
77 continue;
79 std::string fname = functionDecl->getQualifiedNameAsString();
80 report(
81 DiagnosticsEngine::Warning,
82 "this parameter can be const %0",
83 pParmVarDecl->getBeginLoc())
84 << fname << pParmVarDecl->getSourceRange();
85 if (canonicalDecl->getLocation() != functionDecl->getLocation()) {
86 unsigned idx = pParmVarDecl->getFunctionScopeIndex();
87 const ParmVarDecl* pOther = canonicalDecl->getParamDecl(idx);
88 report(
89 DiagnosticsEngine::Note,
90 "canonical parameter declaration here",
91 pOther->getBeginLoc())
92 << pOther->getSourceRange();
94 //functionDecl->dump();
98 bool TraverseFunctionDecl(FunctionDecl *);
99 bool TraverseCXXMethodDecl(CXXMethodDecl * f);
100 bool TraverseCXXConstructorDecl(CXXConstructorDecl * f);
101 bool VisitDeclRefExpr(const DeclRefExpr *);
102 bool VisitLambdaExpr(const LambdaExpr*);
104 private:
105 bool CheckTraverseFunctionDecl(FunctionDecl *);
106 bool checkIfCanBeConst(const Stmt*, const ParmVarDecl*);
107 // integral or enumeration or const * or const &
108 bool isOkForParameter(const QualType& qt);
109 bool isPointerOrReferenceToNonConst(const QualType& qt);
111 std::unordered_set<const ParmVarDecl*> interestingParamSet;
112 std::unordered_map<const ParmVarDecl*, const FunctionDecl*> parmToFunction;
113 FunctionDecl* currentFunctionDecl = nullptr;
116 bool ConstParams::TraverseFunctionDecl(FunctionDecl * functionDecl)
118 // We cannot short-circuit the traverse here entirely without breaking the
119 // loplugin::FunctionAddress stuff.
120 auto prev = currentFunctionDecl;
121 if (CheckTraverseFunctionDecl(functionDecl))
122 currentFunctionDecl = functionDecl;
123 auto rv = FunctionAddress::TraverseFunctionDecl(functionDecl);
124 currentFunctionDecl = prev;
125 return rv;
127 bool ConstParams::TraverseCXXMethodDecl(CXXMethodDecl * f)
129 auto prev = currentFunctionDecl;
130 if (CheckTraverseFunctionDecl(f))
131 currentFunctionDecl = f;
132 auto rv = FunctionAddress::TraverseCXXMethodDecl(f);
133 currentFunctionDecl = prev;
134 return rv;
136 bool ConstParams::TraverseCXXConstructorDecl(CXXConstructorDecl * f)
138 auto prev = currentFunctionDecl;
139 if (CheckTraverseFunctionDecl(f))
140 currentFunctionDecl = f;
141 auto rv = FunctionAddress::TraverseCXXConstructorDecl(f);
142 currentFunctionDecl = prev;
143 return rv;
146 bool ConstParams::CheckTraverseFunctionDecl(FunctionDecl * functionDecl)
148 if (ignoreLocation(functionDecl) || !functionDecl->isThisDeclarationADefinition()) {
149 return false;
151 // ignore stuff that forms part of the stable URE interface
152 if (isInUnoIncludeFile(functionDecl)) {
153 return false;
155 if (functionDecl->isDeleted())
156 return false;
157 // ignore virtual methods
158 if (isa<CXXMethodDecl>(functionDecl)
159 && dyn_cast<CXXMethodDecl>(functionDecl)->isVirtual() ) {
160 return false;
162 // ignore C main
163 if (functionDecl->isMain()) {
164 return false;
166 if (functionDecl->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
167 return false;
169 // ignore the macros from include/tools/link.hxx
170 auto canonicalDecl = functionDecl->getCanonicalDecl();
171 if (compiler.getSourceManager().isMacroBodyExpansion(canonicalDecl->getBeginLoc())
172 || compiler.getSourceManager().isMacroArgExpansion(canonicalDecl->getBeginLoc())) {
173 StringRef name { Lexer::getImmediateMacroName(
174 canonicalDecl->getBeginLoc(), compiler.getSourceManager(), compiler.getLangOpts()) };
175 if (name.startswith("DECL_LINK") || name.startswith("DECL_STATIC_LINK"))
176 return false;
177 auto loc2 = compat::getImmediateExpansionRange(compiler.getSourceManager(), canonicalDecl->getBeginLoc()).first;
178 if (compiler.getSourceManager().isMacroBodyExpansion(loc2))
180 StringRef name2 { Lexer::getImmediateMacroName(
181 loc2, compiler.getSourceManager(), compiler.getLangOpts()) };
182 if (name2.startswith("DECL_DLLPRIVATE_LINK"))
183 return false;
187 if (functionDecl->getIdentifier())
189 StringRef name = functionDecl->getName();
190 if ( name == "file_write"
191 || name == "SalMainPipeExchangeSignal_impl"
192 || name.startswith("SbRtl_")
193 || name == "GoNext"
194 || name == "GoPrevious"
195 || name.startswith("Read_F_")
196 // UNO component entry points
197 || name.endswith("component_getFactory")
198 || name.endswith("_get_implementation")
199 // callback for some external code?
200 || name == "ScAddInAsyncCallBack"
201 // used as function pointers
202 || name == "Read_Footnote"
203 || name == "Read_Field"
204 || name == "Read_And"
205 // passed as a LINK<> to another method
206 || name == "GlobalBasicErrorHdl_Impl"
207 // template
208 || name == "extract_throw" || name == "readProp"
209 // callbacks
210 || name == "signalDragDropReceived" || name == "signal_column_clicked" || name == "signal_key_press"
212 return false;
216 std::string fqn = functionDecl->getQualifiedNameAsString();
217 if ( fqn == "connectivity::jdbc::GlobalRef::set"
218 || fqn == "(anonymous namespace)::ReorderNotifier::operator()"
219 || fqn == "static_txtattr_cast")
220 return false;
222 // calculate the ones we want to check
223 bool foundInterestingParam = false;
224 for (const ParmVarDecl *pParmVarDecl : functionDecl->parameters()) {
225 // ignore unused params
226 if (pParmVarDecl->getName().empty()
227 || pParmVarDecl->hasAttr<UnusedAttr>())
228 continue;
229 auto const type = loplugin::TypeCheck(pParmVarDecl->getType());
230 if (!( type.Pointer().NonConst()
231 || type.LvalueReference().NonConst()))
232 continue;
233 // since we normally can't change typedefs, just ignore them
234 if (isa<TypedefType>(pParmVarDecl->getType()))
235 continue;
236 // some typedefs turn into these
237 if (isa<DecayedType>(pParmVarDecl->getType()))
238 continue;
239 // TODO ignore these for now, has some effects I don't understand
240 if (type.Pointer().Pointer())
241 continue;
242 // const is meaningless when applied to function pointer types
243 if (pParmVarDecl->getType()->isFunctionPointerType())
244 continue;
245 interestingParamSet.insert(pParmVarDecl);
246 parmToFunction[pParmVarDecl] = functionDecl;
247 foundInterestingParam = true;
249 return foundInterestingParam;
252 bool ConstParams::VisitDeclRefExpr( const DeclRefExpr* declRefExpr )
254 if (!currentFunctionDecl)
255 return true;
256 const ParmVarDecl* parmVarDecl = dyn_cast_or_null<ParmVarDecl>(declRefExpr->getDecl());
257 if (!parmVarDecl)
258 return true;
259 if (interestingParamSet.find(parmVarDecl) == interestingParamSet.end())
260 return true;
261 if (!checkIfCanBeConst(declRefExpr, parmVarDecl))
262 interestingParamSet.erase(parmVarDecl);
263 return true;
266 bool ConstParams::VisitLambdaExpr(const LambdaExpr* lambdaExpr)
268 if (ignoreLocation(lambdaExpr))
269 return true;
270 for (auto captureIt = lambdaExpr->capture_begin(); captureIt != lambdaExpr->capture_end();
271 ++captureIt)
273 const LambdaCapture& capture = *captureIt;
274 if (capture.capturesVariable())
276 if (auto varDecl = dyn_cast<ParmVarDecl>(capture.getCapturedVar()))
277 interestingParamSet.erase(varDecl);
280 return true;
283 // Walk up from a statement that contains a DeclRefExpr, checking if the usage means that the
284 // related ParamVarDecl can be const.
285 bool ConstParams::checkIfCanBeConst(const Stmt* stmt, const ParmVarDecl* parmVarDecl)
287 const Stmt* parent = getParentStmt( stmt );
288 if (!parent)
290 // check if we're inside a CXXCtorInitializer
291 auto parentsRange = compiler.getASTContext().getParents(*stmt);
292 auto it = parentsRange.begin();
293 if ( parentsRange.begin() != parentsRange.end())
295 const Decl *decl = it->get<Decl>();
296 if (auto cxxConstructorDecl = dyn_cast_or_null<CXXConstructorDecl>(decl))
298 for ( auto cxxCtorInitializer : cxxConstructorDecl->inits())
300 if ( cxxCtorInitializer->getInit() == stmt)
302 if (cxxCtorInitializer->isAnyMemberInitializer())
304 // if the member is not pointer-to-const or ref-to-const or value, we cannot make the param const
305 auto fieldDecl = cxxCtorInitializer->getAnyMember();
306 auto tc = loplugin::TypeCheck(fieldDecl->getType());
307 if (tc.Pointer() || tc.LvalueReference())
308 return tc.Pointer().Const() || tc.LvalueReference().Const();
309 else
310 return true;
312 else
314 // probably base initialiser, but no simple way to look up the relevant constructor decl
315 return false;
320 if (auto varDecl = dyn_cast_or_null<VarDecl>(decl))
322 return isOkForParameter(varDecl->getType());
325 // parmVarDecl->dump();
326 // stmt->dump();
327 // report(
328 // DiagnosticsEngine::Warning,
329 // "no parent?",
330 // stmt->getBeginLoc())
331 // << stmt->getSourceRange();
332 return false;
335 if (auto unaryOperator = dyn_cast<UnaryOperator>(parent)) {
336 UnaryOperator::Opcode op = unaryOperator->getOpcode();
337 if (op == UO_PreInc || op == UO_PostInc
338 || op == UO_PreDec || op == UO_PostDec) {
339 return false;
341 if (op == UO_Deref || op == UO_AddrOf) {
342 return checkIfCanBeConst(parent, parmVarDecl);
344 return true;
345 } else if (auto binaryOp = dyn_cast<BinaryOperator>(parent)) {
346 BinaryOperator::Opcode op = binaryOp->getOpcode();
347 if (binaryOp->getRHS() == stmt && op == BO_Assign) {
348 return isOkForParameter(binaryOp->getLHS()->getType());
350 if (binaryOp->getRHS() == stmt) {
351 return true;
353 if (op == BO_Assign || op == BO_PtrMemD || op == BO_PtrMemI || op == BO_MulAssign
354 || op == BO_DivAssign || op == BO_RemAssign || op == BO_AddAssign
355 || op == BO_SubAssign || op == BO_ShlAssign || op == BO_ShrAssign
356 || op == BO_AndAssign || op == BO_XorAssign || op == BO_OrAssign) {
357 return false;
359 // for pointer arithmetic need to check parent
360 if (binaryOp->getType()->isPointerType()) {
361 return checkIfCanBeConst(parent, parmVarDecl);
363 return true;
364 } else if (auto constructExpr = dyn_cast<CXXConstructExpr>(parent)) {
365 const CXXConstructorDecl * constructorDecl = constructExpr->getConstructor();
366 for (unsigned i = 0; i < constructExpr->getNumArgs(); ++i) {
367 if (constructExpr->getArg(i) == stmt) {
368 return isOkForParameter(constructorDecl->getParamDecl(i)->getType());
371 } else if (auto operatorCallExpr = dyn_cast<CXXOperatorCallExpr>(parent)) {
372 const CXXMethodDecl* calleeMethodDecl = dyn_cast_or_null<CXXMethodDecl>(operatorCallExpr->getDirectCallee());
373 if (calleeMethodDecl) {
374 // unary operator
375 if (calleeMethodDecl->getNumParams() == 0)
376 return calleeMethodDecl->isConst();
377 // Same logic as CXXOperatorCallExpr::isAssignmentOp(), which our supported clang
378 // doesn't have yet.
379 auto Opc = operatorCallExpr->getOperator();
380 if (Opc == OO_Equal || Opc == OO_StarEqual ||
381 Opc == OO_SlashEqual || Opc == OO_PercentEqual ||
382 Opc == OO_PlusEqual || Opc == OO_MinusEqual ||
383 Opc == OO_LessLessEqual || Opc == OO_GreaterGreaterEqual ||
384 Opc == OO_AmpEqual || Opc == OO_CaretEqual ||
385 Opc == OO_PipeEqual)
387 if (operatorCallExpr->getArg(0) == stmt) // assigning to the param
388 return false;
389 // not all operator= take a const&
390 return isOkForParameter(calleeMethodDecl->getParamDecl(0)->getType());
392 if (operatorCallExpr->getOperator() == OO_Subscript && operatorCallExpr->getArg(1) == stmt)
393 return true;
394 if (operatorCallExpr->getOperator() == OO_EqualEqual || operatorCallExpr->getOperator() == OO_ExclaimEqual)
395 return true;
396 // binary operator
397 if (operatorCallExpr->getArg(0) == stmt)
398 return calleeMethodDecl->isConst();
399 unsigned const n = std::min(
400 operatorCallExpr->getNumArgs(),
401 calleeMethodDecl->getNumParams() + 1);
402 for (unsigned i = 1; i < n; ++i)
403 if (operatorCallExpr->getArg(i) == stmt) {
404 auto qt = calleeMethodDecl->getParamDecl(i - 1)->getType();
405 return isOkForParameter(qt);
407 } else {
408 const Expr* callee = operatorCallExpr->getCallee()->IgnoreParenImpCasts();
409 const DeclRefExpr* dr = dyn_cast<DeclRefExpr>(callee);
410 const FunctionDecl* calleeFunctionDecl = nullptr;
411 if (dr) {
412 calleeFunctionDecl = dyn_cast<FunctionDecl>(dr->getDecl());
414 if (calleeFunctionDecl) {
415 for (unsigned i = 0; i < operatorCallExpr->getNumArgs(); ++i) {
416 if (operatorCallExpr->getArg(i) == stmt) {
417 return isOkForParameter(calleeFunctionDecl->getParamDecl(i)->getType());
422 return false;
423 } else if (auto callExpr = dyn_cast<CallExpr>(parent)) {
424 QualType functionType = callExpr->getCallee()->getType();
425 if (functionType->isFunctionPointerType()) {
426 functionType = functionType->getPointeeType();
428 if (const FunctionProtoType* prototype = functionType->getAs<FunctionProtoType>()) {
429 // TODO could do better
430 if (prototype->isVariadic()) {
431 return false;
433 if (callExpr->getCallee() == stmt) {
434 return true;
436 for (unsigned i = 0; i < callExpr->getNumArgs(); ++i) {
437 if (callExpr->getArg(i) == stmt) {
438 return isOkForParameter(prototype->getParamType(i));
442 const FunctionDecl* calleeFunctionDecl = callExpr->getDirectCallee();
443 if (calleeFunctionDecl)
445 if (auto memberCallExpr = dyn_cast<CXXMemberCallExpr>(parent)) {
446 const MemberExpr* memberExpr = dyn_cast<MemberExpr>(stmt);
447 if (memberExpr && memberCallExpr->getImplicitObjectArgument() == memberExpr->getBase())
449 const CXXMethodDecl* calleeMethodDecl = dyn_cast<CXXMethodDecl>(calleeFunctionDecl);
450 return calleeMethodDecl->isConst();
453 // TODO could do better
454 if (calleeFunctionDecl->isVariadic()) {
455 return false;
457 if (callExpr->getCallee() == stmt) {
458 return true;
460 for (unsigned i = 0; i < callExpr->getNumArgs(); ++i) {
461 if (i >= calleeFunctionDecl->getNumParams()) // can happen in template code
462 return false;
463 if (callExpr->getArg(i) == stmt) {
464 return isOkForParameter(calleeFunctionDecl->getParamDecl(i)->getType());
468 return false;
469 } else if (auto callExpr = dyn_cast<ObjCMessageExpr>(parent)) {
470 if (callExpr->getInstanceReceiver() == stmt) {
471 return true;
473 if (auto const method = callExpr->getMethodDecl()) {
474 // TODO could do better
475 if (method->isVariadic()) {
476 return false;
478 assert(method->param_size() == callExpr->getNumArgs());
479 for (unsigned i = 0; i < callExpr->getNumArgs(); ++i) {
480 if (callExpr->getArg(i) == stmt) {
481 return isOkForParameter(
482 method->param_begin()[i]->getType());
486 } else if (isa<CXXReinterpretCastExpr>(parent)) {
487 return false;
488 } else if (isa<CXXConstCastExpr>(parent)) {
489 return false;
490 } else if (isa<CastExpr>(parent)) { // all other cast expression subtypes
491 if (auto e = dyn_cast<ExplicitCastExpr>(parent)) {
492 if (loplugin::TypeCheck(e->getTypeAsWritten()).Void()) {
493 if (auto const sub = dyn_cast<DeclRefExpr>(
494 e->getSubExpr()->IgnoreParenImpCasts()))
496 if (sub->getDecl() == parmVarDecl)
497 return false;
501 return checkIfCanBeConst(parent, parmVarDecl);
502 } else if (isa<MemberExpr>(parent)) {
503 return checkIfCanBeConst(parent, parmVarDecl);
504 } else if (auto arraySubscriptExpr = dyn_cast<ArraySubscriptExpr>(parent)) {
505 if (arraySubscriptExpr->getIdx() == stmt)
506 return true;
507 return checkIfCanBeConst(parent, parmVarDecl);
508 } else if (isa<ParenExpr>(parent)) {
509 return checkIfCanBeConst(parent, parmVarDecl);
510 } else if (isa<DeclStmt>(parent)) {
511 // TODO could do better here, but would require tracking the target(s)
512 //return false;
513 } else if (isa<ReturnStmt>(parent)) {
514 return !isPointerOrReferenceToNonConst(currentFunctionDecl->getReturnType());
515 } else if (isa<InitListExpr>(parent)) {
516 return false;
517 } else if (isa<IfStmt>(parent)) {
518 return true;
519 } else if (isa<WhileStmt>(parent)) {
520 return true;
521 } else if (isa<ForStmt>(parent)) {
522 return true;
523 } else if (isa<CompoundStmt>(parent)) {
524 return true;
525 } else if (isa<SwitchStmt>(parent)) {
526 return true;
527 } else if (isa<DoStmt>(parent)) {
528 return true;
529 } else if (isa<CXXDeleteExpr>(parent)) {
530 return false;
531 } else if (isa<VAArgExpr>(parent)) {
532 return false;
533 } else if (isa<CXXDependentScopeMemberExpr>(parent)) {
534 return false;
535 } else if (isa<MaterializeTemporaryExpr>(parent)) {
536 return checkIfCanBeConst(parent, parmVarDecl);
537 } else if (auto conditionalExpr = dyn_cast<ConditionalOperator>(parent)) {
538 if (conditionalExpr->getCond() == stmt)
539 return true;
540 return checkIfCanBeConst(parent, parmVarDecl);
541 } else if (isa<UnaryExprOrTypeTraitExpr>(parent)) {
542 return false; // ???
543 } else if (auto cxxNewExpr = dyn_cast<CXXNewExpr>(parent)) {
544 for (unsigned i = 0; i < cxxNewExpr->getNumPlacementArgs(); ++i)
545 if (cxxNewExpr->getPlacementArg(i) == stmt)
546 return false;
547 return true; // ???
548 } else if (auto lambdaExpr = dyn_cast<LambdaExpr>(parent)) {
549 for (auto it = lambdaExpr->capture_begin(); it != lambdaExpr->capture_end(); ++it)
551 if (it->capturesVariable() && it->getCapturedVar() == parmVarDecl)
552 return it->getCaptureKind() != LCK_ByRef;
554 return false;
555 } else if (isa<CXXTypeidExpr>(parent)) {
556 return true;
557 } else if (isa<ParenListExpr>(parent)) {
558 return false; // could be improved, seen in constructors when calling base class constructor
559 } else if (isa<CXXUnresolvedConstructExpr>(parent)) {
560 return false;
561 } else if (isa<UnresolvedMemberExpr>(parent)) {
562 return false;
563 } else if (isa<PackExpansionExpr>(parent)) {
564 return false;
565 } else if (isa<ExprWithCleanups>(parent)) {
566 return checkIfCanBeConst(parent, parmVarDecl);
567 } else if (isa<CaseStmt>(parent)) {
568 return true;
569 } else if (isa<CXXPseudoDestructorExpr>(parent)) {
570 return false;
571 } else if (isa<CXXDependentScopeMemberExpr>(parent)) {
572 return false;
573 } else if (isa<ObjCIvarRefExpr>(parent)) {
574 return checkIfCanBeConst(parent, parmVarDecl);
576 parent->dump();
577 parmVarDecl->dump();
578 report(
579 DiagnosticsEngine::Warning,
580 "oh dear, what can the matter be?",
581 parent->getBeginLoc())
582 << parent->getSourceRange();
583 return true;
586 bool ConstParams::isOkForParameter(const QualType& qt) {
587 if (qt->isIntegralOrEnumerationType())
588 return true;
589 auto const type = loplugin::TypeCheck(qt);
590 if (type.Pointer()) {
591 return bool(type.Pointer().Const());
592 } else if (type.LvalueReference().Const().Pointer()) {
593 // If we have a method that takes (T* t) and it calls std::vector<T*>::push_back
594 // then the type of push_back is T * const &
595 // There is probably a more elegant way to check this, but it will probably require
596 // recalculating types while walking up the AST.
597 return false;
598 } else if (type.LvalueReference()) {
599 return bool(type.LvalueReference().Const());
601 return false;
604 bool ConstParams::isPointerOrReferenceToNonConst(const QualType& qt) {
605 auto const type = loplugin::TypeCheck(qt);
606 if (type.Pointer()) {
607 return !bool(type.Pointer().Const());
608 } else if (type.LvalueReference()) {
609 return !bool(type.LvalueReference().Const());
611 return false;
614 loplugin::Plugin::Registration< ConstParams > X("constparams", false);
618 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */