compilerplugins/clang/check.hxx | 11 +++ compilerplugins/clang/redundantfcast.cxx | 80 +++++++++++++++++++++++++- compilerplugins/clang/test/redundantfcast.cxx | 9 ++ 3 files changed, 98 insertions(+), 2 deletions(-)
New commits: commit d27e70fce2acfc9b14f2f07c9096daa50dc2acd8 Author: Stephan Bergmann <sberg...@redhat.com> AuthorDate: Fri Sep 13 08:31:20 2019 +0200 Commit: Stephan Bergmann <sberg...@redhat.com> CommitDate: Fri Sep 13 09:27:20 2019 +0200 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 <sberg...@redhat.com> diff --git a/compilerplugins/clang/check.hxx b/compilerplugins/clang/check.hxx index 4ac4f8e99cb6..e027a5ca709f 100644 --- a/compilerplugins/clang/check.hxx +++ b/compilerplugins/clang/check.hxx @@ -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); diff --git a/compilerplugins/clang/redundantfcast.cxx b/compilerplugins/clang/redundantfcast.cxx index 8879a386d621..260fe1852417 100644 --- a/compilerplugins/clang/redundantfcast.cxx +++ b/compilerplugins/clang/redundantfcast.cxx @@ -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) diff --git a/compilerplugins/clang/test/redundantfcast.cxx b/compilerplugins/clang/test/redundantfcast.cxx index 9b377c97d395..985aa8c02994 100644 --- a/compilerplugins/clang/test/redundantfcast.cxx +++ b/compilerplugins/clang/test/redundantfcast.cxx @@ -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: */ _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits