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 /compilerplugins/clang/expressionalwayszero.cxx | |
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>
Diffstat (limited to 'compilerplugins/clang/expressionalwayszero.cxx')
-rw-r--r-- | compilerplugins/clang/expressionalwayszero.cxx | 123 |
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: */ |