[Libreoffice-commits] core.git: compilerplugins/clang solenv/CompilerTest_compilerplugins_clang.mk sw/source

Noel Grandin noel.grandin at collabora.co.uk
Fri Aug 18 12:20:59 UTC 2017


 compilerplugins/clang/expressionalwayszero.cxx      |  123 ++++++++++++++++++++
 compilerplugins/clang/test/expressionalwayszero.cxx |   31 +++++
 solenv/CompilerTest_compilerplugins_clang.mk        |    1 
 sw/source/filter/xml/xmlexpit.cxx                   |    4 
 4 files changed, 156 insertions(+), 3 deletions(-)

New commits:
commit 256c28ae3354d49d0e2ebdf11ef2a64da7954f68
Author: Noel Grandin <noel.grandin at collabora.co.uk>
Date:   Fri Aug 18 13:10:01 2017 +0200

    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 at libreoffice.org>
    Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>

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) )
         {


More information about the Libreoffice-commits mailing list