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/.
18 Find parameters that have no name, i.e. they are unused and we're worked around the "unused parameter" warning.
20 Most of these can be removed.
22 TODO look for places where we are working around the warning by doing
27 class CheckUnusedParams
: public loplugin::FilteringPlugin
<CheckUnusedParams
> {
29 explicit CheckUnusedParams(loplugin::InstantiationData
const & data
):
30 FilteringPlugin(data
) {}
32 bool VisitFunctionDecl(FunctionDecl
const *);
33 bool VisitUnaryAddrOf(UnaryOperator
const *);
34 bool VisitInitListExpr(InitListExpr
const *);
35 bool VisitCallExpr(CallExpr
const *);
36 bool VisitBinAssign(BinaryOperator
const *);
37 bool VisitCXXConstructExpr(CXXConstructExpr
const *);
39 void checkForFunctionDecl(Expr
const *, bool bCheckOnly
= false);
40 std::set
<FunctionDecl
const *> m_addressOfSet
;
41 enum class PluginPhase
{ FindAddressOf
, Warning
};
45 void CheckUnusedParams::run()
47 StringRef
fn(handler
.getMainFileName());
48 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/sal/"))
50 // Taking pointer to function
51 if (loplugin::isSamePathname(fn
, SRCDIR
"/l10ntools/source/xmlparse.cxx"))
53 // macro magic which declares something needed by an external library
54 if (loplugin::isSamePathname(fn
, SRCDIR
"/svl/source/misc/gridprinter.cxx"))
58 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/compilerplugins/clang/test/"))
60 if (loplugin::isSamePathname(fn
, SRCDIR
"/cppu/qa/test_reference.cxx"))
63 // leave this alone for now
64 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/libreofficekit/"))
66 // this has a certain pattern to its code which appears to include lots of unused params
67 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/xmloff/"))
69 // I believe someone is busy working on this chunk of code
70 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/ui/docshell/dataprovider.cxx"))
72 // I think erack is working on stuff here
73 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/filter/excel/xiformula.cxx"))
75 // lots of callbacks here
76 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/filter/lotus/op.cxx"))
79 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/filter/html/htmlpars.cxx"))
82 m_phase
= PluginPhase::FindAddressOf
;
83 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
84 m_phase
= PluginPhase::Warning
;
85 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
88 bool CheckUnusedParams::VisitUnaryAddrOf(UnaryOperator
const * op
) {
89 if (m_phase
!= PluginPhase::FindAddressOf
)
91 checkForFunctionDecl(op
->getSubExpr());
95 bool CheckUnusedParams::VisitBinAssign(BinaryOperator
const * binaryOperator
) {
96 if (m_phase
!= PluginPhase::FindAddressOf
)
98 checkForFunctionDecl(binaryOperator
->getRHS());
102 bool CheckUnusedParams::VisitCallExpr(CallExpr
const * callExpr
) {
103 if (m_phase
!= PluginPhase::FindAddressOf
)
105 for (auto arg
: callExpr
->arguments())
106 checkForFunctionDecl(arg
);
110 bool CheckUnusedParams::VisitCXXConstructExpr(CXXConstructExpr
const * constructExpr
) {
111 if (m_phase
!= PluginPhase::FindAddressOf
)
113 for (auto arg
: constructExpr
->arguments())
114 checkForFunctionDecl(arg
);
118 bool CheckUnusedParams::VisitInitListExpr(InitListExpr
const * initListExpr
) {
119 if (m_phase
!= PluginPhase::FindAddressOf
)
121 for (auto subStmt
: *initListExpr
)
122 checkForFunctionDecl(dyn_cast
<Expr
>(subStmt
));
126 void CheckUnusedParams::checkForFunctionDecl(Expr
const * expr
, bool bCheckOnly
) {
127 auto e1
= expr
->IgnoreParenCasts();
128 auto declRef
= dyn_cast
<DeclRefExpr
>(e1
);
131 auto functionDecl
= dyn_cast
<FunctionDecl
>(declRef
->getDecl());
135 getParentStmt(expr
)->dump();
137 m_addressOfSet
.insert(functionDecl
->getCanonicalDecl());
140 static int noFieldsInRecord(RecordType
const * recordType
) {
141 auto recordDecl
= recordType
->getDecl();
142 // if it's complicated, lets just assume it has fields
143 if (isa
<ClassTemplateSpecializationDecl
>(recordDecl
))
145 return std::distance(recordDecl
->field_begin(), recordDecl
->field_end());
147 static bool startswith(const std::string
& rStr
, const char* pSubStr
) {
148 return rStr
.compare(0, strlen(pSubStr
), pSubStr
) == 0;
150 static bool endswith(const std::string
& rStr
, const char* pSubStr
) {
151 auto len
= strlen(pSubStr
);
152 if (len
> rStr
.size())
154 return rStr
.compare(rStr
.size() - len
, rStr
.size(), pSubStr
) == 0;
157 bool CheckUnusedParams::VisitFunctionDecl(FunctionDecl
const * decl
) {
158 if (m_phase
!= PluginPhase::Warning
)
160 if (m_addressOfSet
.find(decl
->getCanonicalDecl()) != m_addressOfSet
.end())
162 if (ignoreLocation(decl
))
164 if (isInUnoIncludeFile(compiler
.getSourceManager().getSpellingLoc(decl
->getLocation())))
167 auto cxxMethodDecl
= dyn_cast
<CXXMethodDecl
>(decl
);
169 if (cxxMethodDecl
->isVirtual())
171 auto cxxConstructorDecl
= dyn_cast
<CXXConstructorDecl
>(cxxMethodDecl
);
172 if (cxxConstructorDecl
&& cxxConstructorDecl
->isCopyOrMoveConstructor())
175 if (!decl
->isThisDeclarationADefinition())
177 if (decl
->isFunctionTemplateSpecialization())
179 if (decl
->isDeleted())
181 if (decl
->getTemplatedKind() != clang::FunctionDecl::TK_NonTemplate
)
183 if (decl
->isOverloadedOperator())
185 if (decl
->isExternC())
188 //TODO, filtering out any functions relating to class templates for now:
189 CXXRecordDecl
const * r
= dyn_cast
<CXXRecordDecl
>(decl
->getDeclContext());
191 && (r
->getTemplateSpecializationKind() != TSK_Undeclared
192 || r
->isDependentContext()))
196 FunctionDecl
const * canon
= decl
->getCanonicalDecl();
197 std::string fqn
= canon
->getQualifiedNameAsString(); // because sometimes clang returns nonsense for the filename of canon
198 if (ignoreLocation(canon
))
200 if (isInUnoIncludeFile(compiler
.getSourceManager().getSpellingLoc(canon
->getLocation())))
202 StringRef fn
= getFilenameOfLocation(compiler
.getSourceManager().getSpellingLoc(compat::getBeginLoc(canon
)));
203 // Some backwards compat magic.
204 // TODO Can probably be removed, but need to do some checking
205 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/sax/fshelper.hxx"))
207 // Platform-specific code
208 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/svl/svdde.hxx"))
210 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/vcl/svmain.hxx"))
212 // passing pointer to function
213 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/vcl/bitmapaccess.hxx"))
215 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/inc/unx/gtk/gtkobject.hxx"))
217 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/inc/unx/gtk/gtksalframe.hxx"))
219 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/inc/unx/gtk/gtkframe.hxx"))
221 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/unx/gtk/fpicker/SalGtkFilePicker.hxx"))
223 if (loplugin::isSamePathname(fn
, SRCDIR
"/extensions/source/propctrlr/propertyeditor.hxx"))
225 if (loplugin::isSamePathname(fn
, SRCDIR
"/forms/source/solar/inc/navtoolbar.hxx"))
227 if (loplugin::isSamePathname(fn
, SRCDIR
"/hwpfilter/source/grammar.cxx"))
229 if (loplugin::isSamePathname(fn
, SRCDIR
"/hwpfilter/source/lexer.cxx"))
231 // marked with a TODO/FIXME
232 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/inc/sallayout.hxx"))
234 if (loplugin::isSamePathname(fn
, SRCDIR
"/accessibility/inc/standard/vclxaccessiblelist.hxx"))
236 // these are "extern C" but clang doesn't seem to report that accurately
237 if (loplugin::isSamePathname(fn
, SRCDIR
"/sax/source/fastparser/fastparser.cxx"))
239 // these all follow the same pattern, seems a pity to break that
240 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/vcl/graphicfilter.hxx"))
242 // looks like work in progress
243 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/source/filter/ipdf/pdfdocument.cxx"))
246 if (loplugin::isSamePathname(fn
, SRCDIR
"/basctl/source/inc/basidesh.hxx"))
249 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/canvas/"))
251 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/include/canvas/"))
253 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/comphelper/unwrapargs.hxx"))
255 // this looks like vaguely useful code (ParseError) that I'm loathe to remove
256 if (loplugin::isSamePathname(fn
, SRCDIR
"/connectivity/source/inc/RowFunctionParser.hxx"))
258 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/svx/EnhancedCustomShapeFunctionParser.hxx"))
260 // TODO marker parameter in constructor, should probably be using an enum
261 if (loplugin::isSamePathname(fn
, SRCDIR
"/framework/inc/uielement/uicommanddescription.hxx"))
263 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/inc/SlideTransitionPane.hxx"))
265 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/animations/CustomAnimationPane.hxx"))
267 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/table/TableDesignPane.hxx"))
270 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/core/data/column2.cxx"))
273 if (loplugin::isSamePathname(fn
, SRCDIR
"/scaddins/source/analysis/analysishelper.hxx"))
275 // SFX_DECL_CHILDWINDOWCONTEXT macro stuff
276 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/inc/NavigatorChildWindow.hxx"))
278 // TODO, need to remove this from the .sdi file too
279 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/inc/SlideSorterViewShell.hxx"))
281 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/inc/OutlineViewShell.hxx"))
283 // SFX_DECL_INTERFACE macro stuff
284 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/inc/ViewShellBase.hxx"))
287 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/filter/ppt/pptinanimations.hxx"))
289 // takes pointer to fn
290 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/sfx2/shell.hxx"))
292 // TODO, need to remove this from the .sdi file too
293 if (fqn
== "SfxObjectShell::StateView_Impl")
295 // SFX_DECL_CHILDWINDOW_WITHID macro
296 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/sfx2/infobar.hxx"))
298 // this looks like vaguely useful code (ParseError) that I'm loathe to remove
299 if (loplugin::isSamePathname(fn
, SRCDIR
"/slideshow/source/inc/slideshowexceptions.hxx"))
301 // SFX_DECL_VIEWFACTORY macro
302 if (loplugin::isSamePathname(fn
, SRCDIR
"/starmath/inc/view.hxx"))
305 if (fqn
== "BrowseBox::DoShowCursor" || fqn
== "BrowseBox::DoHideCursor")
307 // if I change this one, it then overrides a superclass virtual method
308 if (fqn
== "GalleryBrowser2::KeyInput")
310 // takes pointer to function
311 if (fqn
== "cmis::AuthProvider::onedriveAuthCodeFallback" || fqn
== "cmis::AuthProvider::gdriveAuthCodeFallback")
313 if (fqn
== "ooo_mount_operation_ask_password")
315 // TODO tricky to remove because of default params
316 if (fqn
== "xmloff::OAttribute2Property::addBooleanProperty")
318 // taking pointer to function
319 if (fqn
== "sw::DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl"
320 || fqn
== "sw::DocumentContentOperationsManager::DeleteRangeImpl"
321 || fqn
== "SwTableFormula::GetFormulaBoxes"
322 || fqn
== "SwFEShell::Drag"
323 || fqn
== "GetASCWriter" || fqn
== "GetHTMLWriter" || fqn
== "GetXMLWriter"
324 || fqn
== "SwWrtShell::UpdateLayoutFrame" || fqn
== "SwWrtShell::DefaultDrag"
325 || fqn
== "SwWrtShell::DefaultEndDrag"
326 || startswith(fqn
, "SwWW8ImplReader::Read_"))
329 if (fqn
== "SwFntObj::GuessLeading")
331 // SFX_DECL_CHILDWINDOW_WITHID macro
332 if (fqn
== "SwSpellDialogChildWindow::SwSpellDialogChildWindow"
333 || fqn
== "SwFieldDlgWrapper::SwFieldDlgWrapper"
334 || fqn
== "SwInputChild::SwInputChild")
336 // SFX_DECL_VIEWFACTORY macro
337 if (fqn
== "SwSrcView::SwSrcView")
339 // Serves to disambiguate two very similar methods
340 if (fqn
== "MSWordStyles::BuildGetSlot")
342 // TODO there are just too many default params to make this worth fixing right now
343 if (fqn
== "ScDocument::CopyMultiRangeFromClip")
345 // TODO looks like this needs fixing?
346 if (fqn
== "ScTable::ExtendPrintArea")
348 // there is a FIXME in the code
349 if (fqn
== "ScRangeUtil::IsAbsTabArea")
351 // SFX_DECL_CHILDWINDOW_WITHID
352 if (fqn
== "ScInputWindowWrapper::ScInputWindowWrapper"
353 || fqn
== "sc::SearchResultsDlgWrapper::SearchResultsDlgWrapper")
355 // ExecMethod in .sdi file
356 if (fqn
== "ScChartShell::ExecuteExportAsGraphic")
358 // bool marker parameter
359 if (fqn
== "SvxIconReplacementDialog::SvxIconReplacementDialog")
361 // used as pointer to fn
362 if (endswith(fqn
, "_createInstance"))
365 if (startswith(fqn
, "SbRtl_"))
367 // takes pointer to fn
368 if (fqn
== "migration::BasicMigration_create" || fqn
== "migration::WordbookMigration_create"
369 || fqn
== "comp_CBlankNode::_create" || fqn
== "comp_CURI::_create"
370 || fqn
== "comp_CLiteral::_create" || fqn
== "CDocumentBuilder::_getInstance"
371 || fqn
== "DOM::CDocumentBuilder::_getInstance"
372 || fqn
== "xml_security::serial_number_adapter::create"
373 || fqn
== "desktop::splash::create" || fqn
== "ScannerManager_CreateInstance"
374 || fqn
== "formula::FormulaOpCodeMapperObj::create"
375 || fqn
== "(anonymous namespace)::createInstance"
376 || fqn
== "x_error_handler"
377 || fqn
== "warning_func"
378 || fqn
== "error_func"
379 || fqn
== "ScaDateAddIn_CreateInstance"
380 || fqn
== "ScaPricingAddIn_CreateInstance"
381 || fqn
== "(anonymous namespace)::PDFSigningPKCS7PasswordCallback"
382 || fqn
== "ContextMenuEventLink"
383 || fqn
== "DelayedCloseEventLink"
384 || fqn
== "GDIMetaFile::ImplColMonoFnc"
385 || fqn
== "vcl::getGlyph0"
386 || fqn
== "vcl::getGlyph6"
387 || fqn
== "vcl::getGlyph12"
388 || fqn
== "setPasswordCallback"
389 || fqn
== "VCLExceptionSignal_impl"
390 || fqn
== "getFontTable"
391 || fqn
== "textconversiondlgs::ChineseTranslation_UnoDialog::create"
392 || fqn
== "pcr::DefaultHelpProvider::Create"
393 || fqn
== "pcr::DefaultFormComponentInspectorModel::Create"
394 || fqn
== "pcr::ObjectInspectorModel::Create"
395 || fqn
== "GraphicExportFilter::GraphicExportFilter"
396 || fqn
== "CertificateContainer::CertificateContainer"
397 || startswith(fqn
, "ParseCSS1_")
401 if (fqn
== "FontSubsetInfo::CreateFontSubsetFromType1")
403 // used in template magic
404 if (fqn
== "MtfRenderer::MtfRenderer" || fqn
== "shell::sessioninstall::SyncDbusSessionHelper::SyncDbusSessionHelper"
405 || fqn
== "dp_gui::LicenseDialog::LicenseDialog"
406 || fqn
== "(anonymous namespace)::OGLTransitionFactoryImpl::OGLTransitionFactoryImpl")
409 if (fqn
== "GtkSalDisplay::filterGdkEvent" || fqn
== "SvXMLEmbeddedObjectHelper::ImplReadObject"
410 || fqn
== "chart::CachedDataSequence::CachedDataSequence")
413 if (fqn
== "framework::MediaTypeDetectionHelper::MediaTypeDetectionHelper"
414 || fqn
== "framework::UriAbbreviation::UriAbbreviation"
415 || fqn
== "framework::DispatchDisabler::DispatchDisabler"
416 || fqn
== "framework::DispatchRecorderSupplier::DispatchRecorderSupplier")
418 // TODO Armin Le Grand is still working on this
419 if (fqn
== "svx::frame::CreateDiagFrameBorderPrimitives"
420 || fqn
== "svx::frame::CreateBorderPrimitives")
422 // marked with a TODO
423 if (fqn
== "pcr::FormLinkDialog::getExistingRelation"
424 || fqn
== "ooo::vba::DebugHelper::basicexception"
425 || fqn
== "ScPrintFunc::DrawToDev")
428 if (fqn
== "msfilter::lcl_PrintDigest")
430 // TODO something wrong here, the method that calls this (Normal::GenSlidingWindowFunction) cannot be correct
431 if (fqn
== "sc::opencl::OpBase::Gen")
433 // Can't change this without conflicting with another constructor with the same signature
434 if (fqn
== "XclExpSupbook::XclExpSupbook")
436 // ignore the LINK macros from include/tools/link.hxx
437 if (decl
->getLocation().isMacroID())
440 if (fqn
== "lcl_dbg_out")
443 for( auto it
= decl
->param_begin(); it
!= decl
->param_end(); ++it
) {
445 if (param
->hasAttr
<UnusedAttr
>())
447 if (!param
->getName().empty())
449 // ignore params which are enum types with only a single enumerator, these are marker/tag types
450 auto paramType
= param
->getType();
451 if (paramType
->isEnumeralType()) {
452 auto enumType
= paramType
->getAs
<EnumType
>();
453 int cnt
= std::distance(enumType
->getDecl()->enumerator_begin(), enumType
->getDecl()->enumerator_end());
457 // ignore params which are a reference to a struct which has no fields.
459 // (a) marker/tag types
460 // (b) selective "friend" access
461 if (paramType
->isReferenceType()) {
462 auto referenceType
= paramType
->getAs
<ReferenceType
>();
463 if (referenceType
->getPointeeType()->isRecordType()) {
464 auto recordType
= referenceType
->getPointeeType()->getAs
<RecordType
>();
465 if (noFieldsInRecord(recordType
) == 0)
469 else if (paramType
->isRecordType()) {
470 if (noFieldsInRecord(paramType
->getAs
<RecordType
>()) == 0)
473 report( DiagnosticsEngine::Warning
,
474 "unused param %0 in %1", compat::getBeginLoc(param
))
475 << param
->getSourceRange()
480 unsigned idx
= param
->getFunctionScopeIndex();
481 const ParmVarDecl
* pOther
= canon
->getParamDecl(idx
);
482 report( DiagnosticsEngine::Note
, "declaration is here",
483 compat::getBeginLoc(pOther
))
484 << pOther
->getSourceRange();
490 loplugin::Plugin::Registration
<CheckUnusedParams
> X("checkunusedparams", false);
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */