bump product version to 6.3.0.0.beta1
[LibreOffice.git] / compilerplugins / clang / expressionalwayszero.cxx
blob067aa9cc6dbd44cab0d898530603dc344173602a
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:
27 public loplugin::FilteringPlugin<ExpressionAlwaysZero>
29 public:
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"))
40 return;
41 // some auto-generated static data
42 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sal/textenc/tables.cxx"))
43 return;
44 // nested conditional defines that are not worth cleaning up
45 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/opencl/source/openclwrapper.cxx"))
46 return;
47 // some kind of matrix calculation, the compiler will optimise it out anyway
48 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/vcl/source/gdi/bitmap4.cxx"))
49 return;
50 // code follows a pattern
51 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/svx/source/svdraw/svdhdl.cxx"))
52 return;
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"))
56 return;
57 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
60 bool VisitBinaryOperator(BinaryOperator const *);
61 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr const *);
62 bool TraverseStaticAssertDecl(StaticAssertDecl *);
63 private:
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))
71 return true;
72 if (compat::getBeginLoc(binaryOperator).isMacroID())
73 return true;
75 auto op = binaryOperator->getOpcode();
76 if (!(op == BO_And || op == BO_AndAssign || op == BO_LAnd))
77 return true;
79 auto lhsValue = getExprValue(binaryOperator->getLHS());
80 auto rhsValue = getExprValue(binaryOperator->getRHS());
81 if (lhsValue && lhsValue->getExtValue() == 0)
82 ; // ok
83 else if (rhsValue && rhsValue->getExtValue() == 0)
84 ; // ok
85 else if (lhsValue && rhsValue && (lhsValue->getExtValue() & rhsValue->getExtValue()) == 0)
86 ; // ok
87 else
88 return true;
89 report(
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();
95 return true;
98 bool ExpressionAlwaysZero::VisitCXXOperatorCallExpr( CXXOperatorCallExpr const * cxxOperatorCallExpr )
100 if (ignoreLocation(cxxOperatorCallExpr))
101 return true;
102 if (compat::getBeginLoc(cxxOperatorCallExpr).isMacroID())
103 return true;
105 auto op = cxxOperatorCallExpr->getOperator();
106 if ( !(op == OO_Amp || op == OO_AmpEqual || op == OO_AmpAmp))
107 return true;
109 if (cxxOperatorCallExpr->getNumArgs() != 2)
110 return true;
111 auto lhsValue = getExprValue(cxxOperatorCallExpr->getArg(0));
112 auto rhsValue = getExprValue(cxxOperatorCallExpr->getArg(1));
113 if (lhsValue && lhsValue->getExtValue() == 0)
114 ; // ok
115 else if (rhsValue && rhsValue->getExtValue() == 0)
116 ; // ok
117 else if (lhsValue && rhsValue && (lhsValue->getExtValue() & rhsValue->getExtValue()) == 0)
118 ; // ok
119 else
120 return true;
121 report(
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();
127 return true;
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>();
137 APSInt x1;
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 * )
146 return true;
149 loplugin::Plugin::Registration< ExpressionAlwaysZero > X("expressionalwayszero", false);
153 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */