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/.
20 Look for & and operator& expressions where the result is always zero.
21 Generally a mistake when people meant to use | or operator|
26 class ExpressionAlwaysZero
: public loplugin::FilteringPlugin
<ExpressionAlwaysZero
>
29 explicit ExpressionAlwaysZero(loplugin::InstantiationData
const& data
)
30 : FilteringPlugin(data
)
34 virtual void run() override
36 // don't use getMainFileID, it may return "<stdin>"
37 std::string
fn(handler
.getMainFileName());
39 loplugin::normalizeDotDotInFilePath(fn
);
40 // encoding of constant value for binary file format
41 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/package/source/zipapi/ZipFile.cxx"))
43 // some auto-generated static data
44 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/sal/textenc/tables.cxx"))
46 // nested conditional defines that are not worth cleaning up
47 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/opencl/source/openclwrapper.cxx"))
49 // some kind of matrix calculation, the compiler will optimise it out anyway
50 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/source/gdi/bitmap4.cxx"))
52 // code follows a pattern
53 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/svx/source/svdraw/svdhdl.cxx"))
55 // looks like some kind of TODO marker
56 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/chart2/source/view/main/PropertyMapper.cxx")
57 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/sc/source/core/data/formulacell.cxx"))
59 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
62 bool VisitBinaryOperator(BinaryOperator
const*);
63 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr
const*);
64 bool TraverseStaticAssertDecl(StaticAssertDecl
*);
67 // note, abusing std::unique_ptr as a std::optional lookalike
68 std::unique_ptr
<APSInt
> getExprValue(const Expr
* arg
);
71 bool ExpressionAlwaysZero::VisitBinaryOperator(BinaryOperator
const* binaryOperator
)
73 if (ignoreLocation(binaryOperator
))
75 if (binaryOperator
->getBeginLoc().isMacroID())
78 auto op
= binaryOperator
->getOpcode();
79 if (!(op
== BO_And
|| op
== BO_AndAssign
|| op
== BO_LAnd
))
82 auto lhsValue
= getExprValue(binaryOperator
->getLHS());
83 auto rhsValue
= getExprValue(binaryOperator
->getRHS());
84 if (lhsValue
&& lhsValue
->getExtValue() == 0)
86 else if (rhsValue
&& rhsValue
->getExtValue() == 0)
88 else if (lhsValue
&& rhsValue
&& (lhsValue
->getExtValue() & rhsValue
->getExtValue()) == 0)
92 report(DiagnosticsEngine::Warning
, "expression always evaluates to zero, lhs=%0 rhs=%1",
93 binaryOperator
->getBeginLoc())
94 << (lhsValue
? compat::toString(*lhsValue
, 10) : "unknown")
95 << (rhsValue
? compat::toString(*rhsValue
, 10) : "unknown")
96 << binaryOperator
->getSourceRange();
100 bool ExpressionAlwaysZero::VisitCXXOperatorCallExpr(CXXOperatorCallExpr
const* cxxOperatorCallExpr
)
102 if (ignoreLocation(cxxOperatorCallExpr
))
104 if (cxxOperatorCallExpr
->getBeginLoc().isMacroID())
107 auto op
= cxxOperatorCallExpr
->getOperator();
108 if (!(op
== OO_Amp
|| op
== OO_AmpEqual
|| op
== OO_AmpAmp
))
111 if (cxxOperatorCallExpr
->getNumArgs() != 2)
113 auto lhsValue
= getExprValue(cxxOperatorCallExpr
->getArg(0));
114 auto rhsValue
= getExprValue(cxxOperatorCallExpr
->getArg(1));
115 if (lhsValue
&& lhsValue
->getExtValue() == 0)
117 else if (rhsValue
&& rhsValue
->getExtValue() == 0)
119 else if (lhsValue
&& rhsValue
&& (lhsValue
->getExtValue() & rhsValue
->getExtValue()) == 0)
123 report(DiagnosticsEngine::Warning
, "expression always evaluates to zero, lhs=%0 rhs=%1",
124 cxxOperatorCallExpr
->getBeginLoc())
125 << (lhsValue
? compat::toString(*lhsValue
, 10) : "unknown")
126 << (rhsValue
? compat::toString(*rhsValue
, 10) : "unknown")
127 << cxxOperatorCallExpr
->getSourceRange();
131 std::unique_ptr
<APSInt
> ExpressionAlwaysZero::getExprValue(Expr
const* expr
)
133 expr
= expr
->IgnoreParenCasts();
134 // ignore this, it seems to trigger an infinite recursion
135 if (isa
<UnaryExprOrTypeTraitExpr
>(expr
))
137 return std::unique_ptr
<APSInt
>();
140 if (!expr
->isValueDependent() && compat::EvaluateAsInt(expr
, x1
, compiler
.getASTContext()))
141 return std::unique_ptr
<APSInt
>(new APSInt(x1
));
142 return std::unique_ptr
<APSInt
>();
145 // these will often evaluate to zero harmlessly
146 bool ExpressionAlwaysZero::TraverseStaticAssertDecl(StaticAssertDecl
*) { return true; }
148 loplugin::Plugin::Registration
<ExpressionAlwaysZero
> X("expressionalwayszero", false);
151 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */