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:
parent
eefd7c12f7
commit
d27e70fce2
@ -87,6 +87,8 @@ public:
|
||||
|
||||
inline ContextCheck Struct(llvm::StringRef id) const;
|
||||
|
||||
inline ContextCheck ClassOrStruct(llvm::StringRef id) const;
|
||||
|
||||
inline ContextCheck Union(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);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return detail::checkRecordDecl(decl_, clang::TTK_Union, id);
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -165,12 +166,87 @@ public:
|
||||
|
||||
// Find redundant cast to std::function, where clang reports
|
||||
// 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()));
|
||||
if (!cxxConstruct)
|
||||
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)
|
||||
|
@ -95,5 +95,14 @@ void f2()
|
||||
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: */
|
||||
|
Loading…
x
Reference in New Issue
Block a user