Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / compilerplugins / clang / expressionalwayszero.cxx
blobf741d30c426bf3b2a2fb0d4ae3bc4cb77be62abe
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 <string>
11 #include <set>
12 #include <iostream>
13 #include <fstream>
15 #include "plugin.hxx"
16 #include "compat.hxx"
17 #include "check.hxx"
19 /**
20 Look for & and operator& expressions where the result is always zero.
21 Generally a mistake when people meant to use | or operator|
24 namespace
26 class ExpressionAlwaysZero : public loplugin::FilteringPlugin<ExpressionAlwaysZero>
28 public:
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"))
42 return;
43 // some auto-generated static data
44 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sal/textenc/tables.cxx"))
45 return;
46 // nested conditional defines that are not worth cleaning up
47 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/opencl/source/openclwrapper.cxx"))
48 return;
49 // some kind of matrix calculation, the compiler will optimise it out anyway
50 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/vcl/source/gdi/bitmap4.cxx"))
51 return;
52 // code follows a pattern
53 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/svx/source/svdraw/svdhdl.cxx"))
54 return;
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"))
58 return;
59 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
62 bool VisitBinaryOperator(BinaryOperator const*);
63 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr const*);
64 bool TraverseStaticAssertDecl(StaticAssertDecl*);
66 private:
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))
74 return true;
75 if (binaryOperator->getBeginLoc().isMacroID())
76 return true;
78 auto op = binaryOperator->getOpcode();
79 if (!(op == BO_And || op == BO_AndAssign || op == BO_LAnd))
80 return true;
82 auto lhsValue = getExprValue(binaryOperator->getLHS());
83 auto rhsValue = getExprValue(binaryOperator->getRHS());
84 if (lhsValue && lhsValue->getExtValue() == 0)
85 ; // ok
86 else if (rhsValue && rhsValue->getExtValue() == 0)
87 ; // ok
88 else if (lhsValue && rhsValue && (lhsValue->getExtValue() & rhsValue->getExtValue()) == 0)
89 ; // ok
90 else
91 return true;
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();
97 return true;
100 bool ExpressionAlwaysZero::VisitCXXOperatorCallExpr(CXXOperatorCallExpr const* cxxOperatorCallExpr)
102 if (ignoreLocation(cxxOperatorCallExpr))
103 return true;
104 if (cxxOperatorCallExpr->getBeginLoc().isMacroID())
105 return true;
107 auto op = cxxOperatorCallExpr->getOperator();
108 if (!(op == OO_Amp || op == OO_AmpEqual || op == OO_AmpAmp))
109 return true;
111 if (cxxOperatorCallExpr->getNumArgs() != 2)
112 return true;
113 auto lhsValue = getExprValue(cxxOperatorCallExpr->getArg(0));
114 auto rhsValue = getExprValue(cxxOperatorCallExpr->getArg(1));
115 if (lhsValue && lhsValue->getExtValue() == 0)
116 ; // ok
117 else if (rhsValue && rhsValue->getExtValue() == 0)
118 ; // ok
119 else if (lhsValue && rhsValue && (lhsValue->getExtValue() & rhsValue->getExtValue()) == 0)
120 ; // ok
121 else
122 return true;
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();
128 return true;
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>();
139 APSInt x1;
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: */