summaryrefslogtreecommitdiff
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
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>
-rw-r--r--compilerplugins/clang/expressionalwayszero.cxx123
-rw-r--r--compilerplugins/clang/test/expressionalwayszero.cxx31
-rw-r--r--solenv/CompilerTest_compilerplugins_clang.mk1
-rw-r--r--sw/source/filter/xml/xmlexpit.cxx4
4 files changed, 156 insertions, 3 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: */
diff --git a/compilerplugins/clang/test/expressionalwayszero.cxx b/compilerplugins/clang/test/expressionalwayszero.cxx
new file mode 100644
index 000000000000..06bd80a2d90a
--- /dev/null
+++ b/compilerplugins/clang/test/expressionalwayszero.cxx
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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 <o3tl/typed_flags_set.hxx>
+
+constexpr auto ONE = 1;
+constexpr auto TWO = 2;
+
+enum class Enum1 {
+ ONE = 1,
+ TWO = 2,
+};
+namespace o3tl {
+ template<> struct typed_flags<Enum1> : is_typed_flags<Enum1, 0x3> {};
+}
+
+
+int main()
+{
+ auto v1 = ONE & TWO; // expected-error {{expression always evaluates to zero, lhs=1 rhs=2 [loplugin:expressionalwayszero]}}
+ (void)v1;
+ auto v2 = Enum1::ONE & Enum1::TWO; // expected-error {{expression always evaluates to zero, lhs=1 rhs=2 [loplugin:expressionalwayszero]}}
+ (void)v2;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/solenv/CompilerTest_compilerplugins_clang.mk b/solenv/CompilerTest_compilerplugins_clang.mk
index 1c44878f5b53..aec4fc09aecc 100644
--- a/solenv/CompilerTest_compilerplugins_clang.mk
+++ b/solenv/CompilerTest_compilerplugins_clang.mk
@@ -17,6 +17,7 @@ $(eval $(call gb_CompilerTest_add_exception_objects,compilerplugins_clang, \
compilerplugins/clang/test/datamembershadow \
compilerplugins/clang/test/droplong \
compilerplugins/clang/test/externvar \
+ compilerplugins/clang/test/expressionalwayszero \
compilerplugins/clang/test/finalprotected \
compilerplugins/clang/test/loopvartoosmall \
compilerplugins/clang/test/oncevar \
diff --git a/sw/source/filter/xml/xmlexpit.cxx b/sw/source/filter/xml/xmlexpit.cxx
index 541b31826414..2657e61e1e90 100644
--- a/sw/source/filter/xml/xmlexpit.cxx
+++ b/sw/source/filter/xml/xmlexpit.cxx
@@ -297,9 +297,7 @@ void SvXMLExportItemMapper::exportXML( SvXMLExport& rExport,
exportXML( rExport, rExport.GetAttrList(), rSet, rUnitConverter,
rExport.GetNamespaceMap(), nFlags, &aIndexArray );
- if( rExport.GetAttrList().getLength() > 0 ||
- (nFlags & SvXmlExportFlags::EMPTY) ||
- !aIndexArray.empty() )
+ if( rExport.GetAttrList().getLength() > 0 || !aIndexArray.empty() )
{
if( (nFlags & SvXmlExportFlags::IGN_WS) )
{