1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
9 #ifndef LO_CLANG_SHARED_PLUGINS
14 #include <unordered_map>
15 #include <unordered_set>
19 #include "clang/AST/CXXInheritance.h"
20 #include "clang/AST/StmtVisitor.h"
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
29 TODO handle OUStringBuffer/OStringBuffer similarly
34 class StringView
: public loplugin::FilteringPlugin
<StringView
>
37 explicit StringView(loplugin::InstantiationData
const& data
)
38 : FilteringPlugin(data
)
42 bool preRun() override
{ return true; }
44 virtual void run() override
48 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
51 bool VisitFunctionDecl(FunctionDecl
const*);
52 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr
const*);
53 bool VisitImplicitCastExpr(ImplicitCastExpr
const*);
56 void handleCXXConstructExpr(CXXConstructExpr
const* expr
);
57 void handleCXXMemberCallExpr(CXXMemberCallExpr
const* expr
);
60 bool StringView::VisitCXXOperatorCallExpr(CXXOperatorCallExpr
const* cxxOperatorCallExpr
)
62 if (ignoreLocation(cxxOperatorCallExpr
))
65 auto check
= [&](const Expr
* expr
) -> void {
66 auto memberCallExpr
= dyn_cast
<CXXMemberCallExpr
>(compat::IgnoreImplicit(expr
));
69 auto methodDecl
= memberCallExpr
->getMethodDecl();
70 if (!methodDecl
->getIdentifier() || methodDecl
->getName() != "copy")
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));
94 bool StringView::VisitFunctionDecl(FunctionDecl
const* functionDecl
)
96 if (ignoreLocation(functionDecl
))
99 // if (functionDecl->getIdentifier() && functionDecl->getName() == "f1")
100 // functionDecl->dump();
104 bool StringView::VisitImplicitCastExpr(ImplicitCastExpr
const* expr
)
106 if (ignoreLocation(expr
))
110 if (!loplugin::TypeCheck(expr
->getType()).ClassOrStruct("basic_string_view").StdNamespace())
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()))
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
);
132 void StringView::handleCXXConstructExpr(CXXConstructExpr
const* expr
)
134 if (expr
->getNumArgs() != 0)
138 report(DiagnosticsEngine::Warning
,
139 "instead of an empty %0, pass an empty '%select{std::string_view|std::u16string_view}1'",
142 << (loplugin::TypeCheck(expr
->getType()).Class("OString").Namespace("rtl").GlobalNamespace()
145 << expr
->getSourceRange();
148 void StringView::handleCXXMemberCallExpr(CXXMemberCallExpr
const* expr
)
150 auto const dc
= loplugin::DeclCheck(expr
->getMethodDecl()).Function("copy");
155 if (!(dc
.Class("OString").Namespace("rtl").GlobalNamespace()
156 || dc
.Class("OUString").Namespace("rtl").GlobalNamespace()))
160 report(DiagnosticsEngine::Warning
, "rather than copy, pass with a view using subView()",
162 << expr
->getSourceRange();
165 loplugin::Plugin::Registration
<StringView
> stringview("stringview");
168 #endif // LO_CLANG_SHARED_PLUGINS
170 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */