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 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);
|
||||||
|
@ -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)
|
||||||
|
@ -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: */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user