[Libreoffice-commits] core.git: compilerplugins/clang

Stephan Bergmann (via logerrit) logerrit at kemper.freedesktop.org
Fri Sep 13 07:27:57 UTC 2019


 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 <sbergman at redhat.com>
AuthorDate: Fri Sep 13 08:31:20 2019 +0200
Commit:     Stephan Bergmann <sbergman at 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 <sbergman at 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: */


More information about the Libreoffice-commits mailing list