[Libreoffice-commits] core.git: 2 commits - compilerplugins/clang solenv/CompilerTest_compilerplugins_clang.mk

Noel Grandin noel.grandin at collabora.co.uk
Thu Aug 17 11:21:49 UTC 2017


 compilerplugins/clang/convertuintptr.cxx       |  105 +++++++++++++
 compilerplugins/clang/droplong.cxx             |    2 
 compilerplugins/clang/passparamsbyref.cxx      |  195 +++++++++++++++++++++++++
 compilerplugins/clang/passstuffbyref.cxx       |  123 +--------------
 compilerplugins/clang/test/convertuintptr.cxx  |   20 ++
 compilerplugins/clang/test/passparamsbyref.cxx |   39 +++++
 solenv/CompilerTest_compilerplugins_clang.mk   |    2 
 7 files changed, 373 insertions(+), 113 deletions(-)

New commits:
commit d21b119df35ca43d3a4edeab2a809c345e0f617c
Author: Noel Grandin <noel.grandin at collabora.co.uk>
Date:   Thu Aug 17 12:50:30 2017 +0200

    loplugin:passstuffbyref ignore params that are assigned to
    
    makes writing nice code awkward sometimes.
    
    Also split plugin into two different plugins, the logic was getting
    tangled up.
    
    Change-Id: I232e314d29c766c160c29373988dc37a466505be

diff --git a/compilerplugins/clang/passparamsbyref.cxx b/compilerplugins/clang/passparamsbyref.cxx
new file mode 100644
index 000000000000..aa66d09ea3db
--- /dev/null
+++ b/compilerplugins/clang/passparamsbyref.cxx
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <string>
+#include <unordered_set>
+
+#include "check.hxx"
+#include "compat.hxx"
+#include "plugin.hxx"
+
+// Find places where parameters are passed by value
+// It's not very efficient, because we generally end up copying it twice - once into the parameter and
+// again into the destination.
+// They should rather be passed by reference.
+//
+// Generally recommending lambda capture by-ref rather than by-copy is even more
+// problematic than with function parameters, as a lambda instance can easily
+// outlive a referenced variable. So once lambdas start to get used in more
+// sophisticated ways than passing them into standard algorithms, this plugin's
+// advice, at least for explicit captures, will need to be revisited.
+
+namespace {
+
+class PassParamsByRef:
+    public RecursiveASTVisitor<PassParamsByRef>, public loplugin::Plugin
+{
+public:
+    explicit PassParamsByRef(InstantiationData const & data): Plugin(data), mbInsideFunctionDecl(false) {}
+
+    virtual void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
+
+    // When warning about function params of primitive type that could be passed
+    // by value instead of by reference, make sure not to warn if the parameter
+    // is ever bound to a reference; on the one hand, this needs scaffolding in
+    // all Traverse*Decl functions (indirectly) derived from FunctionDecl; and
+    // on the other hand, use a hack of ignoring just the DeclRefExprs nested in
+    // LValueToRValue ImplicitCastExprs when determining whether a param is
+    // bound to a reference:
+    bool TraverseFunctionDecl(FunctionDecl *);
+    bool TraverseImplicitCastExpr(ImplicitCastExpr *);
+
+    bool VisitBinAssign(BinaryOperator const *);
+    bool VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *);
+
+private:
+    bool isFat(QualType type);
+
+    bool mbInsideFunctionDecl;
+    std::unordered_set<ParmVarDecl const *> mParamExclusions;
+};
+
+bool PassParamsByRef::TraverseFunctionDecl(FunctionDecl* functionDecl)
+{
+    if (ignoreLocation(functionDecl))
+        return true;
+    if (functionDecl->isDeleted()
+        || functionDecl->isFunctionTemplateSpecialization())
+    {
+        return true;
+    }
+    // only consider base declarations, not overridden ones, or we warn on methods that
+    // are overriding stuff from external libraries
+    const CXXMethodDecl * methodDecl = dyn_cast<CXXMethodDecl>(functionDecl);
+    if (methodDecl && methodDecl->size_overridden_methods() > 0)
+        return true;
+
+    // Only warn on the definition of the function:
+    if (!functionDecl->doesThisDeclarationHaveABody())
+        return true;
+
+    mbInsideFunctionDecl = true;
+    mParamExclusions.clear();
+    bool ret = RecursiveASTVisitor::TraverseFunctionDecl(functionDecl);
+    mbInsideFunctionDecl = false;
+
+    auto cxxConstructorDecl = dyn_cast<CXXConstructorDecl>(functionDecl);
+    unsigned n = functionDecl->getNumParams();
+    for (unsigned i = 0; i != n; ++i) {
+        const ParmVarDecl * pvDecl = functionDecl->getParamDecl(i);
+        auto const t = pvDecl->getType();
+        if (!isFat(t))
+            continue;
+        if (mParamExclusions.find(pvDecl) != mParamExclusions.end())
+            continue;
+        // Ignore cases where the parameter is std::move'd.
+        // This is a fairly simple check, might need some more complexity if the parameter is std::move'd
+        // somewhere else in the constructor.
+        bool bFoundMove = false;
+        if (cxxConstructorDecl) {
+            for (CXXCtorInitializer const * cxxCtorInitializer : cxxConstructorDecl->inits()) {
+                if (cxxCtorInitializer->isMemberInitializer())
+                {
+                    auto cxxConstructExpr = dyn_cast<CXXConstructExpr>(cxxCtorInitializer->getInit()->IgnoreParenImpCasts());
+                    if (cxxConstructExpr && cxxConstructExpr->getNumArgs() == 1)
+                    {
+                        if (auto callExpr = dyn_cast<CallExpr>(cxxConstructExpr->getArg(0)->IgnoreParenImpCasts())) {
+                            if (loplugin::DeclCheck(callExpr->getCalleeDecl()).Function("move").StdNamespace()) {
+                                bFoundMove = true;
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (bFoundMove)
+            continue;
+        report(
+            DiagnosticsEngine::Warning,
+            ("passing %0 by value, rather pass by const lvalue reference"),
+            pvDecl->getLocation())
+            << t << pvDecl->getSourceRange();
+        auto can = functionDecl->getCanonicalDecl();
+        if (can->getLocation() != functionDecl->getLocation()) {
+            report(
+                DiagnosticsEngine::Note, "function is declared here:",
+                can->getLocation())
+                << can->getSourceRange();
+        }
+    }
+    return ret;
+}
+
+bool PassParamsByRef::TraverseImplicitCastExpr(ImplicitCastExpr * expr) {
+    if (ignoreLocation(expr))
+        return true;
+    return
+        (expr->getCastKind() == CK_LValueToRValue
+         && (dyn_cast<DeclRefExpr>(expr->getSubExpr()->IgnoreParenImpCasts())
+             != nullptr))
+        || RecursiveASTVisitor::TraverseImplicitCastExpr(expr);
+}
+
+bool PassParamsByRef::VisitBinAssign(const BinaryOperator * binaryOperator)
+{
+    if (!mbInsideFunctionDecl)
+        return true;
+    // if we are assigning to a parameter, it can be inconvenient to make the param pass-by-ref
+    if (auto declRefExpr = dyn_cast<DeclRefExpr>(binaryOperator->getLHS()))
+    {
+        if (auto parmVarDecl = dyn_cast<ParmVarDecl>(declRefExpr->getDecl()))
+            mParamExclusions.emplace(parmVarDecl);
+    }
+    return true;
+}
+
+bool PassParamsByRef::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr * cxxOperatorCallExpr )
+{
+    if (!mbInsideFunctionDecl)
+        return true;
+    // if we are assigning to a parameter, it can be inconvenient to make the param pass-by-ref
+    if (!cxxOperatorCallExpr->isAssignmentOp())
+        return true;
+    auto declRefExpr = dyn_cast<DeclRefExpr>(cxxOperatorCallExpr->getArg(0));
+    if (!declRefExpr)
+        return true;
+    if (auto parmVarDecl = dyn_cast<ParmVarDecl>(declRefExpr->getDecl()))
+        mParamExclusions.emplace(parmVarDecl);
+    return true;
+}
+
+bool PassParamsByRef::isFat(QualType type) {
+    if (!type->isRecordType()) {
+        return false;
+    }
+    loplugin::TypeCheck tc(type);
+    if ((tc.Class("Reference").Namespace("uno").Namespace("star")
+            .Namespace("sun").Namespace("com").GlobalNamespace())
+        || (tc.Class("Sequence").Namespace("uno").Namespace("star")
+            .Namespace("sun").Namespace("com").GlobalNamespace())
+        || tc.Class("OString").Namespace("rtl").GlobalNamespace()
+        || tc.Class("OUString").Namespace("rtl").GlobalNamespace()
+        || tc.Class("Reference").Namespace("rtl").GlobalNamespace())
+    {
+        return true;
+    }
+    if (type->isIncompleteType()) {
+        return false;
+    }
+    Type const * t2 = type.getTypePtrOrNull();
+    return t2 != nullptr
+        && compiler.getASTContext().getTypeSizeInChars(t2).getQuantity() > 64;
+}
+
+loplugin::Plugin::Registration< PassParamsByRef > X("passparamsbyref");
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/compilerplugins/clang/passstuffbyref.cxx b/compilerplugins/clang/passstuffbyref.cxx
index 12c13d1b6c89..2fa12db827b9 100644
--- a/compilerplugins/clang/passstuffbyref.cxx
+++ b/compilerplugins/clang/passstuffbyref.cxx
@@ -31,7 +31,7 @@ class PassStuffByRef:
     public RecursiveASTVisitor<PassStuffByRef>, public loplugin::Plugin
 {
 public:
-    explicit PassStuffByRef(InstantiationData const & data): Plugin(data), mbInsideFunctionDecl(false), mbFoundDisqualifier(false) {}
+    explicit PassStuffByRef(InstantiationData const & data): Plugin(data), mbInsideFunctionDecl(false), mbFoundReturnValueDisqualifier(false) {}
 
     virtual void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
 
@@ -59,12 +59,11 @@ private:
         T * decl, bool (RecursiveASTVisitor::* fn)(T *));
     void checkParams(const FunctionDecl * functionDecl);
     void checkReturnValue(const FunctionDecl * functionDecl, const CXXMethodDecl * methodDecl);
-    bool isFat(QualType type);
     bool isPrimitiveConstRef(QualType type);
     bool isReturnExprDisqualified(const Expr* expr);
 
     bool mbInsideFunctionDecl;
-    bool mbFoundDisqualifier;
+    bool mbFoundReturnValueDisqualifier;
 
     struct FDecl {
         std::set<ParmVarDecl const *> parms;
@@ -185,51 +184,6 @@ void PassStuffByRef::checkParams(const FunctionDecl * functionDecl) {
     if (!functionDecl->doesThisDeclarationHaveABody()) {
         return;
     }
-    auto cxxConstructorDecl = dyn_cast<CXXConstructorDecl>(functionDecl);
-    unsigned n = functionDecl->getNumParams();
-    for (unsigned i = 0; i != n; ++i) {
-        const ParmVarDecl * pvDecl = functionDecl->getParamDecl(i);
-        auto const t = pvDecl->getType();
-        if (!isFat(t)) {
-            continue;
-        }
-        // Ignore cases where the parameter is std::move'd.
-        // This is a fairly simple check, might need some more complexity if the parameter is std::move'd
-        // somewhere else in the constructor.
-        bool bFoundMove = false;
-        if (cxxConstructorDecl) {
-            for (CXXCtorInitializer const * cxxCtorInitializer : cxxConstructorDecl->inits()) {
-                if (cxxCtorInitializer->isMemberInitializer())
-                {
-                    auto cxxConstructExpr = dyn_cast<CXXConstructExpr>(cxxCtorInitializer->getInit()->IgnoreParenImpCasts());
-                    if (cxxConstructExpr && cxxConstructExpr->getNumArgs() == 1)
-                    {
-                        if (auto callExpr = dyn_cast<CallExpr>(cxxConstructExpr->getArg(0)->IgnoreParenImpCasts())) {
-                            if (loplugin::DeclCheck(callExpr->getCalleeDecl()).Function("move").StdNamespace()) {
-                                bFoundMove = true;
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        if (bFoundMove) {
-            continue;
-        }
-        report(
-            DiagnosticsEngine::Warning,
-            ("passing %0 by value, rather pass by const lvalue reference"),
-            pvDecl->getLocation())
-            << t << pvDecl->getSourceRange();
-        auto can = functionDecl->getCanonicalDecl();
-        if (can->getLocation() != functionDecl->getLocation()) {
-            report(
-                DiagnosticsEngine::Note, "function is declared here:",
-                can->getLocation())
-                << can->getSourceRange();
-        }
-    }
     // ignore stuff that forms part of the stable URE interface
     if (isInUnoIncludeFile(functionDecl)) {
         return;
@@ -241,6 +195,7 @@ void PassStuffByRef::checkParams(const FunctionDecl * functionDecl) {
     {
         return;
     }
+    unsigned n = functionDecl->getNumParams();
     assert(!functionDecls_.empty());
     functionDecls_.back().check = true;
     for (unsigned i = 0; i != n; ++i) {
@@ -311,11 +266,11 @@ void PassStuffByRef::checkReturnValue(const FunctionDecl * functionDecl, const C
         return;
     }
     mbInsideFunctionDecl = true;
-    mbFoundDisqualifier = false;
+    mbFoundReturnValueDisqualifier = false;
     TraverseStmt(functionDecl->getBody());
     mbInsideFunctionDecl = false;
 
-    if (mbFoundDisqualifier)
+    if (mbFoundReturnValueDisqualifier)
         return;
 
     report(
@@ -342,7 +297,7 @@ bool PassStuffByRef::VisitReturnStmt(const ReturnStmt * returnStmt)
     const Expr* expr = dyn_cast<Expr>(*returnStmt->child_begin())->IgnoreParenCasts();
 
     if (isReturnExprDisqualified(expr)) {
-        mbFoundDisqualifier = true;
+        mbFoundReturnValueDisqualifier = true;
         return true;
     }
     return true;
@@ -394,74 +349,20 @@ bool PassStuffByRef::VisitVarDecl(const VarDecl * varDecl)
     // things guarded by locking are probably best left alone
     loplugin::TypeCheck dc(varDecl->getType());
     if (dc.Class("Guard").Namespace("osl").GlobalNamespace())
-        mbFoundDisqualifier = true;
+        mbFoundReturnValueDisqualifier = true;
     if (dc.Class("ClearableGuard").Namespace("osl").GlobalNamespace())
-        mbFoundDisqualifier = true;
+        mbFoundReturnValueDisqualifier = true;
     if (dc.Class("ResettableGuard").Namespace("osl").GlobalNamespace())
-        mbFoundDisqualifier = true;
+        mbFoundReturnValueDisqualifier = true;
     else if (dc.Class("SolarMutexGuard").GlobalNamespace())
-        mbFoundDisqualifier = true;
+        mbFoundReturnValueDisqualifier = true;
     else if (dc.Class("SfxModelGuard").GlobalNamespace())
-        mbFoundDisqualifier = true;
+        mbFoundReturnValueDisqualifier = true;
     else if (dc.Class("ReadWriteGuard").Namespace("utl").GlobalNamespace())
-        mbFoundDisqualifier = true;
+        mbFoundReturnValueDisqualifier = true;
     return true;
 }
 
-// Would produce a wrong recommendation for
-//
-//   PresenterFrameworkObserver::RunOnUpdateEnd(
-//       xCC,
-//       [pSelf](bool){ return pSelf->ShutdownPresenterScreen(); });
-//
-// in PresenterScreen::RequestShutdownPresenterScreen
-// (sdext/source/presenter/PresenterScreen.cxx), with no obvious way to work
-// around it:
-//
-// bool PassStuffByRef::VisitLambdaExpr(const LambdaExpr * expr) {
-//     if (ignoreLocation(expr)) {
-//         return true;
-//     }
-//     for (auto i(expr->capture_begin()); i != expr->capture_end(); ++i) {
-//         if (i->getCaptureKind() == LambdaCaptureKind::LCK_ByCopy) {
-//             auto const t = i->getCapturedVar()->getType();
-//             if (isFat(t)) {
-//                 report(
-//                     DiagnosticsEngine::Warning,
-//                     ("%0 capture of %1 variable by copy, rather use capture"
-//                      " by reference---UNLESS THE LAMBDA OUTLIVES THE VARIABLE"),
-//                     i->getLocation())
-//                     << (i->isImplicit() ? "implicit" : "explicit") << t
-//                     << expr->getSourceRange();
-//             }
-//         }
-//     }
-//     return true;
-// }
-
-bool PassStuffByRef::isFat(QualType type) {
-    if (!type->isRecordType()) {
-        return false;
-    }
-    loplugin::TypeCheck tc(type);
-    if ((tc.Class("Reference").Namespace("uno").Namespace("star")
-            .Namespace("sun").Namespace("com").GlobalNamespace())
-        || (tc.Class("Sequence").Namespace("uno").Namespace("star")
-            .Namespace("sun").Namespace("com").GlobalNamespace())
-        || tc.Class("OString").Namespace("rtl").GlobalNamespace()
-        || tc.Class("OUString").Namespace("rtl").GlobalNamespace()
-        || tc.Class("Reference").Namespace("rtl").GlobalNamespace())
-    {
-        return true;
-    }
-    if (type->isIncompleteType()) {
-        return false;
-    }
-    Type const * t2 = type.getTypePtrOrNull();
-    return t2 != nullptr
-        && compiler.getASTContext().getTypeSizeInChars(t2).getQuantity() > 64;
-}
-
 bool PassStuffByRef::isPrimitiveConstRef(QualType type) {
     if (type->isIncompleteType()) {
         return false;
diff --git a/compilerplugins/clang/test/passparamsbyref.cxx b/compilerplugins/clang/test/passparamsbyref.cxx
new file mode 100644
index 000000000000..e58aa79bcaa8
--- /dev/null
+++ b/compilerplugins/clang/test/passparamsbyref.cxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <rtl/ustring.hxx>
+
+struct S {
+    OUString mv1;
+    OUString mv2;
+
+    // make sure we ignore cases where the passed in parameter is std::move'd
+    S(OUString v1, OUString v2)
+      : mv1(std::move(v1)), mv2((std::move(v2))) {}
+};
+
+
+void f()
+{
+    S* s;
+    OUString v1, v2;
+    s = new S(v1, v2);
+}
+
+
+// check that we don't warn when the param is modified
+OUString trim_string(OUString aString)
+{
+    aString += "xxx";
+    return aString;
+}
+
+// expected-no-diagnostics
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/solenv/CompilerTest_compilerplugins_clang.mk b/solenv/CompilerTest_compilerplugins_clang.mk
index 59f572ce1374..1c44878f5b53 100644
--- a/solenv/CompilerTest_compilerplugins_clang.mk
+++ b/solenv/CompilerTest_compilerplugins_clang.mk
@@ -23,6 +23,7 @@ $(eval $(call gb_CompilerTest_add_exception_objects,compilerplugins_clang, \
     compilerplugins/clang/test/oslendian-1 \
     compilerplugins/clang/test/oslendian-2 \
     compilerplugins/clang/test/oslendian-3 \
+    compilerplugins/clang/test/passparamsbyref \
     compilerplugins/clang/test/passstuffbyref \
     compilerplugins/clang/test/redundantcast \
     compilerplugins/clang/test/redundantcopy \
commit b0d7b8fa63109117ec19864ddd2462683088d1e3
Author: Noel Grandin <noel.grandin at collabora.co.uk>
Date:   Thu Aug 17 11:35:37 2017 +0200

    new loplugin convertuintptr
    
    an experiment to see if I can make the process of eliminating
    sal_uIntPtr a little easier
    
    Change-Id: I808185fbf18826cb9ab5612a7be4148d52045957

diff --git a/compilerplugins/clang/convertuintptr.cxx b/compilerplugins/clang/convertuintptr.cxx
new file mode 100644
index 000000000000..77eb1b4f8616
--- /dev/null
+++ b/compilerplugins/clang/convertuintptr.cxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <memory>
+#include <cassert>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <set>
+#include "plugin.hxx"
+#include "check.hxx"
+
+/**
+  plugin to help to when converting code from sal_uIntPtr to something more precise.
+ */
+namespace {
+
+class ConvertUIntPtr:
+    public RecursiveASTVisitor<ConvertUIntPtr>, public loplugin::Plugin
+{
+public:
+    explicit ConvertUIntPtr(InstantiationData const & data): Plugin(data) {}
+
+    virtual void run() override
+    {
+        std::string fn( compiler.getSourceManager().getFileEntryForID(
+                        compiler.getSourceManager().getMainFileID())->getName() );
+        normalizeDotDotInFilePath(fn);
+        // using sal_uIntPtr as in-between type when converting void* to rtl_TextEncoding
+        if (fn == SRCDIR "/sal/osl/unx/thread.cxx")
+            return;
+        // too much magic
+        if (fn == SRCDIR "/sal/rtl/alloc_arena.cxx")
+            return;
+        if (fn == SRCDIR "/sal/rtl/alloc_cache.cxx")
+            return;
+        // TODO not sure what is going on here
+        if (fn == SRCDIR "/tools/source/generic/bigint.cxx")
+            return;
+        TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
+    }
+
+    bool VisitImplicitCastExpr(ImplicitCastExpr const *);
+private:
+    bool isIntPtr(QualType qt);
+};
+
+bool ConvertUIntPtr::VisitImplicitCastExpr(ImplicitCastExpr const * castExpr)
+{
+    if (ignoreLocation(castExpr))
+        return true;
+
+    if (castExpr->getCastKind() == CK_LValueToRValue)
+        return true;
+    if (isa<IntegerLiteral>(castExpr->IgnoreCasts()))
+        return true;
+    // ignore literals like "-123"
+    if (isa<UnaryOperator>(castExpr->IgnoreCasts()))
+        return true;
+
+    bool isSrcIntPtr = isIntPtr(castExpr->getSubExpr()->getType());
+    bool isDestIntPtr = isIntPtr(castExpr->getType());
+
+    if (!isSrcIntPtr && !isDestIntPtr)
+        return true;
+
+    // exclude casting between sal_uIntPtr <-> sal_IntPtr
+    if (isSrcIntPtr && isDestIntPtr)
+        return true;
+
+    if (isSrcIntPtr && loplugin::TypeCheck(castExpr->getType()).AnyBoolean())
+        return true;
+
+    report(
+        DiagnosticsEngine::Warning,
+        "cast from %0 to %1",
+        castExpr->getExprLoc())
+      << castExpr->getSubExpr()->getType()
+      << castExpr->getType()
+      << castExpr->getSourceRange();
+
+    return true;
+}
+
+bool ConvertUIntPtr::isIntPtr(QualType qt)
+{
+    auto tc = loplugin::TypeCheck(qt);
+    if (!tc.Typedef())
+        return false;
+    TypedefType const * typedefType = qt->getAs<TypedefType>();
+    auto name = typedefType->getDecl()->getName();
+    return name == "sal_uIntPtr" || name == "sal_IntPtr";
+}
+
+loplugin::Plugin::Registration< ConvertUIntPtr > X("convertuintptr", false);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/compilerplugins/clang/droplong.cxx b/compilerplugins/clang/droplong.cxx
index a6ef33006d9d..fe5675b36d2f 100644
--- a/compilerplugins/clang/droplong.cxx
+++ b/compilerplugins/clang/droplong.cxx
@@ -57,8 +57,6 @@ public:
         TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
     }
 
-    bool shouldVisitTemplateInstantiations () const { return true; }
-
     bool VisitBinAssign(BinaryOperator const *);
     bool VisitVarDecl(VarDecl const *);
     bool VisitCastExpr(CastExpr const *);
diff --git a/compilerplugins/clang/test/convertuintptr.cxx b/compilerplugins/clang/test/convertuintptr.cxx
new file mode 100644
index 000000000000..8789394c541f
--- /dev/null
+++ b/compilerplugins/clang/test/convertuintptr.cxx
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <tools/solar.h>
+
+int main()
+{
+    sal_uIntPtr x = 1;
+    sal_uInt32 y = x; // expected-error {{cast from 'sal_uIntPtr' (aka 'unsigned long') to 'sal_uInt32' (aka 'unsigned int') [loplugin:convertuintptr]}}
+    y = x; // expected-error {{cast from 'sal_uIntPtr' (aka 'unsigned long') to 'sal_uInt32' (aka 'unsigned int') [loplugin:convertuintptr]}}
+    (void)y;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/solenv/CompilerTest_compilerplugins_clang.mk b/solenv/CompilerTest_compilerplugins_clang.mk
index 4f1b41149536..59f572ce1374 100644
--- a/solenv/CompilerTest_compilerplugins_clang.mk
+++ b/solenv/CompilerTest_compilerplugins_clang.mk
@@ -12,6 +12,7 @@ $(eval $(call gb_CompilerTest_CompilerTest,compilerplugins_clang))
 $(eval $(call gb_CompilerTest_add_exception_objects,compilerplugins_clang, \
     compilerplugins/clang/test/casttovoid \
     compilerplugins/clang/test/constparams \
+    compilerplugins/clang/test/convertuintptr \
     compilerplugins/clang/test/cppunitassertequals \
     compilerplugins/clang/test/datamembershadow \
     compilerplugins/clang/test/droplong \


More information about the Libreoffice-commits mailing list