Move setting of LD_LIBRARY_PATH closer to invocation of cppunittester
[LibreOffice.git] / compilerplugins / clang / store / stringloop.cxx
blob3bae1a225b1e62b9b3166fed7c1e6ca2350e0e06
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 "check.hxx"
11 #include "plugin.hxx"
12 #include "config_clang.h"
13 #include <vector>
15 /** Look for OUString/OString being appended to inside a loop, where OUStringBuffer/OStringBuffer would be a better idea
17 namespace
19 class StringLoop : public clang::RecursiveASTVisitor<StringLoop>, public loplugin::Plugin
21 public:
22 explicit StringLoop(loplugin::InstantiationData const& rData)
23 : Plugin(rData)
27 void run() override;
28 bool TraverseForStmt(ForStmt*);
29 bool TraverseCXXForRangeStmt(CXXForRangeStmt*);
30 bool TraverseDoStmt(DoStmt*);
31 bool TraverseWhileStmt(WhileStmt*);
32 bool VisitVarDecl(VarDecl const*);
33 bool VisitCallExpr(CallExpr const*);
35 private:
36 int m_insideLoop = 0;
37 using VarDeclList = std::vector<VarDecl const*>;
38 std::vector<VarDeclList> m_varsPerLoopLevel;
41 void StringLoop::run()
43 // Various places are not worth changing, the code becomes too awkward
44 // Just exclude stuff as I go
45 StringRef fn(handler.getMainFileName());
46 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/bridges/"))
47 return;
48 if (loplugin::isSamePathname(fn, SRCDIR "/cppuhelper/source/shlib.cxx"))
49 return;
50 if (loplugin::isSamePathname(fn, SRCDIR "/registry/source/regimpl.cxx"))
51 return;
52 if (loplugin::isSamePathname(fn, SRCDIR "/l10ntools/source/lngmerge.cxx"))
53 return;
54 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/tools/qa/"))
55 return;
56 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/jvmfwk/"))
57 return;
58 if (loplugin::isSamePathname(fn, SRCDIR "/svl/source/passwordcontainer/passwordcontainer.cxx"))
59 return;
60 if (loplugin::isSamePathname(fn, SRCDIR "/svl/source/numbers/zformat.cxx"))
61 return;
62 if (loplugin::isSamePathname(fn, SRCDIR "/svl/source/numbers/zforscan.cxx"))
63 return;
64 if (loplugin::isSamePathname(fn, SRCDIR "/vcl/source/control/combobox.cxx"))
65 return;
66 if (loplugin::isSamePathname(fn, SRCDIR "/vcl/source/gdi/pdfwriter_impl.cxx"))
67 return;
68 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/svtools/"))
69 return;
70 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/idl/"))
71 return;
72 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/framework/"))
73 return;
74 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/basic/"))
75 return;
76 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sfx2/"))
77 return;
78 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/avmedia/"))
79 return;
80 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/connectivity/"))
81 return;
82 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/editeng/"))
83 return;
84 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/svx/"))
85 return;
86 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/basctl/"))
87 return;
88 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/filter/"))
89 return;
90 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/chart2/"))
91 return;
92 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/cui/"))
93 return;
94 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/dbaccess/"))
95 return;
96 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/oox/"))
97 return;
98 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/writerfilter/"))
99 return;
100 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/desktop/"))
101 return;
102 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/extensions/"))
103 return;
104 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/dtrans/"))
105 return;
106 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/i18npool/"))
107 return;
108 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/embeddedobj/"))
109 return;
110 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sd/"))
111 return;
112 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/xmloff/"))
113 return;
114 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/xmlhelp/"))
115 return;
116 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/forms/"))
117 return;
118 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sc/source/core/tool/address.cxx"))
119 return;
120 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sc/source/core/tool/compiler.cxx"))
121 return;
122 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sc/source/ui/docshell/impex.cxx"))
123 return;
124 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sc/source/ui/miscdlgs/acredlin.cxx"))
125 return;
126 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sc/source/ui/pagedlg/areasdlg.cxx"))
127 return;
128 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sc/source/ui/view/gridwin2.cxx"))
129 return;
130 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sc/source/filter/html/htmlpars.cxx"))
131 return;
132 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/core/doc/doctxm.cxx"))
133 return;
134 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/core/edit/edattr.cxx"))
135 return;
136 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/core/layout/dbg_lay.cxx"))
137 return;
138 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/filter/ascii/ascatr.cxx"))
139 return;
140 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/filter/html/htmlforw.cxx"))
141 return;
142 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/core/unocore/unosect.cxx"))
143 return;
144 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/core/unocore/unochart.cxx"))
145 return;
146 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/core/unocore/unoobj.cxx"))
147 return;
148 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/filter/html/parcss1.cxx"))
149 return;
150 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/filter/html/svxcss1.cxx"))
151 return;
152 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/filter/html/swhtml.cxx"))
153 return;
154 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/uibase/utlui/gloslst.cxx"))
155 return;
156 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/uibase/utlui/content.cxx"))
157 return;
158 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/uibase/docvw/edtwin.cxx"))
159 return;
160 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/filter/ww8/ww8atr.cxx"))
161 return;
162 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/filter/ww8/ww8scan.cxx"))
163 return;
164 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/filter/ww8/ww8par5.cxx"))
165 return;
166 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/ui/fldui/fldfunc.cxx"))
167 return;
168 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/ui/misc/bookmark.cxx"))
169 return;
170 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/ui/dbui/mmlayoutpage.cxx"))
171 return;
172 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/ui/dbui/dbinsdlg.cxx"))
173 return;
174 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/ui/dbui/mmresultdialogs.cxx"))
175 return;
176 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sw/source/ui/index/cnttab.cxx"))
177 return;
178 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/ucb/source/ucp/file/bc.cxx"))
179 return;
181 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
184 bool StringLoop::TraverseForStmt(ForStmt* stmt)
186 ++m_insideLoop;
187 m_varsPerLoopLevel.push_back({});
188 auto const ret = RecursiveASTVisitor::TraverseForStmt(stmt);
189 m_varsPerLoopLevel.pop_back();
190 --m_insideLoop;
191 return ret;
194 bool StringLoop::TraverseCXXForRangeStmt(CXXForRangeStmt* stmt)
196 ++m_insideLoop;
197 m_varsPerLoopLevel.push_back({});
198 auto const ret = RecursiveASTVisitor::TraverseCXXForRangeStmt(stmt);
199 m_varsPerLoopLevel.pop_back();
200 --m_insideLoop;
201 return ret;
204 bool StringLoop::TraverseDoStmt(DoStmt* stmt)
206 ++m_insideLoop;
207 m_varsPerLoopLevel.push_back({});
208 auto const ret = RecursiveASTVisitor::TraverseDoStmt(stmt);
209 m_varsPerLoopLevel.pop_back();
210 --m_insideLoop;
211 return ret;
214 bool StringLoop::TraverseWhileStmt(WhileStmt* stmt)
216 ++m_insideLoop;
217 m_varsPerLoopLevel.push_back({});
218 auto const ret = RecursiveASTVisitor::TraverseWhileStmt(stmt);
219 m_varsPerLoopLevel.pop_back();
220 --m_insideLoop;
221 return ret;
224 bool StringLoop::VisitVarDecl(VarDecl const* varDecl)
226 if (ignoreLocation(varDecl))
227 return true;
228 if (!m_insideLoop)
229 return true;
230 m_varsPerLoopLevel.back().push_back(varDecl);
231 return true;
234 bool StringLoop::VisitCallExpr(CallExpr const* callExpr)
236 if (ignoreLocation(callExpr))
237 return true;
238 if (!m_insideLoop)
239 return true;
240 auto operatorCallExpr = dyn_cast<CXXOperatorCallExpr>(callExpr);
241 if (!operatorCallExpr)
242 return true;
243 if (operatorCallExpr->getOperator() != OO_PlusEqual)
244 return true;
246 if (auto memberExpr = dyn_cast<MemberExpr>(callExpr->getArg(0)))
248 auto tc = loplugin::TypeCheck(memberExpr->getType());
249 if (!tc.Class("OUString").Namespace("rtl").GlobalNamespace()
250 && !tc.Class("OString").Namespace("rtl").GlobalNamespace())
251 return true;
252 auto fieldDecl = dyn_cast<FieldDecl>(memberExpr->getMemberDecl());
253 if (isInUnoIncludeFile(
254 compiler.getSourceManager().getSpellingLoc(fieldDecl->getLocation())))
255 return true;
256 if (ignoreLocation(compiler.getSourceManager().getSpellingLoc(fieldDecl->getLocation())))
257 return true;
258 report(DiagnosticsEngine::Warning,
259 "appending to OUString in loop, rather use OUStringBuffer",
260 operatorCallExpr->getBeginLoc())
261 << operatorCallExpr->getSourceRange();
262 report(DiagnosticsEngine::Note, "field here", fieldDecl->getBeginLoc())
263 << fieldDecl->getSourceRange();
265 else if (auto declRefExpr = dyn_cast<DeclRefExpr>(callExpr->getArg(0)))
267 if (auto varDecl = dyn_cast<VarDecl>(declRefExpr->getDecl()))
269 auto tc = loplugin::TypeCheck(varDecl->getType());
270 if (!tc.Class("OUString").Namespace("rtl").GlobalNamespace()
271 && !tc.Class("OString").Namespace("rtl").GlobalNamespace())
272 return true;
273 // if the var is at the same block scope as the +=, not interesting
274 auto vars = m_varsPerLoopLevel.back();
275 if (std::find(vars.begin(), vars.end(), varDecl) != vars.end())
276 return true;
277 report(DiagnosticsEngine::Warning,
278 "appending to OUString in loop, rather use OUStringBuffer",
279 operatorCallExpr->getBeginLoc())
280 << operatorCallExpr->getSourceRange();
281 report(DiagnosticsEngine::Note, "var here", varDecl->getBeginLoc())
282 << varDecl->getSourceRange();
285 return true;
288 loplugin::Plugin::Registration<StringLoop> X("stringloop", false);
290 } // namespace
292 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */