update credits
[LibreOffice.git] / compilerplugins / clang / moveparam.cxx
blobdc7a84b4d64dc18161e88cc3bcb4c36fd72ba922
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 * Based on LLVM/Clang.
7 * This file is distributed under the University of Illinois Open Source
8 * License. See LICENSE.TXT for details.
12 #include <cassert>
13 #include <string>
14 #include <iostream>
15 #include <fstream>
16 #include <set>
17 #include <unordered_set>
18 #include "config_clang.h"
19 #include "plugin.hxx"
20 #include "check.hxx"
23 Look for places where we can pass by move && param and so avoid
24 unnecessary copies.
25 Empirically, when we are passing a container type to a function, 80% of the time,
26 we are passing a local temporary that can be moved instead of being copied.
28 TODO this could be a lot smarter, with ignoring false+ e.g. when copying a param
29 in a loop
32 namespace
34 class MoveParam : public loplugin::FilteringPlugin<MoveParam>
36 public:
37 explicit MoveParam(loplugin::InstantiationData const& data)
38 : FilteringPlugin(data)
42 virtual bool preRun() override
44 std::string fn(handler.getMainFileName());
45 loplugin::normalizeDotDotInFilePath(fn);
46 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/filter/source/msfilter/escherex.cxx"))
47 return false;
48 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sc/source/ui/docshell/docfunc.cxx"))
49 return false;
50 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sc/source/ui/view/viewfunc.cxx"))
51 return false;
52 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/basegfx/source/polygon/b2dpolygontools.cxx"))
53 return false;
54 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/basegfx/source/polygon/b3dpolygontools.cxx"))
55 return false;
56 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/connectivity/source/commontools/dbtools.cxx"))
57 return false;
58 return true;
61 virtual void run() override
63 if (preRun())
64 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
67 bool VisitCXXOperatorCallExpr(const CXXOperatorCallExpr*);
68 bool VisitCXXConstructExpr(const CXXConstructExpr*);
70 bool isContainerType(QualType qt);
73 bool MoveParam::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr* callExpr)
75 if (ignoreLocation(callExpr))
76 return true;
77 if (!callExpr->isAssignmentOp())
78 return true;
79 auto qt = callExpr->getType();
80 if (!isContainerType(qt))
81 return true;
82 auto declRef = dyn_cast<DeclRefExpr>(callExpr->getArg(1)->IgnoreParenImpCasts());
83 if (!declRef)
84 return true;
86 auto parmVarDecl = dyn_cast_or_null<ParmVarDecl>(declRef->getDecl());
87 if (!parmVarDecl)
88 return true;
90 if (!loplugin::TypeCheck(parmVarDecl->getType()).LvalueReference().Const())
91 return true;
93 StringRef aFileName = getFilenameOfLocation(
94 compiler.getSourceManager().getSpellingLoc(parmVarDecl->getBeginLoc()));
95 if (loplugin::hasPathnamePrefix(aFileName,
96 SRCDIR "/svx/source/sidebar/line/LineWidthValueSet.cxx"))
97 return true;
99 report(DiagnosticsEngine::Warning, "rather use move && param1", callExpr->getBeginLoc());
101 return true;
104 bool MoveParam::VisitCXXConstructExpr(const CXXConstructExpr* constructExpr)
106 if (ignoreLocation(constructExpr->getBeginLoc()))
107 return true;
108 if (isInUnoIncludeFile(constructExpr->getBeginLoc()))
109 return true;
111 auto qt = constructExpr->getType();
112 if (!isContainerType(qt))
113 return true;
115 if (constructExpr->getNumArgs() != 1)
116 return true;
118 auto declRef = dyn_cast<DeclRefExpr>(constructExpr->getArg(0)->IgnoreParenImpCasts());
119 if (!declRef)
120 return true;
122 auto parmVarDecl = dyn_cast_or_null<ParmVarDecl>(declRef->getDecl());
123 if (!parmVarDecl)
124 return true;
126 if (!loplugin::TypeCheck(parmVarDecl->getType()).LvalueReference().Const())
127 return true;
129 StringRef aFileName = getFilenameOfLocation(
130 compiler.getSourceManager().getSpellingLoc(parmVarDecl->getBeginLoc()));
131 if (loplugin::hasPathnamePrefix(aFileName, SRCDIR
132 "/include/drawinglayer/primitive2d/Primitive2DContainer.hxx"))
133 return true;
134 if (loplugin::hasPathnamePrefix(aFileName,
135 SRCDIR "/include/drawinglayer/primitive3d/baseprimitive3d.hxx"))
136 return true;
137 if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/svx/source/svdraw/svdmrkv.cxx"))
138 return true;
139 if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/include/editeng/swafopt.hxx"))
140 return true;
141 if (loplugin::hasPathnamePrefix(
142 aFileName, SRCDIR "/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx"))
143 return true;
144 if (loplugin::hasPathnamePrefix(aFileName,
145 SRCDIR "/chart2/source/tools/InternalDataProvider.cxx"))
146 return true;
147 if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/sc/source/core/data/attrib.cxx"))
148 return true;
149 if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/sw/source/core/doc/docfmt.cxx"))
150 return true;
151 if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/configmgr/source/modifications.cxx"))
152 return true;
153 if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/svx/source/dialog/srchdlg.cxx"))
154 return true;
155 if (loplugin::hasPathnamePrefix(aFileName,
156 SRCDIR "/stoc/source/servicemanager/servicemanager.cxx"))
157 return true;
159 report(DiagnosticsEngine::Warning, "rather use move && param3", constructExpr->getBeginLoc());
161 return true;
164 bool MoveParam::isContainerType(QualType qt)
166 auto tc = loplugin::TypeCheck(qt);
167 return tc.Class("Primitive2DContainer")
168 .Namespace("primitive2d")
169 .Namespace("drawinglayer")
170 .GlobalNamespace()
171 || tc.ClassOrStruct("sorted_vector").Namespace("o3tl").GlobalNamespace()
172 || tc.ClassOrStruct("array").StdNamespace() || tc.ClassOrStruct("vector").StdNamespace()
173 || tc.ClassOrStruct("deque").StdNamespace()
174 || tc.ClassOrStruct("forward_list").StdNamespace()
175 || tc.ClassOrStruct("list").StdNamespace() || tc.ClassOrStruct("set").StdNamespace()
176 || tc.ClassOrStruct("map").StdNamespace() || tc.ClassOrStruct("multiset").StdNamespace()
177 || tc.ClassOrStruct("multimap").StdNamespace()
178 || tc.ClassOrStruct("unordered_set").StdNamespace()
179 || tc.ClassOrStruct("unordered_map").StdNamespace()
180 || tc.ClassOrStruct("unordered_multiset").StdNamespace()
181 || tc.ClassOrStruct("unordered_multimap").StdNamespace()
182 || tc.ClassOrStruct("stack").StdNamespace() || tc.ClassOrStruct("queue").StdNamespace()
183 || tc.ClassOrStruct("priority_queue").StdNamespace();
186 /** off by default because it needs some hand-holding */
187 loplugin::Plugin::Registration<MoveParam> moveparam("moveparam", false);
189 } // namespace
191 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */