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/.
9 #ifndef LO_CLANG_SHARED_PLUGINS
18 Find overridden methods that :
19 (a) declare default params in different places 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 loplugin::FilteringPlugin
<OverrideParam
>
32 explicit OverrideParam(loplugin::InstantiationData
const & data
):
33 FilteringPlugin(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 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
49 bool OverrideParam::VisitCXXMethodDecl(const CXXMethodDecl
* methodDecl
) {
50 if (ignoreLocation(methodDecl
)) {
53 if (methodDecl
->isThisDeclarationADefinition() || methodDecl
->size_overridden_methods() == 0) {
56 loplugin::DeclCheck
dc(methodDecl
);
57 // This class is overriding ShowCursor(bool) AND declaring a ShowCursor() method.
58 // Adding a default param causes 'ambiguous override'.
59 if (dc
.Function("ShowCursor").Class("ScTabViewShell").GlobalNamespace()) {
63 for(auto superMethodIt
= methodDecl
->begin_overridden_methods();
64 superMethodIt
!= methodDecl
->end_overridden_methods(); ++superMethodIt
)
66 const CXXMethodDecl
* superMethodDecl
= *superMethodIt
;
67 if (ignoreLocation(superMethodDecl
)) {
71 for (const ParmVarDecl
*superParmVarDecl
: superMethodDecl
->parameters()) {
72 const ParmVarDecl
*parmVarDecl
= methodDecl
->getParamDecl(i
);
73 if (parmVarDecl
->hasDefaultArg() && !superParmVarDecl
->hasDefaultArg()) {
75 DiagnosticsEngine::Warning
,
76 "overridden method declaration has default arg, but super-method does not",
77 parmVarDecl
->getSourceRange().getBegin())
78 << parmVarDecl
->getSourceRange();
80 DiagnosticsEngine::Note
,
81 "original param here",
82 superParmVarDecl
->getSourceRange().getBegin())
83 << superParmVarDecl
->getSourceRange();
85 else if (!parmVarDecl
->hasDefaultArg() && superParmVarDecl
->hasDefaultArg()) {
87 DiagnosticsEngine::Warning
,
88 "overridden method declaration has no default arg, but super-method does",
89 parmVarDecl
->getSourceRange().getBegin())
90 << parmVarDecl
->getSourceRange();
92 DiagnosticsEngine::Note
,
93 "original param here",
94 superParmVarDecl
->getSourceRange().getBegin())
95 << superParmVarDecl
->getSourceRange();
97 else if (parmVarDecl
->hasDefaultArg() && superParmVarDecl
->hasDefaultArg()
98 && !hasSameDefaultParams(parmVarDecl
, superParmVarDecl
)) {
100 DiagnosticsEngine::Warning
,
101 "overridden method declaration has different default param to super-method",
102 parmVarDecl
->getSourceRange().getBegin())
103 << parmVarDecl
->getSourceRange();
105 DiagnosticsEngine::Note
,
106 "original param here",
107 superParmVarDecl
->getSourceRange().getBegin())
108 << superParmVarDecl
->getSourceRange();
110 /* do nothing for now, will enable this in a later commit
111 if (methodDecl->isThisDeclarationADefinition() && parmVarDecl->getName().empty()) {
112 // ignore this - means the param is unused
114 else if (superParmVarDecl->getName().empty()) {
115 // ignore, nothing reasonable I can do
117 else if (superParmVarDecl->getName() != parmVarDecl->getName()) {
119 DiagnosticsEngine::Warning,
120 "overridden method declaration uses different name for parameter",
121 parmVarDecl->getSourceRange().getBegin())
122 << parmVarDecl->getSourceRange();
124 DiagnosticsEngine::Note,
125 "original param here",
126 superParmVarDecl->getSourceRange().getBegin())
127 << superParmVarDecl->getSourceRange();
135 bool OverrideParam::hasSameDefaultParams(const ParmVarDecl
* parmVarDecl
, const ParmVarDecl
* superParmVarDecl
)
137 // don't know what this means, but it prevents a clang crash
138 if (parmVarDecl
->hasUninstantiatedDefaultArg() || superParmVarDecl
->hasUninstantiatedDefaultArg()) {
142 checkIdenticalDefaultArguments(
143 parmVarDecl
->getDefaultArg(), superParmVarDecl
->getDefaultArg())
144 != IdenticalDefaultArgumentsResult::No
;
145 // for one, Clang 3.8 doesn't have EvaluateAsFloat; for another, since
146 // <http://llvm.org/viewvc/llvm-project?view=revision&revision=291318>
147 // "PR23135: Don't instantiate constexpr functions referenced in
148 // unevaluated operands where possible", default args are not
149 // necessarily evaluated, so the above calls to EvaluateAsInt etc. may
150 // fail (as they do e.g. for SfxViewShell::SetPrinter and derived
151 // classes' 'SfxPrinterChangeFlags nDiffFlags = SFX_PRINTER_ALL' arg,
152 // include/sfx2/viewsh.hxx; what appears would help is to call
153 // 'compiler.getSema().MarkDeclarationsReferencedInExpr()' on
154 // defaultArgExpr and superDefaultArgExpr before any of the calls to
155 // EvaluateAsInt etc., cf. the implementation of
156 // Sema::CheckCXXDefaultArgExpr in Clang's lib/Sema/SemaExpr.cpp, but
157 // that would probably have unwanted side-effects)
160 loplugin::Plugin::Registration
< OverrideParam
> overrideparam("overrideparam");
164 #endif // LO_CLANG_SHARED_PLUGINS
166 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */