bump product version to 6.3.0.0.beta1
[LibreOffice.git] / compilerplugins / clang / empty.cxx
blob5cf5a023e54c1f999c1977fb5191422e5c4c6e98
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 revert(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 assert(false);
42 class Empty : public loplugin::FilteringPlugin<Empty>
44 public:
45 explicit Empty(loplugin::InstantiationData const& data)
46 : FilteringPlugin(data)
50 bool VisitBinLT(BinaryOperator const* expr)
52 visitComparison(expr);
53 return true;
56 bool VisitBinGT(BinaryOperator const* expr)
58 visitComparison(expr);
59 return true;
62 bool VisitBinLE(BinaryOperator const* expr)
64 visitComparison(expr);
65 return true;
68 bool VisitBinGE(BinaryOperator const* expr)
70 visitComparison(expr);
71 return true;
74 bool VisitBinEQ(BinaryOperator const* expr)
76 visitComparison(expr);
77 return true;
80 bool VisitBinNE(BinaryOperator const* expr)
82 visitComparison(expr);
83 return true;
86 private:
87 void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
89 void visitComparison(BinaryOperator const* expr, CallExpr const* lhs, Expr const* rhs,
90 BinaryOperatorKind op)
92 auto const fdecl = lhs->getDirectCallee();
93 if (fdecl == nullptr)
95 return;
97 loplugin::DeclCheck dc(fdecl);
98 if (!(dc.Function("strlen").StdNamespace() || dc.Function("strlen").GlobalNamespace()))
100 return;
102 APSInt val;
103 if (rhs->isValueDependent() || !rhs->isIntegerConstantExpr(val, compiler.getASTContext()))
105 return;
107 switch (op)
109 case BO_LT:
110 if (val.getExtValue() == 1)
112 report(DiagnosticsEngine::Warning,
113 "replace a comparison like 'strlen(e) < 1' with 'e[0] == '\\0''",
114 expr->getExprLoc())
115 << expr->getSourceRange();
117 break;
118 case BO_GT:
119 if (val.getExtValue() == 0)
121 report(DiagnosticsEngine::Warning,
122 "replace a comparison like 'strlen(e) > 0' with 'e[0] != '\\0''",
123 expr->getExprLoc())
124 << expr->getSourceRange();
126 break;
127 case BO_LE:
128 if (val.getExtValue() == 0)
130 report(DiagnosticsEngine::Warning,
131 "replace a comparison like 'strlen(e) <= 0' with 'e[0] == '\\0''",
132 expr->getExprLoc())
133 << expr->getSourceRange();
135 break;
136 case BO_GE:
137 if (val.getExtValue() == 1)
139 report(DiagnosticsEngine::Warning,
140 "replace a comparison like 'strlen(e) >= 1' with 'e[0] != '\\0''",
141 expr->getExprLoc())
142 << expr->getSourceRange();
144 break;
145 case BO_EQ:
146 if (val.getExtValue() == 0)
148 report(DiagnosticsEngine::Warning,
149 "replace a comparison like 'strlen(e) == 0' with 'e[0] == '\\0''",
150 expr->getExprLoc())
151 << expr->getSourceRange();
153 break;
154 case BO_NE:
155 if (val.getExtValue() == 0)
157 report(DiagnosticsEngine::Warning,
158 "replace a comparison like 'strlen(e) != 0' with 'e[0] != '\\0''",
159 expr->getExprLoc())
160 << expr->getSourceRange();
162 break;
163 default:
164 assert(false);
168 void visitComparison(BinaryOperator const* expr)
170 if (ignoreLocation(expr))
172 return;
174 if (auto const call = dyn_cast<CallExpr>(expr->getLHS()->IgnoreParenImpCasts()))
176 visitComparison(expr, call, expr->getRHS(), expr->getOpcode());
178 else if (auto const call = dyn_cast<CallExpr>(expr->getRHS()->IgnoreParenImpCasts()))
180 visitComparison(expr, call, expr->getLHS(), revert(expr->getOpcode()));
185 loplugin::Plugin::Registration<Empty> emptyRegistration("empty");
188 #endif // LO_CLANG_SHARED_PLUGINS
190 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */