nss: upgrade to release 3.73
[LibreOffice.git] / compilerplugins / clang / stringview.cxx
blob06b2fb8fdf029eba23f47805712db1906e86e4d3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 */
9 #ifndef LO_CLANG_SHARED_PLUGINS
11 #include <cassert>
12 #include <string>
13 #include <iostream>
14 #include <unordered_map>
15 #include <unordered_set>
17 #include "plugin.hxx"
18 #include "check.hxx"
19 #include "clang/AST/CXXInheritance.h"
20 #include "clang/AST/StmtVisitor.h"
22 /**
23 Look for places where we are making a substring copy of an OUString, and then passing it to a
24 function that takes a u16string_view, in which case it is more efficient to pass a view
25 of the OUString, rather than making a copy.
27 TODO currently does not check if there is some other visible overload of the callee, that can take
28 a string_view.
29 TODO handle OUStringBuffer/OStringBuffer similarly
32 namespace
34 class StringView : public loplugin::FilteringPlugin<StringView>
36 public:
37 explicit StringView(loplugin::InstantiationData const& data)
38 : FilteringPlugin(data)
42 bool preRun() override { return true; }
44 virtual void run() override
46 if (!preRun())
47 return;
48 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
51 bool VisitFunctionDecl(FunctionDecl const*);
52 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr const*);
53 bool VisitImplicitCastExpr(ImplicitCastExpr const*);
55 private:
56 void handleCXXConstructExpr(CXXConstructExpr const* expr);
57 void handleCXXMemberCallExpr(CXXMemberCallExpr const* expr);
60 bool StringView::VisitCXXOperatorCallExpr(CXXOperatorCallExpr const* cxxOperatorCallExpr)
62 if (ignoreLocation(cxxOperatorCallExpr))
63 return true;
65 auto check = [&](const Expr* expr) -> void {
66 auto memberCallExpr = dyn_cast<CXXMemberCallExpr>(compat::IgnoreImplicit(expr));
67 if (!memberCallExpr)
68 return;
69 auto methodDecl = memberCallExpr->getMethodDecl();
70 if (!methodDecl->getIdentifier() || methodDecl->getName() != "copy")
71 return;
72 report(DiagnosticsEngine::Warning, "rather than copy, pass with a view using subView()",
73 compat::getBeginLoc(expr))
74 << expr->getSourceRange();
76 auto op = cxxOperatorCallExpr->getOperator();
77 if (op == OO_Plus && cxxOperatorCallExpr->getNumArgs() == 2)
79 check(cxxOperatorCallExpr->getArg(0));
80 check(cxxOperatorCallExpr->getArg(1));
82 if (compat::isComparisonOp(cxxOperatorCallExpr))
84 check(cxxOperatorCallExpr->getArg(0));
85 check(cxxOperatorCallExpr->getArg(1));
87 else if (op == OO_PlusEqual)
88 check(cxxOperatorCallExpr->getArg(1));
89 else if (op == OO_Subscript)
90 check(cxxOperatorCallExpr->getArg(0));
91 return true;
94 bool StringView::VisitFunctionDecl(FunctionDecl const* functionDecl)
96 if (ignoreLocation(functionDecl))
97 return true;
98 // debugging
99 // if (functionDecl->getIdentifier() && functionDecl->getName() == "f1")
100 // functionDecl->dump();
101 return true;
104 bool StringView::VisitImplicitCastExpr(ImplicitCastExpr const* expr)
106 if (ignoreLocation(expr))
108 return true;
110 if (!loplugin::TypeCheck(expr->getType()).ClassOrStruct("basic_string_view").StdNamespace())
112 return true;
114 auto const e = expr->getSubExprAsWritten()->IgnoreParens();
115 auto const tc = loplugin::TypeCheck(e->getType());
116 if (!(tc.Class("OString").Namespace("rtl").GlobalNamespace()
117 || tc.Class("OUString").Namespace("rtl").GlobalNamespace()))
119 return true;
121 if (auto const e1 = dyn_cast<CXXConstructExpr>(e))
123 handleCXXConstructExpr(e1);
125 else if (auto const e2 = dyn_cast<CXXMemberCallExpr>(e))
127 handleCXXMemberCallExpr(e2);
129 return true;
132 void StringView::handleCXXConstructExpr(CXXConstructExpr const* expr)
134 if (expr->getNumArgs() != 0)
136 return;
138 report(DiagnosticsEngine::Warning,
139 "instead of an empty %0, pass an empty '%select{std::string_view|std::u16string_view}1'",
140 expr->getExprLoc())
141 << expr->getType()
142 << (loplugin::TypeCheck(expr->getType()).Class("OString").Namespace("rtl").GlobalNamespace()
144 : 1)
145 << expr->getSourceRange();
148 void StringView::handleCXXMemberCallExpr(CXXMemberCallExpr const* expr)
150 auto const dc = loplugin::DeclCheck(expr->getMethodDecl()).Function("copy");
151 if (!dc)
153 return;
155 if (!(dc.Class("OString").Namespace("rtl").GlobalNamespace()
156 || dc.Class("OUString").Namespace("rtl").GlobalNamespace()))
158 return;
160 report(DiagnosticsEngine::Warning, "rather than copy, pass with a view using subView()",
161 expr->getExprLoc())
162 << expr->getSourceRange();
165 loplugin::Plugin::Registration<StringView> stringview("stringview");
168 #endif // LO_CLANG_SHARED_PLUGINS
170 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */