update credits
[LibreOffice.git] / compilerplugins / clang / empty.cxx
blobd5129d29dd3cfbb4a0c65e2b4888e9d0f0c3efed
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #ifndef LO_CLANG_SHARED_PLUGINS
12 #include <cassert>
14 #include "check.hxx"
15 #include "plugin.hxx"
17 // Warn about checks whether a container is empty done via an (expensive) call to obtain the
18 // container's size. For now only handles cases involving strlen.
20 namespace
22 BinaryOperatorKind reverse(BinaryOperatorKind op)
24 switch (op)
26 case BO_LT:
27 return BO_GE;
28 case BO_GT:
29 return BO_LE;
30 case BO_LE:
31 return BO_GT;
32 case BO_GE:
33 return BO_LT;
34 case BO_EQ:
35 case BO_NE:
36 return op;
37 default:
38 abort();
42 class Empty : public loplugin::FilteringPlugin<Empty>
44 public:
45 explicit Empty(loplugin::InstantiationData const& data)
46 : FilteringPlugin(data)
50 bool VisitBinaryOperator(BinaryOperator const* expr)
52 if (expr->isRelationalOp() || expr->isEqualityOp())
54 visitComparison(expr);
56 return true;
59 private:
60 void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
62 void visitComparison(BinaryOperator const* expr, CallExpr const* lhs, Expr const* rhs,
63 BinaryOperatorKind op)
65 auto const fdecl = lhs->getDirectCallee();
66 if (fdecl == nullptr)
68 return;
70 loplugin::DeclCheck dc(fdecl);
71 if (!(dc.Function("strlen").StdNamespace() || dc.Function("strlen").GlobalNamespace()))
73 return;
75 if (rhs->isValueDependent())
77 return;
79 auto const val = rhs->getIntegerConstantExpr(compiler.getASTContext());
80 if (!val)
82 return;
84 switch (op)
86 case BO_LT:
87 if (val->getExtValue() == 1)
89 report(DiagnosticsEngine::Warning,
90 "replace a comparison like 'strlen(e) < 1' with 'e[0] == '\\0''",
91 expr->getExprLoc())
92 << expr->getSourceRange();
94 break;
95 case BO_GT:
96 if (val->getExtValue() == 0)
98 report(DiagnosticsEngine::Warning,
99 "replace a comparison like 'strlen(e) > 0' with 'e[0] != '\\0''",
100 expr->getExprLoc())
101 << expr->getSourceRange();
103 break;
104 case BO_LE:
105 if (val->getExtValue() == 0)
107 report(DiagnosticsEngine::Warning,
108 "replace a comparison like 'strlen(e) <= 0' with 'e[0] == '\\0''",
109 expr->getExprLoc())
110 << expr->getSourceRange();
112 break;
113 case BO_GE:
114 if (val->getExtValue() == 1)
116 report(DiagnosticsEngine::Warning,
117 "replace a comparison like 'strlen(e) >= 1' with 'e[0] != '\\0''",
118 expr->getExprLoc())
119 << expr->getSourceRange();
121 break;
122 case BO_EQ:
123 if (val->getExtValue() == 0)
125 report(DiagnosticsEngine::Warning,
126 "replace a comparison like 'strlen(e) == 0' with 'e[0] == '\\0''",
127 expr->getExprLoc())
128 << expr->getSourceRange();
130 break;
131 case BO_NE:
132 if (val->getExtValue() == 0)
134 report(DiagnosticsEngine::Warning,
135 "replace a comparison like 'strlen(e) != 0' with 'e[0] != '\\0''",
136 expr->getExprLoc())
137 << expr->getSourceRange();
139 break;
140 default:
141 assert(false);
145 void visitComparison(BinaryOperator const* expr)
147 if (ignoreLocation(expr))
149 return;
151 if (auto const call = dyn_cast<CallExpr>(expr->getLHS()->IgnoreParenImpCasts()))
153 visitComparison(expr, call, expr->getRHS(), expr->getOpcode());
155 else if (auto const call = dyn_cast<CallExpr>(expr->getRHS()->IgnoreParenImpCasts()))
157 visitComparison(expr, call, expr->getLHS(), reverse(expr->getOpcode()));
162 loplugin::Plugin::Registration<Empty> emptyRegistration("empty");
165 #endif // LO_CLANG_SHARED_PLUGINS
167 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */