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 static bool startswith(const std::string
& rStr
, const char* pSubStr
) {
27 return rStr
.compare(0, strlen(pSubStr
), pSubStr
) == 0;
30 class ExpressionAlwaysZero
:
31 public RecursiveASTVisitor
<ExpressionAlwaysZero
>, public loplugin::Plugin
34 explicit ExpressionAlwaysZero(loplugin::InstantiationData
const & data
): Plugin(data
) {}
36 virtual void run() override
38 std::string
fn( compiler
.getSourceManager().getFileEntryForID(
39 compiler
.getSourceManager().getMainFileID())->getName() );
40 loplugin::normalizeDotDotInFilePath(fn
);
41 // encoding of constant value for binary file format
42 if (startswith(fn
, SRCDIR
"/package/source/zipapi/ZipFile.cxx"))
44 // some auto-generated static data
45 if (startswith(fn
, SRCDIR
"/sal/textenc/tables.cxx"))
47 // nested conditional defines that are not worth cleaning up
48 if (startswith(fn
, SRCDIR
"/opencl/source/openclwrapper.cxx"))
50 // some kind of matrix calculation, the compiler will optimise it out anyway
51 if (startswith(fn
, SRCDIR
"/vcl/source/gdi/bitmap4.cxx"))
53 // code follows a pattern
54 if (startswith(fn
, SRCDIR
"/svx/source/svdraw/svdhdl.cxx"))
56 // looks like some kind of TODO marker
57 if (startswith(fn
, SRCDIR
"/chart2/source/view/main/PropertyMapper.cxx")
58 || startswith(fn
, SRCDIR
"/sc/source/core/data/formulacell.cxx"))
60 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
63 bool VisitBinaryOperator(BinaryOperator
const *);
64 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr
const *);
65 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
->getLocStart().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)
93 DiagnosticsEngine::Warning
, "expression always evaluates to zero, lhs=%0 rhs=%1",
94 binaryOperator
->getLocStart())
95 << (lhsValue
? lhsValue
->toString(10) : "unknown")
96 << (rhsValue
? rhsValue
->toString(10) : "unknown")
97 << binaryOperator
->getSourceRange();
101 bool ExpressionAlwaysZero::VisitCXXOperatorCallExpr( CXXOperatorCallExpr
const * cxxOperatorCallExpr
)
103 if (ignoreLocation(cxxOperatorCallExpr
))
105 if (cxxOperatorCallExpr
->getLocStart().isMacroID())
108 auto op
= cxxOperatorCallExpr
->getOperator();
109 if ( !(op
== OO_Amp
|| op
== OO_AmpEqual
|| op
== OO_AmpAmp
))
112 if (cxxOperatorCallExpr
->getNumArgs() != 2)
114 auto lhsValue
= getExprValue(cxxOperatorCallExpr
->getArg(0));
115 auto rhsValue
= getExprValue(cxxOperatorCallExpr
->getArg(1));
116 if (lhsValue
&& lhsValue
->getExtValue() == 0)
118 else if (rhsValue
&& rhsValue
->getExtValue() == 0)
120 else if (lhsValue
&& rhsValue
&& (lhsValue
->getExtValue() & rhsValue
->getExtValue()) == 0)
125 DiagnosticsEngine::Warning
, "expression always evaluates to zero, lhs=%0 rhs=%1",
126 cxxOperatorCallExpr
->getLocStart())
127 << (lhsValue
? lhsValue
->toString(10) : "unknown")
128 << (rhsValue
? rhsValue
->toString(10) : "unknown")
129 << cxxOperatorCallExpr
->getSourceRange();
133 std::unique_ptr
<APSInt
> ExpressionAlwaysZero::getExprValue(Expr
const * expr
)
135 expr
= expr
->IgnoreParenCasts();
136 // ignore this, it seems to trigger an infinite recursion
137 if (isa
<UnaryExprOrTypeTraitExpr
>(expr
)) {
138 return std::unique_ptr
<APSInt
>();
141 if (expr
->EvaluateAsInt(x1
, compiler
.getASTContext()))
142 return std::unique_ptr
<APSInt
>(new APSInt(x1
));
143 return std::unique_ptr
<APSInt
>();
146 // these will often evaluate to zero harmlessly
147 bool ExpressionAlwaysZero::TraverseStaticAssertDecl( StaticAssertDecl
* )
152 // on clang-3.8, this plugin can generate OOM
153 #if CLANG_VERSION >= 30900
154 loplugin::Plugin::Registration
< ExpressionAlwaysZero
> X("expressionalwayszero");
156 loplugin::Plugin::Registration
< ExpressionAlwaysZero
> X("expressionalwayszero", false);
161 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */