Avoid some false loplugin:redundantfcast involving std::function and lambdas

Change-Id: Id9a93fb60f957d75450deb93f1461b1d9dacf8ca
Reviewed-on: https://gerrit.libreoffice.org/78860
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
This commit is contained in:
Stephan Bergmann 2019-09-13 08:31:20 +02:00
parent eefd7c12f7
commit d27e70fce2
3 changed files with 98 additions and 2 deletions

View File

@ -87,6 +87,8 @@ public:
inline ContextCheck Struct(llvm::StringRef id) const; inline ContextCheck Struct(llvm::StringRef id) const;
inline ContextCheck ClassOrStruct(llvm::StringRef id) const;
inline ContextCheck Union(llvm::StringRef id) const; inline ContextCheck Union(llvm::StringRef id) const;
inline ContextCheck Function(llvm::StringRef id) const; inline ContextCheck Function(llvm::StringRef id) const;
@ -212,6 +214,15 @@ ContextCheck DeclCheck::Struct(llvm::StringRef id) const
return detail::checkRecordDecl(decl_, clang::TTK_Struct, id); return detail::checkRecordDecl(decl_, clang::TTK_Struct, id);
} }
ContextCheck DeclCheck::ClassOrStruct(llvm::StringRef id) const
{
auto const c1 = Class(id);
if (c1) {
return c1;
}
return Struct(id);
}
ContextCheck DeclCheck::Union(llvm::StringRef id) const ContextCheck DeclCheck::Union(llvm::StringRef id) const
{ {
return detail::checkRecordDecl(decl_, clang::TTK_Union, id); return detail::checkRecordDecl(decl_, clang::TTK_Union, id);

View File

@ -14,6 +14,7 @@
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <unordered_set> #include <unordered_set>
#include <vector>
namespace namespace
{ {
@ -165,12 +166,87 @@ public:
// Find redundant cast to std::function, where clang reports // Find redundant cast to std::function, where clang reports
// two different types for the inner and outer // two different types for the inner and outer
static bool isRedundantStdFunctionCast(CXXFunctionalCastExpr const* expr) bool isRedundantStdFunctionCast(CXXFunctionalCastExpr const* expr)
{ {
bool deduced = false;
QualType target;
auto const written = expr->getTypeAsWritten();
if (auto const t1 = written->getAs<DeducedTemplateSpecializationType>())
{
auto const decl = t1->getTemplateName().getAsTemplateDecl();
if (!decl)
{
return false;
}
if (!loplugin::DeclCheck(decl->getTemplatedDecl())
.ClassOrStruct("function")
.StdNamespace())
{
return false;
}
deduced = true;
}
else if (auto const t2 = written->getAs<TemplateSpecializationType>())
{
auto const decl = t2->getTemplateName().getAsTemplateDecl();
if (!decl)
{
return false;
}
if (!loplugin::DeclCheck(decl->getTemplatedDecl())
.ClassOrStruct("function")
.StdNamespace())
{
return false;
}
if (t2->getNumArgs() != 1)
{
if (isDebugMode())
{
report(DiagnosticsEngine::Fatal,
"TODO: unexpected std::function with %0 template arguments",
expr->getExprLoc())
<< t2->getNumArgs() << expr->getSourceRange();
}
return false;
}
if (t2->getArg(0).getKind() != TemplateArgument::Type)
{
if (isDebugMode())
{
report(DiagnosticsEngine::Fatal,
"TODO: unexpected std::function with non-type template argument",
expr->getExprLoc())
<< expr->getSourceRange();
}
return false;
}
target = t2->getArg(0).getAsType();
}
else
{
return false;
}
auto cxxConstruct = dyn_cast<CXXConstructExpr>(compat::IgnoreImplicit(expr->getSubExpr())); auto cxxConstruct = dyn_cast<CXXConstructExpr>(compat::IgnoreImplicit(expr->getSubExpr()));
if (!cxxConstruct) if (!cxxConstruct)
return false; return false;
return isa<LambdaExpr>(cxxConstruct->getArg(0)); auto const lambda = dyn_cast<LambdaExpr>(cxxConstruct->getArg(0));
if (!lambda)
return false;
if (deduced)
// std::function([...](Args)->Ret{...}) should always be redundant:
return true;
auto const decl = lambda->getCallOperator();
std::vector<QualType> args;
for (unsigned i = 0; i != decl->getNumParams(); ++i)
{
args.push_back(decl->getParamDecl(i)->getType());
}
auto const source
= compiler.getASTContext().getFunctionType(decl->getReturnType(), args, {});
// std::function<Ret1(Args1)>([...](Args2)->Ret2{...}) is redundant if target Ret1(Args1)
// matches source Ret2(Args2):
return target.getCanonicalType() == source.getCanonicalType();
} }
bool VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr const* expr) bool VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr const* expr)

View File

@ -95,5 +95,14 @@ void f2()
f1(std::function([&]() {})); f1(std::function([&]() {}));
} }
}; };
namespace test6
{
void f1(std::function<void(int)>);
void f1(std::function<void(long)>);
void f2()
{
f1(std::function<void(long)>([&](int) {})); // should not warn here
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */