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 #include "clang/AST/ParentMapContext.h"
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.
35 public loplugin::FunctionAddress
<loplugin::FilteringPlugin
<ConstParams
>>
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")
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")
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())
79 std::string fname
= functionDecl
->getQualifiedNameAsString();
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
);
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
*);
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
;
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
;
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
;
146 bool ConstParams::CheckTraverseFunctionDecl(FunctionDecl
* functionDecl
)
148 if (ignoreLocation(functionDecl
) || !functionDecl
->isThisDeclarationADefinition()) {
151 // ignore stuff that forms part of the stable URE interface
152 if (isInUnoIncludeFile(functionDecl
)) {
155 if (functionDecl
->isDeleted())
157 // ignore virtual methods
158 if (isa
<CXXMethodDecl
>(functionDecl
)
159 && dyn_cast
<CXXMethodDecl
>(functionDecl
)->isVirtual() ) {
163 if (functionDecl
->isMain()) {
166 if (functionDecl
->getTemplatedKind() != FunctionDecl::TK_NonTemplate
)
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"))
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"))
187 if (functionDecl
->getIdentifier())
189 StringRef name
= functionDecl
->getName();
190 if ( name
== "file_write"
191 || name
== "SalMainPipeExchangeSignal_impl"
192 || name
.startswith("SbRtl_")
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"
208 || name
== "extract_throw" || name
== "readProp"
210 || name
== "signalDragDropReceived" || name
== "signal_column_clicked" || name
== "signal_key_press"
216 std::string fqn
= functionDecl
->getQualifiedNameAsString();
217 if ( fqn
== "connectivity::jdbc::GlobalRef::set"
218 || fqn
== "(anonymous namespace)::ReorderNotifier::operator()"
219 || fqn
== "static_txtattr_cast")
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
>())
229 auto const type
= loplugin::TypeCheck(pParmVarDecl
->getType());
230 if (!( type
.Pointer().NonConst()
231 || type
.LvalueReference().NonConst()))
233 // since we normally can't change typedefs, just ignore them
234 if (isa
<TypedefType
>(pParmVarDecl
->getType()))
236 // some typedefs turn into these
237 if (isa
<DecayedType
>(pParmVarDecl
->getType()))
239 // TODO ignore these for now, has some effects I don't understand
240 if (type
.Pointer().Pointer())
242 // const is meaningless when applied to function pointer types
243 if (pParmVarDecl
->getType()->isFunctionPointerType())
245 interestingParamSet
.insert(pParmVarDecl
);
246 parmToFunction
[pParmVarDecl
] = functionDecl
;
247 foundInterestingParam
= true;
249 return foundInterestingParam
;
252 bool ConstParams::VisitDeclRefExpr( const DeclRefExpr
* declRefExpr
)
254 if (!currentFunctionDecl
)
256 const ParmVarDecl
* parmVarDecl
= dyn_cast_or_null
<ParmVarDecl
>(declRefExpr
->getDecl());
259 if (interestingParamSet
.find(parmVarDecl
) == interestingParamSet
.end())
261 if (!checkIfCanBeConst(declRefExpr
, parmVarDecl
))
262 interestingParamSet
.erase(parmVarDecl
);
266 bool ConstParams::VisitLambdaExpr(const LambdaExpr
* lambdaExpr
)
268 if (ignoreLocation(lambdaExpr
))
270 for (auto captureIt
= lambdaExpr
->capture_begin(); captureIt
!= lambdaExpr
->capture_end();
273 const LambdaCapture
& capture
= *captureIt
;
274 if (capture
.capturesVariable())
276 if (auto varDecl
= dyn_cast
<ParmVarDecl
>(capture
.getCapturedVar()))
277 interestingParamSet
.erase(varDecl
);
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
);
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();
314 // probably base initialiser, but no simple way to look up the relevant constructor decl
320 if (auto varDecl
= dyn_cast_or_null
<VarDecl
>(decl
))
322 return isOkForParameter(varDecl
->getType());
325 // parmVarDecl->dump();
328 // DiagnosticsEngine::Warning,
330 // stmt->getBeginLoc())
331 // << stmt->getSourceRange();
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
) {
341 if (op
== UO_Deref
|| op
== UO_AddrOf
) {
342 return checkIfCanBeConst(parent
, parmVarDecl
);
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
) {
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
) {
359 // for pointer arithmetic need to check parent
360 if (binaryOp
->getType()->isPointerType()) {
361 return checkIfCanBeConst(parent
, parmVarDecl
);
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
) {
375 if (calleeMethodDecl
->getNumParams() == 0)
376 return calleeMethodDecl
->isConst();
377 // Same logic as CXXOperatorCallExpr::isAssignmentOp(), which our supported clang
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
||
387 if (operatorCallExpr
->getArg(0) == stmt
) // assigning to the param
389 // not all operator= take a const&
390 return isOkForParameter(calleeMethodDecl
->getParamDecl(0)->getType());
392 if (operatorCallExpr
->getOperator() == OO_Subscript
&& operatorCallExpr
->getArg(1) == stmt
)
394 if (operatorCallExpr
->getOperator() == OO_EqualEqual
|| operatorCallExpr
->getOperator() == OO_ExclaimEqual
)
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
);
408 const Expr
* callee
= operatorCallExpr
->getCallee()->IgnoreParenImpCasts();
409 const DeclRefExpr
* dr
= dyn_cast
<DeclRefExpr
>(callee
);
410 const FunctionDecl
* calleeFunctionDecl
= nullptr;
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());
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()) {
433 if (callExpr
->getCallee() == stmt
) {
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()) {
457 if (callExpr
->getCallee() == stmt
) {
460 for (unsigned i
= 0; i
< callExpr
->getNumArgs(); ++i
) {
461 if (i
>= calleeFunctionDecl
->getNumParams()) // can happen in template code
463 if (callExpr
->getArg(i
) == stmt
) {
464 return isOkForParameter(calleeFunctionDecl
->getParamDecl(i
)->getType());
469 } else if (auto callExpr
= dyn_cast
<ObjCMessageExpr
>(parent
)) {
470 if (callExpr
->getInstanceReceiver() == stmt
) {
473 if (auto const method
= callExpr
->getMethodDecl()) {
474 // TODO could do better
475 if (method
->isVariadic()) {
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
)) {
488 } else if (isa
<CXXConstCastExpr
>(parent
)) {
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
)
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
)
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)
513 } else if (isa
<ReturnStmt
>(parent
)) {
514 return !isPointerOrReferenceToNonConst(currentFunctionDecl
->getReturnType());
515 } else if (isa
<InitListExpr
>(parent
)) {
517 } else if (isa
<IfStmt
>(parent
)) {
519 } else if (isa
<WhileStmt
>(parent
)) {
521 } else if (isa
<ForStmt
>(parent
)) {
523 } else if (isa
<CompoundStmt
>(parent
)) {
525 } else if (isa
<SwitchStmt
>(parent
)) {
527 } else if (isa
<DoStmt
>(parent
)) {
529 } else if (isa
<CXXDeleteExpr
>(parent
)) {
531 } else if (isa
<VAArgExpr
>(parent
)) {
533 } else if (isa
<CXXDependentScopeMemberExpr
>(parent
)) {
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
)
540 return checkIfCanBeConst(parent
, parmVarDecl
);
541 } else if (isa
<UnaryExprOrTypeTraitExpr
>(parent
)) {
543 } else if (auto cxxNewExpr
= dyn_cast
<CXXNewExpr
>(parent
)) {
544 for (unsigned i
= 0; i
< cxxNewExpr
->getNumPlacementArgs(); ++i
)
545 if (cxxNewExpr
->getPlacementArg(i
) == stmt
)
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
;
555 } else if (isa
<CXXTypeidExpr
>(parent
)) {
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
)) {
561 } else if (isa
<UnresolvedMemberExpr
>(parent
)) {
563 } else if (isa
<PackExpansionExpr
>(parent
)) {
565 } else if (isa
<ExprWithCleanups
>(parent
)) {
566 return checkIfCanBeConst(parent
, parmVarDecl
);
567 } else if (isa
<CaseStmt
>(parent
)) {
569 } else if (isa
<CXXPseudoDestructorExpr
>(parent
)) {
571 } else if (isa
<CXXDependentScopeMemberExpr
>(parent
)) {
573 } else if (isa
<ObjCIvarRefExpr
>(parent
)) {
574 return checkIfCanBeConst(parent
, parmVarDecl
);
579 DiagnosticsEngine::Warning
,
580 "oh dear, what can the matter be?",
581 parent
->getBeginLoc())
582 << parent
->getSourceRange();
586 bool ConstParams::isOkForParameter(const QualType
& qt
) {
587 if (qt
->isIntegralOrEnumerationType())
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.
598 } else if (type
.LvalueReference()) {
599 return bool(type
.LvalueReference().Const());
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());
614 loplugin::Plugin::Registration
< ConstParams
> X("constparams", false);
618 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */