LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / compilerplugins / clang / empty.cxx
blobc3cc86520f47ee7887c07a587d926f9cd9f39954
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 "compat.hxx"
16 #include "plugin.hxx"
18 // Warn about checks whether a container is empty done via an (expensive) call to obtain the
19 // container's size. For now only handles cases involving strlen.
21 namespace
23 BinaryOperatorKind reverse(BinaryOperatorKind op)
25 switch (op)
27 case BO_LT:
28 return BO_GE;
29 case BO_GT:
30 return BO_LE;
31 case BO_LE:
32 return BO_GT;
33 case BO_GE:
34 return BO_LT;
35 case BO_EQ:
36 case BO_NE:
37 return op;
38 default:
39 abort();
43 class Empty : public loplugin::FilteringPlugin<Empty>
45 public:
46 explicit Empty(loplugin::InstantiationData const& data)
47 : FilteringPlugin(data)
51 bool VisitBinaryOperator(BinaryOperator const* expr)
53 if (expr->isRelationalOp() || expr->isEqualityOp())
55 visitComparison(expr);
57 return true;
60 private:
61 void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
63 void visitComparison(BinaryOperator const* expr, CallExpr const* lhs, Expr const* rhs,
64 BinaryOperatorKind op)
66 auto const fdecl = lhs->getDirectCallee();
67 if (fdecl == nullptr)
69 return;
71 loplugin::DeclCheck dc(fdecl);
72 if (!(dc.Function("strlen").StdNamespace() || dc.Function("strlen").GlobalNamespace()))
74 return;
76 if (rhs->isValueDependent())
78 return;
80 auto const val = compat::getIntegerConstantExpr(rhs, compiler.getASTContext());
81 if (!val)
83 return;
85 switch (op)
87 case BO_LT:
88 if (val->getExtValue() == 1)
90 report(DiagnosticsEngine::Warning,
91 "replace a comparison like 'strlen(e) < 1' with 'e[0] == '\\0''",
92 expr->getExprLoc())
93 << expr->getSourceRange();
95 break;
96 case BO_GT:
97 if (val->getExtValue() == 0)
99 report(DiagnosticsEngine::Warning,
100 "replace a comparison like 'strlen(e) > 0' with 'e[0] != '\\0''",
101 expr->getExprLoc())
102 << expr->getSourceRange();
104 break;
105 case BO_LE:
106 if (val->getExtValue() == 0)
108 report(DiagnosticsEngine::Warning,
109 "replace a comparison like 'strlen(e) <= 0' with 'e[0] == '\\0''",
110 expr->getExprLoc())
111 << expr->getSourceRange();
113 break;
114 case BO_GE:
115 if (val->getExtValue() == 1)
117 report(DiagnosticsEngine::Warning,
118 "replace a comparison like 'strlen(e) >= 1' with 'e[0] != '\\0''",
119 expr->getExprLoc())
120 << expr->getSourceRange();
122 break;
123 case BO_EQ:
124 if (val->getExtValue() == 0)
126 report(DiagnosticsEngine::Warning,
127 "replace a comparison like 'strlen(e) == 0' with 'e[0] == '\\0''",
128 expr->getExprLoc())
129 << expr->getSourceRange();
131 break;
132 case BO_NE:
133 if (val->getExtValue() == 0)
135 report(DiagnosticsEngine::Warning,
136 "replace a comparison like 'strlen(e) != 0' with 'e[0] != '\\0''",
137 expr->getExprLoc())
138 << expr->getSourceRange();
140 break;
141 default:
142 assert(false);
146 void visitComparison(BinaryOperator const* expr)
148 if (ignoreLocation(expr))
150 return;
152 if (auto const call = dyn_cast<CallExpr>(expr->getLHS()->IgnoreParenImpCasts()))
154 visitComparison(expr, call, expr->getRHS(), expr->getOpcode());
156 else if (auto const call = dyn_cast<CallExpr>(expr->getRHS()->IgnoreParenImpCasts()))
158 visitComparison(expr, call, expr->getLHS(), reverse(expr->getOpcode()));
163 loplugin::Plugin::Registration<Empty> emptyRegistration("empty");
166 #endif // LO_CLANG_SHARED_PLUGINS
168 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */