diff options
author | Noel Grandin <noel.grandin@collabora.co.uk> | 2017-08-18 13:10:01 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2017-08-18 14:19:20 +0200 |
commit | 256c28ae3354d49d0e2ebdf11ef2a64da7954f68 (patch) | |
tree | cd12a01a9a6fa72f874ffe053d441cb0e2e4fa91 | |
parent | 6e1d959a2e890004be5be259610033210d18f7cd (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.cxx | 123 | ||||
-rw-r--r-- | compilerplugins/clang/test/expressionalwayszero.cxx | 31 | ||||
-rw-r--r-- | solenv/CompilerTest_compilerplugins_clang.mk | 1 | ||||
-rw-r--r-- | sw/source/filter/xml/xmlexpit.cxx | 4 |
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) ) { |