summaryrefslogtreecommitdiff
path: root/compilerplugins/clang/empty.cxx
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2019-01-16 10:45:54 +0100
committerStephan Bergmann <sbergman@redhat.com>2019-01-16 13:08:28 +0100
commit4828debf7b4fa19bc26e2a02e5606d2c07b4c5d2 (patch)
treeb93d14373ea652e634847d31cb73d70febd862be /compilerplugins/clang/empty.cxx
parenta0e326f5e109a1dc3402b4102ad730de6feeba96 (diff)
New loplugin:empty
Change-Id: I8729db064573ac21dfe6b203c5ae244d79ecc4fe Reviewed-on: https://gerrit.libreoffice.org/66430 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
Diffstat (limited to 'compilerplugins/clang/empty.cxx')
-rw-r--r--compilerplugins/clang/empty.cxx186
1 files changed, 186 insertions, 0 deletions
diff --git a/compilerplugins/clang/empty.cxx b/compilerplugins/clang/empty.cxx
new file mode 100644
index 000000000000..74cc7b06e176
--- /dev/null
+++ b/compilerplugins/clang/empty.cxx
@@ -0,0 +1,186 @@
+/* -*- 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 <cassert>
+
+#include "check.hxx"
+#include "plugin.hxx"
+
+// Warn about checks whether a container is empty done via an (expensive) call to obtain the
+// container's size. For now only handles cases involving strlen.
+
+namespace
+{
+BinaryOperatorKind revert(BinaryOperatorKind op)
+{
+ switch (op)
+ {
+ case BO_LT:
+ return BO_GE;
+ case BO_GT:
+ return BO_LE;
+ case BO_LE:
+ return BO_GT;
+ case BO_GE:
+ return BO_LT;
+ case BO_EQ:
+ case BO_NE:
+ return op;
+ default:
+ assert(false);
+ }
+}
+
+class Empty : public loplugin::FilteringPlugin<Empty>
+{
+public:
+ explicit Empty(loplugin::InstantiationData const& data)
+ : FilteringPlugin(data)
+ {
+ }
+
+ bool VisitBinLT(BinaryOperator const* expr)
+ {
+ visitComparison(expr);
+ return true;
+ }
+
+ bool VisitBinGT(BinaryOperator const* expr)
+ {
+ visitComparison(expr);
+ return true;
+ }
+
+ bool VisitBinLE(BinaryOperator const* expr)
+ {
+ visitComparison(expr);
+ return true;
+ }
+
+ bool VisitBinGE(BinaryOperator const* expr)
+ {
+ visitComparison(expr);
+ return true;
+ }
+
+ bool VisitBinEQ(BinaryOperator const* expr)
+ {
+ visitComparison(expr);
+ return true;
+ }
+
+ bool VisitBinNE(BinaryOperator const* expr)
+ {
+ visitComparison(expr);
+ return true;
+ }
+
+private:
+ void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
+
+ void visitComparison(BinaryOperator const* expr, CallExpr const* lhs, Expr const* rhs,
+ BinaryOperatorKind op)
+ {
+ auto const fdecl = lhs->getDirectCallee();
+ if (fdecl == nullptr)
+ {
+ return;
+ }
+ loplugin::DeclCheck dc(fdecl);
+ if (!(dc.Function("strlen").StdNamespace() || dc.Function("strlen").GlobalNamespace()))
+ {
+ return;
+ }
+ APSInt val;
+ if (!rhs->isIntegerConstantExpr(val, compiler.getASTContext()))
+ {
+ return;
+ }
+ switch (op)
+ {
+ case BO_LT:
+ if (val.getExtValue() == 1)
+ {
+ report(DiagnosticsEngine::Warning,
+ "replace a comparison like 'strlen(e) < 1' with 'e[0] == '\\0''",
+ expr->getExprLoc())
+ << expr->getSourceRange();
+ }
+ break;
+ case BO_GT:
+ if (val.getExtValue() == 0)
+ {
+ report(DiagnosticsEngine::Warning,
+ "replace a comparison like 'strlen(e) > 0' with 'e[0] != '\\0''",
+ expr->getExprLoc())
+ << expr->getSourceRange();
+ }
+ break;
+ case BO_LE:
+ if (val.getExtValue() == 0)
+ {
+ report(DiagnosticsEngine::Warning,
+ "replace a comparison like 'strlen(e) <= 0' with 'e[0] == '\\0''",
+ expr->getExprLoc())
+ << expr->getSourceRange();
+ }
+ break;
+ case BO_GE:
+ if (val.getExtValue() == 1)
+ {
+ report(DiagnosticsEngine::Warning,
+ "replace a comparison like 'strlen(e) >= 1' with 'e[0] != '\\0''",
+ expr->getExprLoc())
+ << expr->getSourceRange();
+ }
+ break;
+ case BO_EQ:
+ if (val.getExtValue() == 0)
+ {
+ report(DiagnosticsEngine::Warning,
+ "replace a comparison like 'strlen(e) == 0' with 'e[0] == '\\0''",
+ expr->getExprLoc())
+ << expr->getSourceRange();
+ }
+ break;
+ case BO_NE:
+ if (val.getExtValue() == 0)
+ {
+ report(DiagnosticsEngine::Warning,
+ "replace a comparison like 'strlen(e) != 0' with 'e[0] != '\\0''",
+ expr->getExprLoc())
+ << expr->getSourceRange();
+ }
+ break;
+ default:
+ assert(false);
+ }
+ }
+
+ void visitComparison(BinaryOperator const* expr)
+ {
+ if (ignoreLocation(expr))
+ {
+ return;
+ }
+ if (auto const call = dyn_cast<CallExpr>(expr->getLHS()->IgnoreParenImpCasts()))
+ {
+ visitComparison(expr, call, expr->getRHS(), expr->getOpcode());
+ }
+ else if (auto const call = dyn_cast<CallExpr>(expr->getRHS()->IgnoreParenImpCasts()))
+ {
+ visitComparison(expr, call, expr->getLHS(), revert(expr->getOpcode()));
+ }
+ }
+};
+
+loplugin::Plugin::Registration<Empty> X("empty");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */