bump product version to 5.0.4.1
[LibreOffice.git] / compilerplugins / clang / passstuffbyref.cxx
blob6d98dbf903419ed4b99e2fe0513222de44a9fe4d
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 */
10 #include <string>
11 #include <set>
13 #include "plugin.hxx"
15 // Find places where various things are passed by value.
16 // It's not very efficient, because we generally end up copying it twice - once into the parameter and
17 // again into the destination.
18 // They should rather be passed by reference.
20 // Generally recommending lambda capture by-ref rather than by-copy is even more
21 // problematic than with function parameters, as a lambda instance can easily
22 // outlive a referrenced variable. So once lambdas start to get used in more
23 // sophisticated ways than passing them into standard algorithms, this plugin's
24 // advice, at least for explicit captures, will need to be revisited.
26 namespace {
28 class PassStuffByRef:
29 public RecursiveASTVisitor<PassStuffByRef>, public loplugin::Plugin
31 public:
32 explicit PassStuffByRef(InstantiationData const & data): Plugin(data) {}
34 virtual void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
36 bool VisitFunctionDecl(const FunctionDecl * decl);
38 bool VisitLambdaExpr(const LambdaExpr * expr);
40 private:
41 bool isFat(QualType type, std::string * name);
44 bool PassStuffByRef::VisitFunctionDecl(const FunctionDecl * functionDecl) {
45 if (ignoreLocation(functionDecl)) {
46 return true;
48 // only warn on the definition/prototype of the function,
49 // not on the function implementation
50 if ((functionDecl->isThisDeclarationADefinition()
51 && functionDecl->getPreviousDecl() != nullptr)
52 || functionDecl->isDeleted())
54 return true;
56 // only consider base declarations, not overriden ones, or we warn on methods that
57 // are overriding stuff from external libraries
58 if (isa<CXXMethodDecl>(functionDecl)) {
59 CXXMethodDecl const * m = dyn_cast<CXXMethodDecl>(functionDecl);
60 if (m->size_overridden_methods() > 0)
61 return true;
63 unsigned n = functionDecl->getNumParams();
64 for (unsigned i = 0; i != n; ++i) {
65 const ParmVarDecl * pvDecl = functionDecl->getParamDecl(i);
66 std::string name;
67 if (isFat(pvDecl->getType(), &name)) {
68 report(
69 DiagnosticsEngine::Warning,
70 ("passing '%0' by value, rather pass by reference, e.g., '%0"
71 " const &'"),
72 pvDecl->getLocation())
73 << name << pvDecl->getSourceRange();
76 return true;
79 bool PassStuffByRef::VisitLambdaExpr(const LambdaExpr * expr) {
80 if (ignoreLocation(expr)) {
81 return true;
83 for (auto i(expr->capture_begin()); i != expr->capture_end(); ++i) {
84 if (i->getCaptureKind() == LambdaCaptureKind::LCK_ByCopy) {
85 std::string name;
86 if (isFat(i->getCapturedVar()->getType(), &name)) {
87 report(
88 DiagnosticsEngine::Warning,
89 ("%0 capture of '%1' variable by copy, rather use capture"
90 " by reference---UNLESS THE LAMBDA OUTLIVES THE VARIABLE"),
91 i->getLocation())
92 << (i->isImplicit() ? "implicit" : "explicit") << name
93 << expr->getSourceRange();
97 return true;
100 bool PassStuffByRef::isFat(QualType type, std::string * name) {
101 if (!type->isRecordType()) {
102 return false;
104 *name = type.getUnqualifiedType().getCanonicalType().getAsString();
105 if (*name == "class rtl::OUString" || *name == "class rtl::OString"
106 || name->find("class com::sun::star::uno::Sequence") == 0)
108 return true;
110 if (type->isIncompleteType()) {
111 return false;
113 Type const * t2 = type.getTypePtrOrNull();
114 return t2 != nullptr
115 && compiler.getASTContext().getTypeSizeInChars(t2).getQuantity() > 64;
118 loplugin::Plugin::Registration< PassStuffByRef > X("passstuffbyref");
122 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */