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 VisitUnaryOperator(UnaryOperator
const *);
34 bool VisitInitListExpr(InitListExpr
const *);
35 bool VisitCallExpr(CallExpr
const *);
36 bool VisitBinaryOperator(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::VisitUnaryOperator(UnaryOperator
const * op
) {
89 if (op
->getOpcode() != UO_AddrOf
) {
92 if (m_phase
!= PluginPhase::FindAddressOf
)
94 checkForFunctionDecl(op
->getSubExpr());
98 bool CheckUnusedParams::VisitBinaryOperator(BinaryOperator
const * binaryOperator
) {
99 if (binaryOperator
->getOpcode() != BO_Assign
) {
102 if (m_phase
!= PluginPhase::FindAddressOf
)
104 checkForFunctionDecl(binaryOperator
->getRHS());
108 bool CheckUnusedParams::VisitCallExpr(CallExpr
const * callExpr
) {
109 if (m_phase
!= PluginPhase::FindAddressOf
)
111 for (auto arg
: callExpr
->arguments())
112 checkForFunctionDecl(arg
);
116 bool CheckUnusedParams::VisitCXXConstructExpr(CXXConstructExpr
const * constructExpr
) {
117 if (m_phase
!= PluginPhase::FindAddressOf
)
119 for (auto arg
: constructExpr
->arguments())
120 checkForFunctionDecl(arg
);
124 bool CheckUnusedParams::VisitInitListExpr(InitListExpr
const * initListExpr
) {
125 if (m_phase
!= PluginPhase::FindAddressOf
)
127 for (auto subStmt
: *initListExpr
)
128 checkForFunctionDecl(dyn_cast
<Expr
>(subStmt
));
132 void CheckUnusedParams::checkForFunctionDecl(Expr
const * expr
, bool bCheckOnly
) {
133 auto e1
= expr
->IgnoreParenCasts();
134 auto declRef
= dyn_cast
<DeclRefExpr
>(e1
);
137 auto functionDecl
= dyn_cast
<FunctionDecl
>(declRef
->getDecl());
141 getParentStmt(expr
)->dump();
143 m_addressOfSet
.insert(functionDecl
->getCanonicalDecl());
146 static int noFieldsInRecord(RecordType
const * recordType
) {
147 auto recordDecl
= recordType
->getDecl();
148 // if it's complicated, lets just assume it has fields
149 if (isa
<ClassTemplateSpecializationDecl
>(recordDecl
))
151 return std::distance(recordDecl
->field_begin(), recordDecl
->field_end());
153 static bool startswith(const std::string
& rStr
, const char* pSubStr
) {
154 return rStr
.compare(0, strlen(pSubStr
), pSubStr
) == 0;
156 static bool endswith(const std::string
& rStr
, const char* pSubStr
) {
157 auto len
= strlen(pSubStr
);
158 if (len
> rStr
.size())
160 return rStr
.compare(rStr
.size() - len
, rStr
.size(), pSubStr
) == 0;
163 bool CheckUnusedParams::VisitFunctionDecl(FunctionDecl
const * decl
) {
164 if (m_phase
!= PluginPhase::Warning
)
166 if (m_addressOfSet
.find(decl
->getCanonicalDecl()) != m_addressOfSet
.end())
168 if (ignoreLocation(decl
))
170 if (isInUnoIncludeFile(compiler
.getSourceManager().getSpellingLoc(decl
->getLocation())))
173 auto cxxMethodDecl
= dyn_cast
<CXXMethodDecl
>(decl
);
175 if (cxxMethodDecl
->isVirtual())
177 auto cxxConstructorDecl
= dyn_cast
<CXXConstructorDecl
>(cxxMethodDecl
);
178 if (cxxConstructorDecl
&& cxxConstructorDecl
->isCopyOrMoveConstructor())
181 if (!decl
->isThisDeclarationADefinition())
183 if (decl
->isFunctionTemplateSpecialization())
185 if (decl
->isDeleted())
187 if (decl
->getTemplatedKind() != clang::FunctionDecl::TK_NonTemplate
)
189 if (decl
->isOverloadedOperator())
191 if (decl
->isExternC())
194 //TODO, filtering out any functions relating to class templates for now:
195 CXXRecordDecl
const * r
= dyn_cast
<CXXRecordDecl
>(decl
->getDeclContext());
197 && (r
->getTemplateSpecializationKind() != TSK_Undeclared
198 || r
->isDependentContext()))
202 FunctionDecl
const * canon
= decl
->getCanonicalDecl();
203 std::string fqn
= canon
->getQualifiedNameAsString(); // because sometimes clang returns nonsense for the filename of canon
204 if (ignoreLocation(canon
))
206 if (isInUnoIncludeFile(compiler
.getSourceManager().getSpellingLoc(canon
->getLocation())))
208 StringRef fn
= getFilenameOfLocation(compiler
.getSourceManager().getSpellingLoc(compat::getBeginLoc(canon
)));
209 // Some backwards compat magic.
210 // TODO Can probably be removed, but need to do some checking
211 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/sax/fshelper.hxx"))
213 // Platform-specific code
214 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/svl/svdde.hxx"))
216 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/vcl/svmain.hxx"))
218 // passing pointer to function
219 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/vcl/BitmapReadAccess.hxx"))
221 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/inc/unx/gtk/gtkobject.hxx"))
223 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/inc/unx/gtk/gtksalframe.hxx"))
225 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/inc/unx/gtk/gtkframe.hxx"))
227 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/unx/gtk/fpicker/SalGtkFilePicker.hxx"))
229 if (loplugin::isSamePathname(fn
, SRCDIR
"/extensions/source/propctrlr/propertyeditor.hxx"))
231 if (loplugin::isSamePathname(fn
, SRCDIR
"/forms/source/solar/inc/navtoolbar.hxx"))
233 if (loplugin::isSamePathname(fn
, SRCDIR
"/hwpfilter/source/grammar.cxx"))
235 if (loplugin::isSamePathname(fn
, SRCDIR
"/hwpfilter/source/lexer.cxx"))
237 // marked with a TODO/FIXME
238 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/inc/sallayout.hxx"))
240 if (loplugin::isSamePathname(fn
, SRCDIR
"/accessibility/inc/standard/vclxaccessiblelist.hxx"))
242 // these are "extern C" but clang doesn't seem to report that accurately
243 if (loplugin::isSamePathname(fn
, SRCDIR
"/sax/source/fastparser/fastparser.cxx"))
245 // these all follow the same pattern, seems a pity to break that
246 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/vcl/graphicfilter.hxx"))
248 // looks like work in progress
249 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/source/filter/ipdf/pdfdocument.cxx"))
252 if (loplugin::isSamePathname(fn
, SRCDIR
"/basctl/source/inc/basidesh.hxx"))
255 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/canvas/"))
257 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/include/canvas/"))
259 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/comphelper/unwrapargs.hxx"))
261 // this looks like vaguely useful code (ParseError) that I'm loathe to remove
262 if (loplugin::isSamePathname(fn
, SRCDIR
"/connectivity/source/inc/RowFunctionParser.hxx"))
264 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/svx/EnhancedCustomShapeFunctionParser.hxx"))
266 // TODO marker parameter in constructor, should probably be using an enum
267 if (loplugin::isSamePathname(fn
, SRCDIR
"/framework/inc/uielement/uicommanddescription.hxx"))
269 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/inc/SlideTransitionPane.hxx"))
271 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/animations/CustomAnimationPane.hxx"))
273 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/table/TableDesignPane.hxx"))
276 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/core/data/column2.cxx"))
279 if (loplugin::isSamePathname(fn
, SRCDIR
"/scaddins/source/analysis/analysishelper.hxx"))
281 // SFX_DECL_CHILDWINDOWCONTEXT macro stuff
282 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/inc/NavigatorChildWindow.hxx"))
284 // TODO, need to remove this from the .sdi file too
285 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/inc/SlideSorterViewShell.hxx"))
287 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/inc/OutlineViewShell.hxx"))
289 // SFX_DECL_INTERFACE macro stuff
290 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/inc/ViewShellBase.hxx"))
293 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/filter/ppt/pptinanimations.hxx"))
295 // takes pointer to fn
296 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/sfx2/shell.hxx"))
298 // TODO, need to remove this from the .sdi file too
299 if (fqn
== "SfxObjectShell::StateView_Impl")
301 // SFX_DECL_CHILDWINDOW_WITHID macro
302 if (loplugin::isSamePathname(fn
, SRCDIR
"/include/sfx2/infobar.hxx"))
304 // this looks like vaguely useful code (ParseError) that I'm loathe to remove
305 if (loplugin::isSamePathname(fn
, SRCDIR
"/slideshow/source/inc/slideshowexceptions.hxx"))
307 // SFX_DECL_VIEWFACTORY macro
308 if (loplugin::isSamePathname(fn
, SRCDIR
"/starmath/inc/view.hxx"))
311 if (fqn
== "BrowseBox::DoShowCursor" || fqn
== "BrowseBox::DoHideCursor")
313 // if I change this one, it then overrides a superclass virtual method
314 if (fqn
== "GalleryBrowser2::KeyInput")
316 // takes pointer to function
317 if (fqn
== "cmis::AuthProvider::onedriveAuthCodeFallback" || fqn
== "cmis::AuthProvider::gdriveAuthCodeFallback")
319 if (fqn
== "ooo_mount_operation_ask_password")
321 // TODO tricky to remove because of default params
322 if (fqn
== "xmloff::OAttribute2Property::addBooleanProperty")
324 // taking pointer to function
325 if (fqn
== "sw::DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl"
326 || fqn
== "sw::DocumentContentOperationsManager::DeleteRangeImpl"
327 || fqn
== "SwTableFormula::GetFormulaBoxes"
328 || fqn
== "SwFEShell::Drag"
329 || fqn
== "GetASCWriter" || fqn
== "GetHTMLWriter" || fqn
== "GetXMLWriter"
330 || fqn
== "SwWrtShell::UpdateLayoutFrame" || fqn
== "SwWrtShell::DefaultDrag"
331 || fqn
== "SwWrtShell::DefaultEndDrag"
332 || startswith(fqn
, "SwWW8ImplReader::Read_"))
335 if (fqn
== "SwFntObj::GuessLeading")
337 // SFX_DECL_CHILDWINDOW_WITHID macro
338 if (fqn
== "SwSpellDialogChildWindow::SwSpellDialogChildWindow"
339 || fqn
== "SwFieldDlgWrapper::SwFieldDlgWrapper"
340 || fqn
== "SwInputChild::SwInputChild")
342 // SFX_DECL_VIEWFACTORY macro
343 if (fqn
== "SwSrcView::SwSrcView")
345 // Serves to disambiguate two very similar methods
346 if (fqn
== "MSWordStyles::BuildGetSlot")
348 // TODO there are just too many default params to make this worth fixing right now
349 if (fqn
== "ScDocument::CopyMultiRangeFromClip")
351 // TODO looks like this needs fixing?
352 if (fqn
== "ScTable::ExtendPrintArea")
354 // there is a FIXME in the code
355 if (fqn
== "ScRangeUtil::IsAbsTabArea")
357 // SFX_DECL_CHILDWINDOW_WITHID
358 if (fqn
== "ScInputWindowWrapper::ScInputWindowWrapper"
359 || fqn
== "sc::SearchResultsDlgWrapper::SearchResultsDlgWrapper")
361 // ExecMethod in .sdi file
362 if (fqn
== "ScChartShell::ExecuteExportAsGraphic")
364 // bool marker parameter
365 if (fqn
== "SvxIconReplacementDialog::SvxIconReplacementDialog")
367 // used as pointer to fn
368 if (endswith(fqn
, "_createInstance"))
371 if (startswith(fqn
, "SbRtl_"))
373 // takes pointer to fn
374 if (fqn
== "migration::BasicMigration_create" || fqn
== "migration::WordbookMigration_create"
375 || fqn
== "comp_CBlankNode::_create" || fqn
== "comp_CURI::_create"
376 || fqn
== "comp_CLiteral::_create" || fqn
== "CDocumentBuilder::_getInstance"
377 || fqn
== "DOM::CDocumentBuilder::_getInstance"
378 || fqn
== "xml_security::serial_number_adapter::create"
379 || fqn
== "desktop::splash::create" || fqn
== "ScannerManager_CreateInstance"
380 || fqn
== "formula::FormulaOpCodeMapperObj::create"
381 || fqn
== "(anonymous namespace)::createInstance"
382 || fqn
== "x_error_handler"
383 || fqn
== "warning_func"
384 || fqn
== "error_func"
385 || fqn
== "ScaDateAddIn_CreateInstance"
386 || fqn
== "ScaPricingAddIn_CreateInstance"
387 || fqn
== "(anonymous namespace)::PDFSigningPKCS7PasswordCallback"
388 || fqn
== "ContextMenuEventLink"
389 || fqn
== "DelayedCloseEventLink"
390 || fqn
== "GDIMetaFile::ImplColMonoFnc"
391 || fqn
== "vcl::getGlyph0"
392 || fqn
== "vcl::getGlyph6"
393 || fqn
== "vcl::getGlyph12"
394 || fqn
== "setPasswordCallback"
395 || fqn
== "VCLExceptionSignal_impl"
396 || fqn
== "getFontTable"
397 || fqn
== "textconversiondlgs::ChineseTranslation_UnoDialog::create"
398 || fqn
== "pcr::DefaultHelpProvider::Create"
399 || fqn
== "pcr::DefaultFormComponentInspectorModel::Create"
400 || fqn
== "pcr::ObjectInspectorModel::Create"
401 || fqn
== "GraphicExportFilter::GraphicExportFilter"
402 || fqn
== "CertificateContainer::CertificateContainer"
403 || startswith(fqn
, "ParseCSS1_")
407 if (fqn
== "FontSubsetInfo::CreateFontSubsetFromType1")
409 // used in template magic
410 if (fqn
== "MtfRenderer::MtfRenderer" || fqn
== "shell::sessioninstall::SyncDbusSessionHelper::SyncDbusSessionHelper"
411 || fqn
== "dp_gui::LicenseDialog::LicenseDialog"
412 || fqn
== "(anonymous namespace)::OGLTransitionFactoryImpl::OGLTransitionFactoryImpl")
415 if (fqn
== "GtkSalDisplay::filterGdkEvent" || fqn
== "SvXMLEmbeddedObjectHelper::ImplReadObject"
416 || fqn
== "chart::CachedDataSequence::CachedDataSequence")
419 if (fqn
== "framework::MediaTypeDetectionHelper::MediaTypeDetectionHelper"
420 || fqn
== "framework::UriAbbreviation::UriAbbreviation"
421 || fqn
== "framework::DispatchDisabler::DispatchDisabler"
422 || fqn
== "framework::DispatchRecorderSupplier::DispatchRecorderSupplier")
424 // TODO Armin Le Grand is still working on this
425 if (fqn
== "svx::frame::CreateDiagFrameBorderPrimitives"
426 || fqn
== "svx::frame::CreateBorderPrimitives")
428 // marked with a TODO
429 if (fqn
== "pcr::FormLinkDialog::getExistingRelation"
430 || fqn
== "ooo::vba::DebugHelper::basicexception"
431 || fqn
== "ScPrintFunc::DrawToDev")
434 if (fqn
== "msfilter::lcl_PrintDigest")
436 // TODO something wrong here, the method that calls this (Normal::GenSlidingWindowFunction) cannot be correct
437 if (fqn
== "sc::opencl::OpBase::Gen")
439 // Can't change this without conflicting with another constructor with the same signature
440 if (fqn
== "XclExpSupbook::XclExpSupbook")
442 // ignore the LINK macros from include/tools/link.hxx
443 if (decl
->getLocation().isMacroID())
446 if (fqn
== "lcl_dbg_out")
449 for( auto it
= decl
->param_begin(); it
!= decl
->param_end(); ++it
) {
451 if (param
->hasAttr
<UnusedAttr
>())
453 if (!param
->getName().empty())
455 // ignore params which are enum types with only a single enumerator, these are marker/tag types
456 auto paramType
= param
->getType();
457 if (paramType
->isEnumeralType()) {
458 auto enumType
= paramType
->getAs
<EnumType
>();
459 int cnt
= std::distance(enumType
->getDecl()->enumerator_begin(), enumType
->getDecl()->enumerator_end());
463 // ignore params which are a reference to a struct which has no fields.
465 // (a) marker/tag types
466 // (b) selective "friend" access
467 if (paramType
->isReferenceType()) {
468 auto referenceType
= paramType
->getAs
<ReferenceType
>();
469 if (referenceType
->getPointeeType()->isRecordType()) {
470 auto recordType
= referenceType
->getPointeeType()->getAs
<RecordType
>();
471 if (noFieldsInRecord(recordType
) == 0)
475 else if (paramType
->isRecordType()) {
476 if (noFieldsInRecord(paramType
->getAs
<RecordType
>()) == 0)
479 report( DiagnosticsEngine::Warning
,
480 "unused param %0 in %1", compat::getBeginLoc(param
))
481 << param
->getSourceRange()
486 unsigned idx
= param
->getFunctionScopeIndex();
487 const ParmVarDecl
* pOther
= canon
->getParamDecl(idx
);
488 report( DiagnosticsEngine::Note
, "declaration is here",
489 compat::getBeginLoc(pOther
))
490 << pOther
->getSourceRange();
496 loplugin::Plugin::Registration
<CheckUnusedParams
> X("checkunusedparams", false);
500 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */