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 overridden methods that :
19 (a) declare default params in different palces to their super-method(s)
22 (b) Find places where the values of the default parameters are different
23 (c) Find places where the names of the parameters differ
29 public RecursiveASTVisitor
<OverrideParam
>, public loplugin::Plugin
32 explicit OverrideParam(loplugin::InstantiationData
const & data
):
35 virtual void run() override
;
37 bool VisitCXXMethodDecl(const CXXMethodDecl
*);
40 bool hasSameDefaultParams(const ParmVarDecl
* parmVarDecl
, const ParmVarDecl
* superParmVarDecl
);
43 void OverrideParam::run()
46 StringRef fn( compiler.getSourceManager().getFileEntryForID(
47 compiler.getSourceManager().getMainFileID())->getName() );
48 if (fn == SRCDIR "/include/svx/checklbx.hxx")
51 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
54 bool OverrideParam::VisitCXXMethodDecl(const CXXMethodDecl
* methodDecl
) {
55 if (ignoreLocation(methodDecl
)) {
58 if (methodDecl
->isThisDeclarationADefinition() || methodDecl
->size_overridden_methods() == 0) {
61 loplugin::DeclCheck
dc(methodDecl
);
62 // there is an InsertEntry override here which causes trouble if I modify it
63 if (dc
.Function("InsertEntry").Class("SvxCheckListBox").GlobalNamespace()) {
66 // This class is overriding ShowCursor(bool) AND declaring a ShowCursor() method.
67 // Adding a default param causes 'ambiguous override'.
68 if (dc
.Function("ShowCursor").Class("ScTabViewShell").GlobalNamespace()) {
72 for(auto superMethodIt
= methodDecl
->begin_overridden_methods();
73 superMethodIt
!= methodDecl
->end_overridden_methods(); ++superMethodIt
)
75 const CXXMethodDecl
* superMethodDecl
= *superMethodIt
;
76 if (ignoreLocation(superMethodDecl
)) {
80 for (const ParmVarDecl
*superParmVarDecl
: compat::parameters(*superMethodDecl
)) {
81 const ParmVarDecl
*parmVarDecl
= methodDecl
->getParamDecl(i
);
82 if (parmVarDecl
->hasDefaultArg() && !superParmVarDecl
->hasDefaultArg()) {
84 DiagnosticsEngine::Warning
,
85 "overridden method declaration has default arg, but super-method does not",
86 parmVarDecl
->getSourceRange().getBegin())
87 << parmVarDecl
->getSourceRange();
89 DiagnosticsEngine::Note
,
90 "original param here",
91 superParmVarDecl
->getSourceRange().getBegin())
92 << superParmVarDecl
->getSourceRange();
94 else if (!parmVarDecl
->hasDefaultArg() && superParmVarDecl
->hasDefaultArg()) {
96 DiagnosticsEngine::Warning
,
97 "overridden method declaration has no default arg, but super-method does",
98 parmVarDecl
->getSourceRange().getBegin())
99 << parmVarDecl
->getSourceRange();
101 DiagnosticsEngine::Note
,
102 "original param here",
103 superParmVarDecl
->getSourceRange().getBegin())
104 << superParmVarDecl
->getSourceRange();
106 else if (parmVarDecl
->hasDefaultArg() && superParmVarDecl
->hasDefaultArg()
107 && !hasSameDefaultParams(parmVarDecl
, superParmVarDecl
)) {
109 DiagnosticsEngine::Warning
,
110 "overridden method declaration has different default param to super-method",
111 parmVarDecl
->getSourceRange().getBegin())
112 << parmVarDecl
->getSourceRange();
114 DiagnosticsEngine::Note
,
115 "original param here",
116 superParmVarDecl
->getSourceRange().getBegin())
117 << superParmVarDecl
->getSourceRange();
119 /* do nothing for now, will enable this in a later commit
120 if (methodDecl->isThisDeclarationADefinition() && parmVarDecl->getName().empty()) {
121 // ignore this - means the param is unused
123 else if (superParmVarDecl->getName().empty()) {
124 // ignore, nothing reasonable I can do
126 else if (superParmVarDecl->getName() != parmVarDecl->getName()) {
128 DiagnosticsEngine::Warning,
129 "overridden method declaration uses different name for parameter",
130 parmVarDecl->getSourceRange().getBegin())
131 << parmVarDecl->getSourceRange();
133 DiagnosticsEngine::Note,
134 "original param here",
135 superParmVarDecl->getSourceRange().getBegin())
136 << superParmVarDecl->getSourceRange();
144 bool OverrideParam::hasSameDefaultParams(const ParmVarDecl
* parmVarDecl
, const ParmVarDecl
* superParmVarDecl
)
146 // don't know what this means, but it prevents a clang crash
147 if (parmVarDecl
->hasUninstantiatedDefaultArg() || superParmVarDecl
->hasUninstantiatedDefaultArg()) {
151 checkIdenticalDefaultArguments(
152 parmVarDecl
->getDefaultArg(), superParmVarDecl
->getDefaultArg())
153 != IdenticalDefaultArgumentsResult::No
;
154 // for one, Clang 3.8 doesn't have EvaluateAsFloat; for another, since
155 // <http://llvm.org/viewvc/llvm-project?view=revision&revision=291318>
156 // "PR23135: Don't instantiate constexpr functions referenced in
157 // unevaluated operands where possible", default args are not
158 // necessarily evaluated, so the above calls to EvaluateAsInt etc. may
159 // fail (as they do e.g. for SfxViewShell::SetPrinter and derived
160 // classes' 'SfxPrinterChangeFlags nDiffFlags = SFX_PRINTER_ALL' arg,
161 // include/sfx2/viewsh.hxx; what appears would help is to call
162 // 'compiler.getSema().MarkDeclarationsReferencedInExpr()' on
163 // defaultArgExpr and superDefaultArgExpr before any of the calls to
164 // EvaluateAsInt etc., cf. the implementation of
165 // Sema::CheckCXXDefaultArgExpr in Clang's lib/Sema/SemaExpr.cpp, but
166 // that would probably have unwanted side-effects)
169 loplugin::Plugin::Registration
< OverrideParam
> X("overrideparam");
173 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */