summaryrefslogtreecommitdiff
path: root/compilerplugins/clang/expressionalwayszero.cxx
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2017-08-18 13:10:01 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2017-08-18 14:19:20 +0200
commit256c28ae3354d49d0e2ebdf11ef2a64da7954f68 (patch)
treecd12a01a9a6fa72f874ffe053d441cb0e2e4fa91 /compilerplugins/clang/expressionalwayszero.cxx
parent6e1d959a2e890004be5be259610033210d18f7cd (diff)
new loplugin:expressionalwayszero
The code in SvXMLExportItemMapper::exportXML was broken as far back as its introduction in commit 0c28e3c480a95c03b513c55f029b979bcd9c0401 "Move SvXMLAttrContainerItem to SVX, moved writer only code to sw" Change-Id: I90043ce8b7263aa56fd0883d350e29b97eeaf99b Reviewed-on: https://gerrit.libreoffice.org/41282 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'compilerplugins/clang/expressionalwayszero.cxx')
-rw-r--r--compilerplugins/clang/expressionalwayszero.cxx123
1 files changed, 123 insertions, 0 deletions
diff --git a/compilerplugins/clang/expressionalwayszero.cxx b/compilerplugins/clang/expressionalwayszero.cxx
new file mode 100644
index 000000000000..1090d9d9765b
--- /dev/null
+++ b/compilerplugins/clang/expressionalwayszero.cxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <string>
+#include <set>
+#include <iostream>
+#include <fstream>
+
+#include <boost/optional.hpp>
+
+#include "plugin.hxx"
+#include "compat.hxx"
+#include "check.hxx"
+
+/**
+ Look for & and operator& expressions where the result is always zero.
+ Generally a mistake when people meant to use | or operator|
+*/
+
+namespace {
+
+static bool startswith(const std::string& rStr, const char* pSubStr) {
+ return rStr.compare(0, strlen(pSubStr), pSubStr) == 0;
+}
+
+class ExpressionAlwaysZero:
+ public RecursiveASTVisitor<ExpressionAlwaysZero>, public loplugin::Plugin
+{
+public:
+ explicit ExpressionAlwaysZero(InstantiationData const & data): Plugin(data) {}
+
+ virtual void run() override
+ {
+ std::string fn( compiler.getSourceManager().getFileEntryForID(
+ compiler.getSourceManager().getMainFileID())->getName() );
+ normalizeDotDotInFilePath(fn);
+ // encoding of constant value for binary file format
+ if (startswith(fn, SRCDIR "/package/source/zipapi/ZipFile.cxx"))
+ return;
+ TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
+ }
+
+ bool VisitBinaryOperator(BinaryOperator const *);
+ bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr const *);
+ bool TraverseStaticAssertDecl(StaticAssertDecl *);
+private:
+ boost::optional<APSInt> getExprValue(const Expr* arg);
+};
+
+bool ExpressionAlwaysZero::VisitBinaryOperator( BinaryOperator const * binaryOperator )
+{
+ if (ignoreLocation(binaryOperator))
+ return true;
+ if (binaryOperator->getLocStart().isMacroID())
+ return true;
+ if (binaryOperator->getOpcode() != BO_And)
+ return true;
+ auto lhsValue = getExprValue(binaryOperator->getLHS());
+ auto rhsValue = getExprValue(binaryOperator->getRHS());
+ if (!lhsValue || !rhsValue || (lhsValue->getExtValue() & rhsValue->getExtValue()) != 0)
+ return true;
+ report(
+ DiagnosticsEngine::Warning, "expression always evaluates to zero, lhs=%0 rhs=%1",
+ binaryOperator->getLocStart())
+ << lhsValue->toString(10)
+ << rhsValue->toString(10)
+ << binaryOperator->getSourceRange();
+ return true;
+}
+
+bool ExpressionAlwaysZero::VisitCXXOperatorCallExpr( CXXOperatorCallExpr const * cxxOperatorCallExpr )
+{
+ if (ignoreLocation(cxxOperatorCallExpr))
+ return true;
+ if (cxxOperatorCallExpr->getLocStart().isMacroID())
+ return true;
+ if (cxxOperatorCallExpr->getOperator() != clang::OverloadedOperatorKind::OO_Amp)
+ return true;
+ if (cxxOperatorCallExpr->getNumArgs() != 2)
+ return true;
+ auto lhsValue = getExprValue(cxxOperatorCallExpr->getArg(0));
+ auto rhsValue = getExprValue(cxxOperatorCallExpr->getArg(1));
+ if (!lhsValue || !rhsValue || (lhsValue->getExtValue() & rhsValue->getExtValue()) != 0)
+ return true;
+ report(
+ DiagnosticsEngine::Warning, "expression always evaluates to zero, lhs=%0 rhs=%1",
+ cxxOperatorCallExpr->getLocStart())
+ << lhsValue->toString(10)
+ << rhsValue->toString(10)
+ << cxxOperatorCallExpr->getSourceRange();
+ return true;
+}
+
+boost::optional<APSInt> ExpressionAlwaysZero::getExprValue(Expr const * expr)
+{
+ expr = expr->IgnoreParenCasts();
+ // ignore this, it seems to trigger an infinite recursion
+ if (isa<UnaryExprOrTypeTraitExpr>(expr)) {
+ return boost::optional<APSInt>();
+ }
+ APSInt x1;
+ if (expr->EvaluateAsInt(x1, compiler.getASTContext()))
+ return x1;
+ return boost::optional<APSInt>();
+}
+
+// these will often evaluate to zero harmlessly
+bool ExpressionAlwaysZero::TraverseStaticAssertDecl( StaticAssertDecl * )
+{
+ return true;
+}
+
+loplugin::Plugin::Registration< ExpressionAlwaysZero > X("expressionalwayszero");
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */