libreoffice/compilerplugins/clang/overrideparam.cxx
Andrea Gelmini 6fab286b2a Fix typos
Change-Id: I4f16ba5fc32cbfd6a5b01e495f3ad905da193524
Reviewed-on: https://gerrit.libreoffice.org/34808
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Tested-by: Noel Grandin <noel.grandin@collabora.co.uk>
2017-03-03 07:42:39 +00:00

216 lines
8.3 KiB
C++

/* -*- 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 overridden 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);
bool evaluate(const Expr* expr, APSInt& x);
};
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)) {
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;
}
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 (evaluate(defaultArgExpr, x1) && evaluate(superDefaultArgExpr, x2))
{
return x1 == x2;
}
#if CLANG_VERSION >= 30900
APFloat f1(0.0f), f2(0.0f);
if (defaultArgExpr->EvaluateAsFloat(f1, compiler.getASTContext())
&& superDefaultArgExpr->EvaluateAsFloat(f2, compiler.getASTContext()))
{
return f1.bitwiseIsEqual(f2);
}
#endif
// catch params with defaults like "= OUString()"
if (isa<MaterializeTemporaryExpr>(defaultArgExpr)
&& isa<MaterializeTemporaryExpr>(superDefaultArgExpr))
{
return true;
}
if (isa<CXXBindTemporaryExpr>(defaultArgExpr)
&& isa<CXXBindTemporaryExpr>(superDefaultArgExpr))
{
return true;
}
return true;
// 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)
}
bool OverrideParam::evaluate(const Expr* expr, APSInt& x)
{
if (expr->EvaluateAsInt(x, compiler.getASTContext()))
{
return true;
}
if (isa<CXXNullPtrLiteralExpr>(expr)) {
x = 0;
return true;
}
return false;
}
loplugin::Plugin::Registration< OverrideParam > X("overrideparam");
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */