Update git submodules
[LibreOffice.git] / compilerplugins / clang / overrideparam.cxx
blob61efe15b1eb095847beafdea8b60927b54320734
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
9 #ifndef LO_CLANG_SHARED_PLUGINS
11 #include <string>
12 #include <set>
14 #include "plugin.hxx"
15 #include "check.hxx"
18 Find overridden methods that :
19 (a) declare default params in different places to their super-method(s)
21 Still TODO
22 (b) Find places where the values of the default parameters are different
23 (c) Find places where the names of the parameters differ
26 namespace {
28 class OverrideParam:
29 public loplugin::FilteringPlugin<OverrideParam>
31 public:
32 explicit OverrideParam(loplugin::InstantiationData const & data):
33 FilteringPlugin(data) {}
35 virtual void run() override;
37 bool VisitCXXMethodDecl(const CXXMethodDecl *);
39 private:
40 bool hasSameDefaultParams(const ParmVarDecl * parmVarDecl, const ParmVarDecl * superParmVarDecl);
43 void OverrideParam::run()
45 if (preRun())
46 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
49 bool OverrideParam::VisitCXXMethodDecl(const CXXMethodDecl * methodDecl) {
50 if (ignoreLocation(methodDecl)) {
51 return true;
53 if (methodDecl->isThisDeclarationADefinition() || methodDecl->size_overridden_methods() == 0) {
54 return true;
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()) {
60 return true;
63 for(auto superMethodIt = methodDecl->begin_overridden_methods();
64 superMethodIt != methodDecl->end_overridden_methods(); ++superMethodIt)
66 const CXXMethodDecl * superMethodDecl = *superMethodIt;
67 if (ignoreLocation(superMethodDecl)) {
68 continue;
70 int i = 0;
71 for (const ParmVarDecl *superParmVarDecl : superMethodDecl->parameters()) {
72 const ParmVarDecl *parmVarDecl = methodDecl->getParamDecl(i);
73 if (parmVarDecl->hasDefaultArg() && !superParmVarDecl->hasDefaultArg()) {
74 report(
75 DiagnosticsEngine::Warning,
76 "overridden method declaration has default arg, but super-method does not",
77 parmVarDecl->getSourceRange().getBegin())
78 << parmVarDecl->getSourceRange();
79 report(
80 DiagnosticsEngine::Note,
81 "original param here",
82 superParmVarDecl->getSourceRange().getBegin())
83 << superParmVarDecl->getSourceRange();
85 else if (!parmVarDecl->hasDefaultArg() && superParmVarDecl->hasDefaultArg()) {
86 report(
87 DiagnosticsEngine::Warning,
88 "overridden method declaration has no default arg, but super-method does",
89 parmVarDecl->getSourceRange().getBegin())
90 << parmVarDecl->getSourceRange();
91 report(
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)) {
99 report(
100 DiagnosticsEngine::Warning,
101 "overridden method declaration has different default param to super-method",
102 parmVarDecl->getSourceRange().getBegin())
103 << parmVarDecl->getSourceRange();
104 report(
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()) {
118 report(
119 DiagnosticsEngine::Warning,
120 "overridden method declaration uses different name for parameter",
121 parmVarDecl->getSourceRange().getBegin())
122 << parmVarDecl->getSourceRange();
123 report(
124 DiagnosticsEngine::Note,
125 "original param here",
126 superParmVarDecl->getSourceRange().getBegin())
127 << superParmVarDecl->getSourceRange();
129 ++i;
132 return true;
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()) {
139 return true;
141 return
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");
162 } // namespace
164 #endif // LO_CLANG_SHARED_PLUGINS
166 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */