Move setting of LD_LIBRARY_PATH closer to invocation of cppunittester
[LibreOffice.git] / compilerplugins / clang / store / checkunusedparams.cxx
blob33916b4810bbd1083e2d16a8e793697002f822fa
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 <cassert>
11 #include <string>
12 #include <set>
13 #include <iostream>
15 #include "config_clang.h"
17 #include "plugin.hxx"
19 /**
20 Find parameters that have no name, i.e. they are unused and we're worked around the "unused parameter" warning.
22 Most of these can be removed.
24 TODO look for places where we are working around the warning by doing
25 (void) param1;
27 namespace {
29 class CheckUnusedParams: public loplugin::FilteringPlugin<CheckUnusedParams> {
30 public:
31 explicit CheckUnusedParams(loplugin::InstantiationData const & data):
32 FilteringPlugin(data) {}
33 void run() override;
34 bool VisitFunctionDecl(FunctionDecl const *);
35 bool VisitUnaryOperator(UnaryOperator const *);
36 bool VisitInitListExpr(InitListExpr const *);
37 bool VisitCallExpr(CallExpr const *);
38 bool VisitBinaryOperator(BinaryOperator const *);
39 bool VisitCXXConstructExpr(CXXConstructExpr const *);
40 private:
41 void checkForFunctionDecl(Expr const *, bool bCheckOnly = false);
42 std::set<FunctionDecl const *> m_addressOfSet;
43 enum class PluginPhase { FindAddressOf, Warning };
44 PluginPhase m_phase;
47 void CheckUnusedParams::run()
49 StringRef fn(handler.getMainFileName());
50 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sal/"))
51 return;
52 // Taking pointer to function
53 if (loplugin::isSamePathname(fn, SRCDIR "/l10ntools/source/xmlparse.cxx"))
54 return;
55 // macro magic which declares something needed by an external library
56 if (loplugin::isSamePathname(fn, SRCDIR "/svl/source/misc/gridprinter.cxx"))
57 return;
59 // valid test/qa code
60 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/compilerplugins/clang/test/"))
61 return;
62 if (loplugin::isSamePathname(fn, SRCDIR "/cppu/qa/test_reference.cxx"))
63 return;
65 // leave this alone for now
66 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/libreofficekit/"))
67 return;
68 // this has a certain pattern to its code which appears to include lots of unused params
69 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/xmloff/"))
70 return;
71 // I believe someone is busy working on this chunk of code
72 if (loplugin::isSamePathname(fn, SRCDIR "/sc/source/ui/docshell/dataprovider.cxx"))
73 return;
74 // I think erack is working on stuff here
75 if (loplugin::isSamePathname(fn, SRCDIR "/sc/source/filter/excel/xiformula.cxx"))
76 return;
77 // lots of callbacks here
78 if (loplugin::isSamePathname(fn, SRCDIR "/sc/source/filter/lotus/op.cxx"))
79 return;
80 // template magic
81 if (loplugin::isSamePathname(fn, SRCDIR "/sc/source/filter/html/htmlpars.cxx"))
82 return;
84 m_phase = PluginPhase::FindAddressOf;
85 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
86 m_phase = PluginPhase::Warning;
87 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
90 bool CheckUnusedParams::VisitUnaryOperator(UnaryOperator const * op) {
91 if (op->getOpcode() != UO_AddrOf) {
92 return true;
94 if (m_phase != PluginPhase::FindAddressOf)
95 return true;
96 checkForFunctionDecl(op->getSubExpr());
97 return true;
100 bool CheckUnusedParams::VisitBinaryOperator(BinaryOperator const * binaryOperator) {
101 if (binaryOperator->getOpcode() != BO_Assign) {
102 return true;
104 if (m_phase != PluginPhase::FindAddressOf)
105 return true;
106 checkForFunctionDecl(binaryOperator->getRHS());
107 return true;
110 bool CheckUnusedParams::VisitCallExpr(CallExpr const * callExpr) {
111 if (m_phase != PluginPhase::FindAddressOf)
112 return true;
113 for (auto arg : callExpr->arguments())
114 checkForFunctionDecl(arg);
115 return true;
118 bool CheckUnusedParams::VisitCXXConstructExpr(CXXConstructExpr const * constructExpr) {
119 if (m_phase != PluginPhase::FindAddressOf)
120 return true;
121 for (auto arg : constructExpr->arguments())
122 checkForFunctionDecl(arg);
123 return true;
126 bool CheckUnusedParams::VisitInitListExpr(InitListExpr const * initListExpr) {
127 if (m_phase != PluginPhase::FindAddressOf)
128 return true;
129 for (auto subStmt : *initListExpr)
130 checkForFunctionDecl(dyn_cast<Expr>(subStmt));
131 return true;
134 void CheckUnusedParams::checkForFunctionDecl(Expr const * expr, bool bCheckOnly) {
135 auto e1 = expr->IgnoreParenCasts();
136 auto declRef = dyn_cast<DeclRefExpr>(e1);
137 if (!declRef)
138 return;
139 auto functionDecl = dyn_cast<FunctionDecl>(declRef->getDecl());
140 if (!functionDecl)
141 return;
142 if (bCheckOnly)
143 getParentStmt(expr)->dump();
144 else
145 m_addressOfSet.insert(functionDecl->getCanonicalDecl());
148 static int noFieldsInRecord(RecordType const * recordType) {
149 auto recordDecl = recordType->getDecl();
150 // if it's complicated, let's just assume it has fields
151 if (isa<ClassTemplateSpecializationDecl>(recordDecl))
152 return 1;
153 return std::distance(recordDecl->field_begin(), recordDecl->field_end());
155 static bool startswith(const std::string& rStr, const char* pSubStr) {
156 return rStr.compare(0, strlen(pSubStr), pSubStr) == 0;
158 static bool endswith(const std::string& rStr, const char* pSubStr) {
159 auto len = strlen(pSubStr);
160 if (len > rStr.size())
161 return false;
162 return rStr.compare(rStr.size() - len, rStr.size(), pSubStr) == 0;
165 bool CheckUnusedParams::VisitFunctionDecl(FunctionDecl const * decl) {
166 if (m_phase != PluginPhase::Warning)
167 return true;
168 if (m_addressOfSet.find(decl->getCanonicalDecl()) != m_addressOfSet.end())
169 return true;
170 if (ignoreLocation(decl))
171 return true;
172 if (isInUnoIncludeFile(compiler.getSourceManager().getSpellingLoc(decl->getLocation())))
173 return true;
175 auto cxxMethodDecl = dyn_cast<CXXMethodDecl>(decl);
176 if (cxxMethodDecl) {
177 if (cxxMethodDecl->isVirtual())
178 return true;
179 auto cxxConstructorDecl = dyn_cast<CXXConstructorDecl>(cxxMethodDecl);
180 if (cxxConstructorDecl && cxxConstructorDecl->isCopyOrMoveConstructor())
181 return true;
183 if (!decl->isThisDeclarationADefinition())
184 return true;
185 if (decl->isFunctionTemplateSpecialization())
186 return true;
187 if (decl->isDeleted())
188 return true;
189 if (decl->getTemplatedKind() != clang::FunctionDecl::TK_NonTemplate)
190 return true;
191 if (decl->isOverloadedOperator())
192 return true;
193 if (decl->isExternC())
194 return true;
196 //TODO, filtering out any functions relating to class templates for now:
197 CXXRecordDecl const * r = dyn_cast<CXXRecordDecl>(decl->getDeclContext());
198 if (r != nullptr
199 && (r->getTemplateSpecializationKind() != TSK_Undeclared
200 || r->isDependentContext()))
202 return true;
204 FunctionDecl const * canon = decl->getCanonicalDecl();
205 std::string fqn = canon->getQualifiedNameAsString(); // because sometimes clang returns nonsense for the filename of canon
206 if (ignoreLocation(canon))
207 return true;
208 if (isInUnoIncludeFile(compiler.getSourceManager().getSpellingLoc(canon->getLocation())))
209 return true;
210 StringRef fn = getFilenameOfLocation(compiler.getSourceManager().getSpellingLoc(canon->getBeginLoc()));
211 // Some backwards compat magic.
212 // TODO Can probably be removed, but need to do some checking
213 if (loplugin::isSamePathname(fn, SRCDIR "/include/sax/fshelper.hxx"))
214 return true;
215 // Platform-specific code
216 if (loplugin::isSamePathname(fn, SRCDIR "/include/svl/svdde.hxx"))
217 return true;
218 if (loplugin::isSamePathname(fn, SRCDIR "/include/vcl/svmain.hxx"))
219 return true;
220 // passing pointer to function
221 if (loplugin::isSamePathname(fn, SRCDIR "/include/vcl/BitmapReadAccess.hxx"))
222 return true;
223 if (loplugin::isSamePathname(fn, SRCDIR "/vcl/inc/unx/gtk/gtkobject.hxx"))
224 return true;
225 if (loplugin::isSamePathname(fn, SRCDIR "/vcl/inc/unx/gtk/gtksalframe.hxx"))
226 return true;
227 if (loplugin::isSamePathname(fn, SRCDIR "/vcl/inc/unx/gtk/gtkframe.hxx"))
228 return true;
229 if (loplugin::isSamePathname(fn, SRCDIR "/vcl/unx/gtk/fpicker/SalGtkFilePicker.hxx"))
230 return true;
231 if (loplugin::isSamePathname(fn, SRCDIR "/extensions/source/propctrlr/propertyeditor.hxx"))
232 return true;
233 if (loplugin::isSamePathname(fn, SRCDIR "/forms/source/solar/inc/navtoolbar.hxx"))
234 return true;
235 if (loplugin::isSamePathname(fn, SRCDIR "/hwpfilter/source/grammar.cxx"))
236 return true;
237 if (loplugin::isSamePathname(fn, SRCDIR "/hwpfilter/source/lexer.cxx"))
238 return true;
239 // marked with a TODO/FIXME
240 if (loplugin::isSamePathname(fn, SRCDIR "/vcl/inc/sallayout.hxx"))
241 return true;
242 if (loplugin::isSamePathname(fn, SRCDIR "/accessibility/inc/standard/vclxaccessiblelist.hxx"))
243 return true;
244 // these are "extern C" but clang doesn't seem to report that accurately
245 if (loplugin::isSamePathname(fn, SRCDIR "/sax/source/fastparser/fastparser.cxx"))
246 return true;
247 // these all follow the same pattern, seems a pity to break that
248 if (loplugin::isSamePathname(fn, SRCDIR "/include/vcl/graphicfilter.hxx"))
249 return true;
250 // looks like work in progress
251 if (loplugin::isSamePathname(fn, SRCDIR "/vcl/source/filter/ipdf/pdfdocument.cxx"))
252 return true;
253 // macro magic
254 if (loplugin::isSamePathname(fn, SRCDIR "/basctl/source/inc/basidesh.hxx"))
255 return true;
256 // template magic
257 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/canvas/"))
258 return true;
259 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/include/canvas/"))
260 return true;
261 if (loplugin::isSamePathname(fn, SRCDIR "/include/comphelper/unwrapargs.hxx"))
262 return true;
263 // this looks like vaguely useful code (ParseError) that I'm loathe to remove
264 if (loplugin::isSamePathname(fn, SRCDIR "/connectivity/source/inc/RowFunctionParser.hxx"))
265 return true;
266 if (loplugin::isSamePathname(fn, SRCDIR "/include/svx/EnhancedCustomShapeFunctionParser.hxx"))
267 return true;
268 // TODO marker parameter in constructor, should probably be using an enum
269 if (loplugin::isSamePathname(fn, SRCDIR "/framework/inc/uielement/uicommanddescription.hxx"))
270 return true;
271 if (loplugin::isSamePathname(fn, SRCDIR "/sd/source/ui/inc/SlideTransitionPane.hxx"))
272 return true;
273 if (loplugin::isSamePathname(fn, SRCDIR "/sd/source/ui/animations/CustomAnimationPane.hxx"))
274 return true;
275 if (loplugin::isSamePathname(fn, SRCDIR "/sd/source/ui/table/TableDesignPane.hxx"))
276 return true;
277 // debug stuff
278 if (loplugin::isSamePathname(fn, SRCDIR "/sc/source/core/data/column2.cxx"))
279 return true;
280 // weird stuff
281 if (loplugin::isSamePathname(fn, SRCDIR "/scaddins/source/analysis/analysishelper.hxx"))
282 return true;
283 // SFX_DECL_CHILDWINDOWCONTEXT macro stuff
284 if (loplugin::isSamePathname(fn, SRCDIR "/sd/source/ui/inc/NavigatorChildWindow.hxx"))
285 return true;
286 // TODO, need to remove this from the .sdi file too
287 if (loplugin::isSamePathname(fn, SRCDIR "/sd/source/ui/inc/SlideSorterViewShell.hxx"))
288 return true;
289 if (loplugin::isSamePathname(fn, SRCDIR "/sd/source/ui/inc/OutlineViewShell.hxx"))
290 return true;
291 // SFX_DECL_INTERFACE macro stuff
292 if (loplugin::isSamePathname(fn, SRCDIR "/sd/source/ui/inc/ViewShellBase.hxx"))
293 return true;
294 // debug stuff
295 if (loplugin::isSamePathname(fn, SRCDIR "/sd/source/filter/ppt/pptinanimations.hxx"))
296 return true;
297 // takes pointer to fn
298 if (loplugin::isSamePathname(fn, SRCDIR "/include/sfx2/shell.hxx"))
299 return true;
300 // TODO, need to remove this from the .sdi file too
301 if (fqn == "SfxObjectShell::StateView_Impl")
302 return true;
303 // SFX_DECL_CHILDWINDOW_WITHID macro
304 if (loplugin::isSamePathname(fn, SRCDIR "/include/sfx2/infobar.hxx"))
305 return true;
306 // this looks like vaguely useful code (ParseError) that I'm loathe to remove
307 if (loplugin::isSamePathname(fn, SRCDIR "/slideshow/source/inc/slideshowexceptions.hxx"))
308 return true;
309 // SFX_DECL_VIEWFACTORY macro
310 if (loplugin::isSamePathname(fn, SRCDIR "/starmath/inc/view.hxx"))
311 return true;
312 // debugging
313 if (fqn == "BrowseBox::DoShowCursor" || fqn == "BrowseBox::DoHideCursor")
314 return true;
315 // if I change this one, it then overrides a superclass virtual method
316 if (fqn == "GalleryBrowser2::KeyInput")
317 return true;
318 // takes pointer to function
319 if (fqn == "cmis::AuthProvider::onedriveAuthCodeFallback" || fqn == "cmis::AuthProvider::gdriveAuthCodeFallback")
320 return true;
321 if (fqn == "ooo_mount_operation_ask_password")
322 return true;
323 // TODO tricky to remove because of default params
324 if (fqn == "xmloff::OAttribute2Property::addBooleanProperty")
325 return true;
326 // taking pointer to function
327 if (fqn == "sw::DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl"
328 || fqn == "sw::DocumentContentOperationsManager::DeleteRangeImpl"
329 || fqn == "SwTableFormula::GetFormulaBoxes"
330 || fqn == "SwFEShell::Drag"
331 || fqn == "GetASCWriter" || fqn == "GetHTMLWriter" || fqn == "GetXMLWriter"
332 || fqn == "SwWrtShell::UpdateLayoutFrame" || fqn == "SwWrtShell::DefaultDrag"
333 || fqn == "SwWrtShell::DefaultEndDrag"
334 || startswith(fqn, "SwWW8ImplReader::Read_"))
335 return true;
336 // WIN32 only
337 if (fqn == "SwFntObj::GuessLeading")
338 return true;
339 // SFX_DECL_CHILDWINDOW_WITHID macro
340 if (fqn == "SwSpellDialogChildWindow::SwSpellDialogChildWindow"
341 || fqn == "SwFieldDlgWrapper::SwFieldDlgWrapper"
342 || fqn == "SwInputChild::SwInputChild")
343 return true;
344 // SFX_DECL_VIEWFACTORY macro
345 if (fqn == "SwSrcView::SwSrcView")
346 return true;
347 // Serves to disambiguate two very similar methods
348 if (fqn == "MSWordStyles::BuildGetSlot")
349 return true;
350 // TODO there are just too many default params to make this worth fixing right now
351 if (fqn == "ScDocument::CopyMultiRangeFromClip")
352 return true;
353 // TODO looks like this needs fixing?
354 if (fqn == "ScTable::ExtendPrintArea")
355 return true;
356 // there is a FIXME in the code
357 if (fqn == "ScRangeUtil::IsAbsTabArea")
358 return true;
359 // SFX_DECL_CHILDWINDOW_WITHID
360 if (fqn == "ScInputWindowWrapper::ScInputWindowWrapper"
361 || fqn == "sc::SearchResultsDlgWrapper::SearchResultsDlgWrapper")
362 return true;
363 // ExecMethod in .sdi file
364 if (fqn == "ScChartShell::ExecuteExportAsGraphic")
365 return true;
366 // bool marker parameter
367 if (fqn == "SvxIconReplacementDialog::SvxIconReplacementDialog")
368 return true;
369 // used as pointer to fn
370 if (endswith(fqn, "_createInstance"))
371 return true;
372 // callback
373 if (startswith(fqn, "SbRtl_"))
374 return true;
375 // takes pointer to fn
376 if (fqn == "migration::BasicMigration_create" || fqn == "migration::WordbookMigration_create"
377 || fqn == "comp_CBlankNode::_create" || fqn == "comp_CURI::_create"
378 || fqn == "comp_CLiteral::_create" || fqn == "CDocumentBuilder::_getInstance"
379 || fqn == "DOM::CDocumentBuilder::_getInstance"
380 || fqn == "xml_security::serial_number_adapter::create"
381 || fqn == "desktop::splash::create" || fqn == "ScannerManager_CreateInstance"
382 || fqn == "formula::FormulaOpCodeMapperObj::create"
383 || fqn == "(anonymous namespace)::createInstance"
384 || fqn == "x_error_handler"
385 || fqn == "warning_func"
386 || fqn == "error_func"
387 || fqn == "ScaDateAddIn_CreateInstance"
388 || fqn == "ScaPricingAddIn_CreateInstance"
389 || fqn == "(anonymous namespace)::PDFSigningPKCS7PasswordCallback"
390 || fqn == "ContextMenuEventLink"
391 || fqn == "DelayedCloseEventLink"
392 || fqn == "GDIMetaFile::ImplColMonoFnc"
393 || fqn == "vcl::getGlyph0"
394 || fqn == "vcl::getGlyph6"
395 || fqn == "vcl::getGlyph12"
396 || fqn == "setPasswordCallback"
397 || fqn == "VCLExceptionSignal_impl"
398 || fqn == "getFontTable"
399 || fqn == "textconversiondlgs::ChineseTranslation_UnoDialog::create"
400 || fqn == "pcr::DefaultHelpProvider::Create"
401 || fqn == "pcr::DefaultFormComponentInspectorModel::Create"
402 || fqn == "pcr::ObjectInspectorModel::Create"
403 || fqn == "GraphicExportFilter::GraphicExportFilter"
404 || fqn == "CertificateContainer::CertificateContainer"
405 || startswith(fqn, "ParseCSS1_")
407 return true;
408 // TODO
409 if (fqn == "FontSubsetInfo::CreateFontSubsetFromType1")
410 return true;
411 // used in template magic
412 if (fqn == "MtfRenderer::MtfRenderer" || fqn == "shell::sessioninstall::SyncDbusSessionHelper::SyncDbusSessionHelper"
413 || fqn == "dp_gui::LicenseDialog::LicenseDialog"
414 || fqn == "(anonymous namespace)::OGLTransitionFactoryImpl::OGLTransitionFactoryImpl")
415 return true;
416 // FIXME
417 if (fqn == "GtkSalDisplay::filterGdkEvent" || fqn == "SvXMLEmbeddedObjectHelper::ImplReadObject"
418 || fqn == "chart::CachedDataSequence::CachedDataSequence")
419 return true;
420 // used via macro
421 if (fqn == "framework::MediaTypeDetectionHelper::MediaTypeDetectionHelper"
422 || fqn == "framework::UriAbbreviation::UriAbbreviation"
423 || fqn == "framework::DispatchDisabler::DispatchDisabler"
424 || fqn == "framework::DispatchRecorderSupplier::DispatchRecorderSupplier")
425 return true;
426 // TODO Armin Le Grand is still working on this
427 if (fqn == "svx::frame::CreateDiagFrameBorderPrimitives"
428 || fqn == "svx::frame::CreateBorderPrimitives")
429 return true;
430 // marked with a TODO
431 if (fqn == "pcr::FormLinkDialog::getExistingRelation"
432 || fqn == "ooo::vba::DebugHelper::basicexception"
433 || fqn == "ScPrintFunc::DrawToDev")
434 return true;
435 // macros at work
436 if (fqn == "msfilter::lcl_PrintDigest")
437 return true;
438 // TODO something wrong here, the method that calls this (Normal::GenSlidingWindowFunction) cannot be correct
439 if (fqn == "sc::opencl::OpBase::Gen")
440 return true;
441 // Can't change this without conflicting with another constructor with the same signature
442 if (fqn == "XclExpSupbook::XclExpSupbook")
443 return true;
444 // ignore the LINK macros from include/tools/link.hxx
445 if (decl->getLocation().isMacroID())
446 return true;
447 // debug code in sw/
448 if (fqn == "lcl_dbg_out")
449 return true;
451 for( auto it = decl->param_begin(); it != decl->param_end(); ++it) {
452 auto param = *it;
453 if (param->hasAttr<UnusedAttr>())
454 continue;
455 if (!param->getName().empty())
456 continue;
457 // ignore params which are enum types with only a single enumerator, these are marker/tag types
458 auto paramType = param->getType();
459 if (paramType->isEnumeralType()) {
460 auto enumType = paramType->getAs<EnumType>();
461 int cnt = std::distance(enumType->getDecl()->enumerator_begin(), enumType->getDecl()->enumerator_end());
462 if (cnt == 1)
463 continue;
465 // ignore params which are a reference to a struct which has no fields.
466 // These are either
467 // (a) marker/tag types
468 // (b) selective "friend" access
469 if (paramType->isReferenceType()) {
470 auto referenceType = paramType->getAs<ReferenceType>();
471 if (referenceType->getPointeeType()->isRecordType()) {
472 auto recordType = referenceType->getPointeeType()->getAs<RecordType>();
473 if (noFieldsInRecord(recordType) == 0)
474 continue;
477 else if (paramType->isRecordType()) {
478 if (noFieldsInRecord(paramType->getAs<RecordType>()) == 0)
479 continue;
481 report( DiagnosticsEngine::Warning,
482 "unused param %0 in %1", param->getBeginLoc())
483 << param->getSourceRange()
484 << param->getName()
485 << fqn;
486 if (canon != decl)
488 unsigned idx = param->getFunctionScopeIndex();
489 const ParmVarDecl* pOther = canon->getParamDecl(idx);
490 report( DiagnosticsEngine::Note, "declaration is here",
491 pOther->getBeginLoc())
492 << pOther->getSourceRange();
495 return true;
498 loplugin::Plugin::Registration<CheckUnusedParams> X("checkunusedparams", false);
502 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */