diff options
author | Noel Grandin <noel@peralex.com> | 2016-07-22 14:35:27 +0200 |
---|---|---|
committer | Noel Grandin <noelgrandin@gmail.com> | 2016-07-25 06:09:17 +0000 |
commit | 938821fb08e427864db6a10642f385bde9803f6c (patch) | |
tree | 759da9d0d0905a90f6dac2f0bf750721c17421c4 /compilerplugins | |
parent | 4d4d77a1aad1bcae18bad35dad5308d33d6b2e51 (diff) |
new loplugin overrideparam
verify that parameters on override methods have the same set of default
values for their params as their parent/super-methods do.
Change-Id: Ibdbc1c6e417fbaa680ea025a6bbf5ba9c2e5bcd2
Reviewed-on: https://gerrit.libreoffice.org/27437
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Noel Grandin <noelgrandin@gmail.com>
Diffstat (limited to 'compilerplugins')
-rw-r--r-- | compilerplugins/clang/overrideparam.cxx | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/compilerplugins/clang/overrideparam.cxx b/compilerplugins/clang/overrideparam.cxx new file mode 100644 index 000000000000..c04165bbd8c2 --- /dev/null +++ b/compilerplugins/clang/overrideparam.cxx @@ -0,0 +1,179 @@ +/* -*- 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/. + */ + +#include <string> +#include <set> + +#include "plugin.hxx" +#include "compat.hxx" +#include "check.hxx" + +/* + Find overriden methods that : + (a) declare default params in different palces 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 RecursiveASTVisitor<OverrideParam>, public loplugin::Plugin +{ +public: + explicit OverrideParam(InstantiationData const & data): Plugin(data) {} + + virtual void run() override; + + bool VisitCXXMethodDecl(const CXXMethodDecl *); + +private: + bool hasSameDefaultParams(const ParmVarDecl * parmVarDecl, const ParmVarDecl * superParmVarDecl); +}; + +void OverrideParam::run() +{ + /* + StringRef fn( compiler.getSourceManager().getFileEntryForID( + compiler.getSourceManager().getMainFileID())->getName() ); + if (fn == SRCDIR "/include/svx/checklbx.hxx") + return; +*/ + 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); + // there is an InsertEntry override here which causes trouble if I modify it + if (dc.Function("InsertEntry").Class("SvxCheckListBox").GlobalNamespace()) { + return true; + } + // 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 : compat::parameters(*superMethodDecl)) { + 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)) { + /* do nothing for now, will enable this in a later commit + 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 false; + } + const Expr* defaultArgExpr = parmVarDecl->getDefaultArg(); + const Expr* superDefaultArgExpr = superParmVarDecl->getDefaultArg(); + + if (defaultArgExpr->isNullPointerConstant(compiler.getASTContext(), Expr::NPC_NeverValueDependent) + && superDefaultArgExpr->isNullPointerConstant(compiler.getASTContext(), Expr::NPC_NeverValueDependent)) + { + return true; + } + APSInt x1, x2; + if (defaultArgExpr->EvaluateAsInt(x1, compiler.getASTContext()) + && superDefaultArgExpr->EvaluateAsInt(x2, compiler.getASTContext())) + { + return x1 == x2; + } + // catch params with defaults like "= OUString()" + if (isa<MaterializeTemporaryExpr>(defaultArgExpr) + && isa<MaterializeTemporaryExpr>(superDefaultArgExpr)) + { + return true; + } + return false; +} + + +loplugin::Plugin::Registration< OverrideParam > X("overrideparam"); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |