summaryrefslogtreecommitdiffstats
path: root/compilerplugins/clang/overrideparam.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'compilerplugins/clang/overrideparam.cxx')
-rw-r--r--compilerplugins/clang/overrideparam.cxx166
1 files changed, 166 insertions, 0 deletions
diff --git a/compilerplugins/clang/overrideparam.cxx b/compilerplugins/clang/overrideparam.cxx
new file mode 100644
index 000000000..61efe15b1
--- /dev/null
+++ b/compilerplugins/clang/overrideparam.cxx
@@ -0,0 +1,166 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#ifndef LO_CLANG_SHARED_PLUGINS
+
+#include <string>
+#include <set>
+
+#include "plugin.hxx"
+#include "check.hxx"
+
+/*
+ Find overridden methods that :
+ (a) declare default params in different places to their super-method(s)
+
+ Still TODO
+ (b) Find places where the values of the default parameters are different
+ (c) Find places where the names of the parameters differ
+*/
+
+namespace {
+
+class OverrideParam:
+ public loplugin::FilteringPlugin<OverrideParam>
+{
+public:
+ explicit OverrideParam(loplugin::InstantiationData const & data):
+ FilteringPlugin(data) {}
+
+ virtual void run() override;
+
+ bool VisitCXXMethodDecl(const CXXMethodDecl *);
+
+private:
+ bool hasSameDefaultParams(const ParmVarDecl * parmVarDecl, const ParmVarDecl * superParmVarDecl);
+};
+
+void OverrideParam::run()
+{
+ if (preRun())
+ TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
+}
+
+bool OverrideParam::VisitCXXMethodDecl(const CXXMethodDecl * methodDecl) {
+ if (ignoreLocation(methodDecl)) {
+ return true;
+ }
+ if (methodDecl->isThisDeclarationADefinition() || methodDecl->size_overridden_methods() == 0) {
+ return true;
+ }
+ loplugin::DeclCheck dc(methodDecl);
+ // This class is overriding ShowCursor(bool) AND declaring a ShowCursor() method.
+ // Adding a default param causes 'ambiguous override'.
+ if (dc.Function("ShowCursor").Class("ScTabViewShell").GlobalNamespace()) {
+ return true;
+ }
+
+ for(auto superMethodIt = methodDecl->begin_overridden_methods();
+ superMethodIt != methodDecl->end_overridden_methods(); ++superMethodIt)
+ {
+ const CXXMethodDecl * superMethodDecl = *superMethodIt;
+ if (ignoreLocation(superMethodDecl)) {
+ continue;
+ }
+ int i = 0;
+ for (const ParmVarDecl *superParmVarDecl : superMethodDecl->parameters()) {
+ const ParmVarDecl *parmVarDecl = methodDecl->getParamDecl(i);
+ if (parmVarDecl->hasDefaultArg() && !superParmVarDecl->hasDefaultArg()) {
+ report(
+ DiagnosticsEngine::Warning,
+ "overridden method declaration has default arg, but super-method does not",
+ parmVarDecl->getSourceRange().getBegin())
+ << parmVarDecl->getSourceRange();
+ report(
+ DiagnosticsEngine::Note,
+ "original param here",
+ superParmVarDecl->getSourceRange().getBegin())
+ << superParmVarDecl->getSourceRange();
+ }
+ else if (!parmVarDecl->hasDefaultArg() && superParmVarDecl->hasDefaultArg()) {
+ report(
+ DiagnosticsEngine::Warning,
+ "overridden method declaration has no default arg, but super-method does",
+ parmVarDecl->getSourceRange().getBegin())
+ << parmVarDecl->getSourceRange();
+ report(
+ DiagnosticsEngine::Note,
+ "original param here",
+ superParmVarDecl->getSourceRange().getBegin())
+ << superParmVarDecl->getSourceRange();
+ }
+ else if (parmVarDecl->hasDefaultArg() && superParmVarDecl->hasDefaultArg()
+ && !hasSameDefaultParams(parmVarDecl, superParmVarDecl)) {
+ report(
+ DiagnosticsEngine::Warning,
+ "overridden method declaration has different default param to super-method",
+ parmVarDecl->getSourceRange().getBegin())
+ << parmVarDecl->getSourceRange();
+ report(
+ DiagnosticsEngine::Note,
+ "original param here",
+ superParmVarDecl->getSourceRange().getBegin())
+ << superParmVarDecl->getSourceRange();
+ }
+ /* do nothing for now, will enable this in a later commit
+ if (methodDecl->isThisDeclarationADefinition() && parmVarDecl->getName().empty()) {
+ // ignore this - means the param is unused
+ }
+ else if (superParmVarDecl->getName().empty()) {
+ // ignore, nothing reasonable I can do
+ }
+ else if (superParmVarDecl->getName() != parmVarDecl->getName()) {
+ report(
+ DiagnosticsEngine::Warning,
+ "overridden method declaration uses different name for parameter",
+ parmVarDecl->getSourceRange().getBegin())
+ << parmVarDecl->getSourceRange();
+ report(
+ DiagnosticsEngine::Note,
+ "original param here",
+ superParmVarDecl->getSourceRange().getBegin())
+ << superParmVarDecl->getSourceRange();
+ }*/
+ ++i;
+ }
+ }
+ return true;
+}
+
+bool OverrideParam::hasSameDefaultParams(const ParmVarDecl * parmVarDecl, const ParmVarDecl * superParmVarDecl)
+{
+ // don't know what this means, but it prevents a clang crash
+ if (parmVarDecl->hasUninstantiatedDefaultArg() || superParmVarDecl->hasUninstantiatedDefaultArg()) {
+ return true;
+ }
+ return
+ checkIdenticalDefaultArguments(
+ parmVarDecl->getDefaultArg(), superParmVarDecl->getDefaultArg())
+ != IdenticalDefaultArgumentsResult::No;
+ // for one, Clang 3.8 doesn't have EvaluateAsFloat; for another, since
+ // <http://llvm.org/viewvc/llvm-project?view=revision&revision=291318>
+ // "PR23135: Don't instantiate constexpr functions referenced in
+ // unevaluated operands where possible", default args are not
+ // necessarily evaluated, so the above calls to EvaluateAsInt etc. may
+ // fail (as they do e.g. for SfxViewShell::SetPrinter and derived
+ // classes' 'SfxPrinterChangeFlags nDiffFlags = SFX_PRINTER_ALL' arg,
+ // include/sfx2/viewsh.hxx; what appears would help is to call
+ // 'compiler.getSema().MarkDeclarationsReferencedInExpr()' on
+ // defaultArgExpr and superDefaultArgExpr before any of the calls to
+ // EvaluateAsInt etc., cf. the implementation of
+ // Sema::CheckCXXDefaultArgExpr in Clang's lib/Sema/SemaExpr.cpp, but
+ // that would probably have unwanted side-effects)
+}
+
+loplugin::Plugin::Registration< OverrideParam > overrideparam("overrideparam");
+
+} // namespace
+
+#endif // LO_CLANG_SHARED_PLUGINS
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */