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/.
15 #include "config_clang.h"
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
29 class CheckUnusedParams
: public loplugin::FilteringPlugin
<CheckUnusedParams
> {
31 explicit CheckUnusedParams(loplugin::InstantiationData
const & data
):
32 FilteringPlugin(data
) {}
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 *);
41 void checkForFunctionDecl(Expr
const *, bool bCheckOnly
= false);
42 std::set
<FunctionDecl
const *> m_addressOfSet
;
43 enum class PluginPhase
{ FindAddressOf
, Warning
};
47 void CheckUnusedParams::run()
49 StringRef
fn(handler
.getMainFileName());
50 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/sal/"))
52 // Taking pointer to function
53 if (loplugin::isSamePathname(fn
, SRCDIR
"/l10ntools/source/xmlparse.cxx"))
55 // macro magic which declares something needed by an external library
56 if (loplugin::isSamePathname(fn
, SRCDIR
"/svl/source/misc/gridprinter.cxx"))
60 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/compilerplugins/clang/test/"))
62 if (loplugin::isSamePathname(fn
, SRCDIR
"/cppu/qa/test_reference.cxx"))
65 // leave this alone for now
66 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/libreofficekit/"))
68 // this has a certain pattern to its code which appears to include lots of unused params
69 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/xmloff/"))
71 // I believe someone is busy working on this chunk of code
72 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/ui/docshell/dataprovider.cxx"))
74 // I think erack is working on stuff here
75 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/filter/excel/xiformula.cxx"))
77 // lots of callbacks here
78 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/filter/lotus/op.cxx"))
81 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/filter/html/htmlpars.cxx"))
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
) {
94 if (m_phase
!= PluginPhase::FindAddressOf
)
96 checkForFunctionDecl(op
->getSubExpr());
100 bool CheckUnusedParams::VisitBinaryOperator(BinaryOperator
const * binaryOperator
) {
101 if (binaryOperator
->getOpcode() != BO_Assign
) {
104 if (m_phase
!= PluginPhase::FindAddressOf
)
106 checkForFunctionDecl(binaryOperator
->getRHS());
110 bool CheckUnusedParams::VisitCallExpr(CallExpr
const * callExpr
) {
111 if (m_phase
!= PluginPhase::FindAddressOf
)
113 for (auto arg
: callExpr
->arguments())
114 checkForFunctionDecl(arg
);
118 bool CheckUnusedParams::VisitCXXConstructExpr(CXXConstructExpr
const * constructExpr
) {
119 if (m_phase
!= PluginPhase::FindAddressOf
)
121 for (auto arg
: constructExpr
->arguments())
122 checkForFunctionDecl(arg
);
126 bool CheckUnusedParams::VisitInitListExpr(InitListExpr
const * initListExpr
) {
127 if (m_phase
!= PluginPhase::FindAddressOf
)
129 for (auto subStmt
: *initListExpr
)
130 checkForFunctionDecl(dyn_cast
<Expr
>(subStmt
));
134 void CheckUnusedParams::checkForFunctionDecl(Expr
const * expr
, bool bCheckOnly
) {
135 auto e1
= expr
->IgnoreParenCasts();
136 auto declRef
= dyn_cast
<DeclRefExpr
>(e1
);
139 auto functionDecl
= dyn_cast
<FunctionDecl
>(declRef
->getDecl());
143 getParentStmt(expr
)->dump();
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
))
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())
162 return rStr
.compare(rStr
.size() - len
, rStr
.size(), pSubStr
) == 0;
165 bool CheckUnusedParams::VisitFunctionDecl(FunctionDecl
const * decl
) {
166 if (m_phase
!= PluginPhase::Warning
)
168 if (m_addressOfSet
.find(decl
->getCanonicalDecl()) != m_addressOfSet
.end())
170 if (ignoreLocation(decl
))
172 if (isInUnoIncludeFile(compiler
.getSourceManager().getSpellingLoc(decl
->getLocation())))
175 auto cxxMethodDecl
= dyn_cast
<CXXMethodDecl
>(decl
);
177 if (cxxMethodDecl
->isVirtual())
179 auto cxxConstructorDecl
= dyn_cast
<CXXConstructorDecl
>(cxxMethodDecl
);
180 if (cxxConstructorDecl
&& cxxConstructorDecl
->isCopyOrMoveConstructor())
183 if (!decl
->isThisDeclarationADefinition())
185 if (decl
->isFunctionTemplateSpecialization())
187 if (decl
->isDeleted())
189 if (decl
->getTemplatedKind() != clang::FunctionDecl::TK_NonTemplate
)
191 if (decl
->isOverloadedOperator())
193 if (decl
->isExternC())
196 //TODO, filtering out any functions relating to class templates for now:
197 CXXRecordDecl
const * r
= dyn_cast
<CXXRecordDecl
>(decl
->getDeclContext());
199 && (r
->getTemplateSpecializationKind() != TSK_Undeclared
200 || r
->isDependentContext()))
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
))
208 if (isInUnoIncludeFile(compiler
.getSourceManager().getSpellingLoc(canon
->getLocation())))
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"))
215 // Platform-specific code
216 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/svl/svdde.hxx"))
218 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/vcl/svmain.hxx"))
220 // passing pointer to function
221 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/vcl/BitmapReadAccess.hxx"))
223 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/inc/unx/gtk/gtkobject.hxx"))
225 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/inc/unx/gtk/gtksalframe.hxx"))
227 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/inc/unx/gtk/gtkframe.hxx"))
229 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/unx/gtk/fpicker/SalGtkFilePicker.hxx"))
231 if (loplugin::isSamePathname(fn
, SRCDIR
"/extensions/source/propctrlr/propertyeditor.hxx"))
233 if (loplugin::isSamePathname(fn
, SRCDIR
"/forms/source/solar/inc/navtoolbar.hxx"))
235 if (loplugin::isSamePathname(fn
, SRCDIR
"/hwpfilter/source/grammar.cxx"))
237 if (loplugin::isSamePathname(fn
, SRCDIR
"/hwpfilter/source/lexer.cxx"))
239 // marked with a TODO/FIXME
240 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/inc/sallayout.hxx"))
242 if (loplugin::isSamePathname(fn
, SRCDIR
"/accessibility/inc/standard/vclxaccessiblelist.hxx"))
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"))
247 // these all follow the same pattern, seems a pity to break that
248 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/vcl/graphicfilter.hxx"))
250 // looks like work in progress
251 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/source/filter/ipdf/pdfdocument.cxx"))
254 if (loplugin::isSamePathname(fn
, SRCDIR
"/basctl/source/inc/basidesh.hxx"))
257 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/canvas/"))
259 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/include/canvas/"))
261 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/comphelper/unwrapargs.hxx"))
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"))
266 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/svx/EnhancedCustomShapeFunctionParser.hxx"))
268 // TODO marker parameter in constructor, should probably be using an enum
269 if (loplugin::isSamePathname(fn
, SRCDIR
"/framework/inc/uielement/uicommanddescription.hxx"))
271 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/inc/SlideTransitionPane.hxx"))
273 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/animations/CustomAnimationPane.hxx"))
275 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/table/TableDesignPane.hxx"))
278 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/core/data/column2.cxx"))
281 if (loplugin::isSamePathname(fn
, SRCDIR
"/scaddins/source/analysis/analysishelper.hxx"))
283 // SFX_DECL_CHILDWINDOWCONTEXT macro stuff
284 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/inc/NavigatorChildWindow.hxx"))
286 // TODO, need to remove this from the .sdi file too
287 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/inc/SlideSorterViewShell.hxx"))
289 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/inc/OutlineViewShell.hxx"))
291 // SFX_DECL_INTERFACE macro stuff
292 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/inc/ViewShellBase.hxx"))
295 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/filter/ppt/pptinanimations.hxx"))
297 // takes pointer to fn
298 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/sfx2/shell.hxx"))
300 // TODO, need to remove this from the .sdi file too
301 if (fqn
== "SfxObjectShell::StateView_Impl")
303 // SFX_DECL_CHILDWINDOW_WITHID macro
304 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/sfx2/infobar.hxx"))
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"))
309 // SFX_DECL_VIEWFACTORY macro
310 if (loplugin::isSamePathname(fn
, SRCDIR
"/starmath/inc/view.hxx"))
313 if (fqn
== "BrowseBox::DoShowCursor" || fqn
== "BrowseBox::DoHideCursor")
315 // if I change this one, it then overrides a superclass virtual method
316 if (fqn
== "GalleryBrowser2::KeyInput")
318 // takes pointer to function
319 if (fqn
== "cmis::AuthProvider::onedriveAuthCodeFallback" || fqn
== "cmis::AuthProvider::gdriveAuthCodeFallback")
321 if (fqn
== "ooo_mount_operation_ask_password")
323 // TODO tricky to remove because of default params
324 if (fqn
== "xmloff::OAttribute2Property::addBooleanProperty")
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_"))
337 if (fqn
== "SwFntObj::GuessLeading")
339 // SFX_DECL_CHILDWINDOW_WITHID macro
340 if (fqn
== "SwSpellDialogChildWindow::SwSpellDialogChildWindow"
341 || fqn
== "SwFieldDlgWrapper::SwFieldDlgWrapper"
342 || fqn
== "SwInputChild::SwInputChild")
344 // SFX_DECL_VIEWFACTORY macro
345 if (fqn
== "SwSrcView::SwSrcView")
347 // Serves to disambiguate two very similar methods
348 if (fqn
== "MSWordStyles::BuildGetSlot")
350 // TODO there are just too many default params to make this worth fixing right now
351 if (fqn
== "ScDocument::CopyMultiRangeFromClip")
353 // TODO looks like this needs fixing?
354 if (fqn
== "ScTable::ExtendPrintArea")
356 // there is a FIXME in the code
357 if (fqn
== "ScRangeUtil::IsAbsTabArea")
359 // SFX_DECL_CHILDWINDOW_WITHID
360 if (fqn
== "ScInputWindowWrapper::ScInputWindowWrapper"
361 || fqn
== "sc::SearchResultsDlgWrapper::SearchResultsDlgWrapper")
363 // ExecMethod in .sdi file
364 if (fqn
== "ScChartShell::ExecuteExportAsGraphic")
366 // bool marker parameter
367 if (fqn
== "SvxIconReplacementDialog::SvxIconReplacementDialog")
369 // used as pointer to fn
370 if (endswith(fqn
, "_createInstance"))
373 if (startswith(fqn
, "SbRtl_"))
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_")
409 if (fqn
== "FontSubsetInfo::CreateFontSubsetFromType1")
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")
417 if (fqn
== "GtkSalDisplay::filterGdkEvent" || fqn
== "SvXMLEmbeddedObjectHelper::ImplReadObject"
418 || fqn
== "chart::CachedDataSequence::CachedDataSequence")
421 if (fqn
== "framework::MediaTypeDetectionHelper::MediaTypeDetectionHelper"
422 || fqn
== "framework::UriAbbreviation::UriAbbreviation"
423 || fqn
== "framework::DispatchDisabler::DispatchDisabler"
424 || fqn
== "framework::DispatchRecorderSupplier::DispatchRecorderSupplier")
426 // TODO Armin Le Grand is still working on this
427 if (fqn
== "svx::frame::CreateDiagFrameBorderPrimitives"
428 || fqn
== "svx::frame::CreateBorderPrimitives")
430 // marked with a TODO
431 if (fqn
== "pcr::FormLinkDialog::getExistingRelation"
432 || fqn
== "ooo::vba::DebugHelper::basicexception"
433 || fqn
== "ScPrintFunc::DrawToDev")
436 if (fqn
== "msfilter::lcl_PrintDigest")
438 // TODO something wrong here, the method that calls this (Normal::GenSlidingWindowFunction) cannot be correct
439 if (fqn
== "sc::opencl::OpBase::Gen")
441 // Can't change this without conflicting with another constructor with the same signature
442 if (fqn
== "XclExpSupbook::XclExpSupbook")
444 // ignore the LINK macros from include/tools/link.hxx
445 if (decl
->getLocation().isMacroID())
448 if (fqn
== "lcl_dbg_out")
451 for( auto it
= decl
->param_begin(); it
!= decl
->param_end(); ++it
) {
453 if (param
->hasAttr
<UnusedAttr
>())
455 if (!param
->getName().empty())
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());
465 // ignore params which are a reference to a struct which has no fields.
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)
477 else if (paramType
->isRecordType()) {
478 if (noFieldsInRecord(paramType
->getAs
<RecordType
>()) == 0)
481 report( DiagnosticsEngine::Warning
,
482 "unused param %0 in %1", param
->getBeginLoc())
483 << param
->getSourceRange()
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();
498 loplugin::Plugin::Registration
<CheckUnusedParams
> X("checkunusedparams", false);
502 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */