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
:
27 public loplugin::FilteringPlugin
<ExpressionAlwaysZero
>
30 explicit ExpressionAlwaysZero(loplugin::InstantiationData
const & data
): FilteringPlugin(data
) {}
32 virtual void run() override
34 // don't use getMainFileID, it may return "<stdin>"
35 std::string
fn(handler
.getMainFileName());
37 loplugin::normalizeDotDotInFilePath(fn
);
38 // encoding of constant value for binary file format
39 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/package/source/zipapi/ZipFile.cxx"))
41 // some auto-generated static data
42 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/sal/textenc/tables.cxx"))
44 // nested conditional defines that are not worth cleaning up
45 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/opencl/source/openclwrapper.cxx"))
47 // some kind of matrix calculation, the compiler will optimise it out anyway
48 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/vcl/source/gdi/bitmap4.cxx"))
50 // code follows a pattern
51 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/svx/source/svdraw/svdhdl.cxx"))
53 // looks like some kind of TODO marker
54 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/chart2/source/view/main/PropertyMapper.cxx")
55 || loplugin::hasPathnamePrefix(fn
, SRCDIR
"/sc/source/core/data/formulacell.cxx"))
57 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
60 bool VisitBinaryOperator(BinaryOperator
const *);
61 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr
const *);
62 bool TraverseStaticAssertDecl(StaticAssertDecl
*);
64 // note, abusing std::unique_ptr as a std::optional lookalike
65 std::unique_ptr
<APSInt
> getExprValue(const Expr
* arg
);
68 bool ExpressionAlwaysZero::VisitBinaryOperator( BinaryOperator
const * binaryOperator
)
70 if (ignoreLocation(binaryOperator
))
72 if (compat::getBeginLoc(binaryOperator
).isMacroID())
75 auto op
= binaryOperator
->getOpcode();
76 if (!(op
== BO_And
|| op
== BO_AndAssign
|| op
== BO_LAnd
))
79 auto lhsValue
= getExprValue(binaryOperator
->getLHS());
80 auto rhsValue
= getExprValue(binaryOperator
->getRHS());
81 if (lhsValue
&& lhsValue
->getExtValue() == 0)
83 else if (rhsValue
&& rhsValue
->getExtValue() == 0)
85 else if (lhsValue
&& rhsValue
&& (lhsValue
->getExtValue() & rhsValue
->getExtValue()) == 0)
90 DiagnosticsEngine::Warning
, "expression always evaluates to zero, lhs=%0 rhs=%1",
91 compat::getBeginLoc(binaryOperator
))
92 << (lhsValue
? lhsValue
->toString(10) : "unknown")
93 << (rhsValue
? rhsValue
->toString(10) : "unknown")
94 << binaryOperator
->getSourceRange();
98 bool ExpressionAlwaysZero::VisitCXXOperatorCallExpr( CXXOperatorCallExpr
const * cxxOperatorCallExpr
)
100 if (ignoreLocation(cxxOperatorCallExpr
))
102 if (compat::getBeginLoc(cxxOperatorCallExpr
).isMacroID())
105 auto op
= cxxOperatorCallExpr
->getOperator();
106 if ( !(op
== OO_Amp
|| op
== OO_AmpEqual
|| op
== OO_AmpAmp
))
109 if (cxxOperatorCallExpr
->getNumArgs() != 2)
111 auto lhsValue
= getExprValue(cxxOperatorCallExpr
->getArg(0));
112 auto rhsValue
= getExprValue(cxxOperatorCallExpr
->getArg(1));
113 if (lhsValue
&& lhsValue
->getExtValue() == 0)
115 else if (rhsValue
&& rhsValue
->getExtValue() == 0)
117 else if (lhsValue
&& rhsValue
&& (lhsValue
->getExtValue() & rhsValue
->getExtValue()) == 0)
122 DiagnosticsEngine::Warning
, "expression always evaluates to zero, lhs=%0 rhs=%1",
123 compat::getBeginLoc(cxxOperatorCallExpr
))
124 << (lhsValue
? lhsValue
->toString(10) : "unknown")
125 << (rhsValue
? rhsValue
->toString(10) : "unknown")
126 << cxxOperatorCallExpr
->getSourceRange();
130 std::unique_ptr
<APSInt
> ExpressionAlwaysZero::getExprValue(Expr
const * expr
)
132 expr
= expr
->IgnoreParenCasts();
133 // ignore this, it seems to trigger an infinite recursion
134 if (isa
<UnaryExprOrTypeTraitExpr
>(expr
)) {
135 return std::unique_ptr
<APSInt
>();
138 if (!expr
->isValueDependent() && compat::EvaluateAsInt(expr
, x1
, compiler
.getASTContext()))
139 return std::unique_ptr
<APSInt
>(new APSInt(x1
));
140 return std::unique_ptr
<APSInt
>();
143 // these will often evaluate to zero harmlessly
144 bool ExpressionAlwaysZero::TraverseStaticAssertDecl( StaticAssertDecl
* )
149 loplugin::Plugin::Registration
< ExpressionAlwaysZero
> X("expressionalwayszero", false);
153 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */