basctl/source/basicide/localizationmgr.cxx                   |    6 
 chart2/source/controller/accessibility/AccessibleBase.cxx    |    2 
 chart2/source/controller/main/ChartController_Properties.cxx |    2 
 chart2/source/controller/main/ChartController_Window.cxx     |    4 
 chart2/source/controller/main/DragMethod_PieSegment.cxx      |    2 
 chart2/source/tools/ObjectIdentifier.cxx                     |   16 
 compilerplugins/clang/stringviewvar.cxx                      |  406 +++++++++++
 compilerplugins/clang/test/stringviewvar.cxx                 |   65 +
 desktop/source/deployment/gui/dp_gui_extlistbox.cxx          |    1 
 desktop/source/deployment/misc/dp_platform.cxx               |    8 
 desktop/source/lib/init.cxx                                  |   18 
 desktop/source/migration/migration.cxx                       |    4 
 filter/source/xsltdialog/typedetectionimport.cxx             |   10 
 oox/source/dump/pptxdumper.cxx                               |   37 -
 sc/source/core/tool/dbdata.cxx                               |    6 
 sfx2/source/sidebar/ResourceManager.cxx                      |    6 
 solenv/CompilerTest_compilerplugins_clang.mk                 |    1 
 svgio/source/svgreader/svgtextpathnode.cxx                   |    4 
 sw/source/core/graphic/ndgrf.cxx                             |    4 
 sw/source/filter/html/swhtml.cxx                             |    2 
 sw/source/filter/ww8/docxattributeoutput.cxx                 |    2 
 vcl/source/font/FeatureParser.cxx                            |   11 
 xmloff/source/chart/SchXMLTools.cxx                          |    5 
 23 files changed, 549 insertions(+), 73 deletions(-)

New commits:
commit 441e32d9555f410a0a2df995a70f9958cf2b0f1d
Author:     Stephan Bergmann <sberg...@redhat.com>
AuthorDate: Tue Apr 19 16:45:02 2022 +0200
Commit:     Stephan Bergmann <sberg...@redhat.com>
CommitDate: Tue Apr 19 18:31:24 2022 +0200

    Fix heap-use-after-free
    
    ...when dp_gui::ExtensionRemovedListener::disposing
    (desktop/source/deployment/gui/dp_gui_extlistbox.cxx) calls
    
    >         m_pParent->removeEntry( xPackage );
    
    on an already destroyed m_pParent in e.g. the following scenario:  In an
    installation with some bundled extensions (e.g., --enable-ext-ct2n), "Tools 
-
    Extension Manager...", deselect "Display Extensions - Bundled with 
LibreOffice",
    "Close", "File - Exit LibreOffice".
    
    It appears the issue was present ever since at least
    051f7b163fa4bf1917fb3db98fed2a6a932a827e "jl152#i77196# Use ExtensionManager
    instead of PackageManager"
    
    Change-Id: I446cba382103828b97a2b1db9fa8afc207b73bc7
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133180
    Tested-by: Jenkins
    Reviewed-by: Stephan Bergmann <sberg...@redhat.com>

diff --git a/desktop/source/deployment/gui/dp_gui_extlistbox.cxx 
b/desktop/source/deployment/gui/dp_gui_extlistbox.cxx
index f66c016ea6a7..3b96147bbf02 100644
--- a/desktop/source/deployment/gui/dp_gui_extlistbox.cxx
+++ b/desktop/source/deployment/gui/dp_gui_extlistbox.cxx
@@ -1106,6 +1106,7 @@ void ExtensionBox_Impl::checkEntries()
                         m_bHasActive = false;
                     }
                     m_vRemovedEntries.push_back(*iIndex);
+                    
(*iIndex)->m_xPackage->removeEventListener(m_xRemoveListener);
                     iIndex = m_vEntries.erase(iIndex);
                 }
             }
commit ab699bfdb3375f7142a50cc35322e2924c9e5945
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Fri Apr 15 12:25:12 2022 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Tue Apr 19 18:31:10 2022 +0200

    new loplugin:stringviewvar looks for OUString vars that can be
    
    ... that can be string_view
    
    Change-Id: I0ddf66725e08b58e866a764f57200dd188b9f639
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133066
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/basctl/source/basicide/localizationmgr.cxx 
b/basctl/source/basicide/localizationmgr.cxx
index 6dd07a021d32..279fd7555801 100644
--- a/basctl/source/basicide/localizationmgr.cxx
+++ b/basctl/source/basicide/localizationmgr.cxx
@@ -975,7 +975,7 @@ void LocalizationMgr::resetResourceForDialog( const 
Reference< container::XNameC
         return;
 
     // Dialog as control
-    OUString aDummyName;
+    std::u16string_view aDummyName;
     Any aDialogCtrl;
     aDialogCtrl <<= xDialogModel;
     Reference< XStringResourceResolver > xDummyStringResolver;
@@ -1002,7 +1002,7 @@ void LocalizationMgr::setResourceIDsForDialog( const 
Reference< container::XName
         return;
 
     // Dialog as control
-    OUString aDummyName;
+    std::u16string_view aDummyName;
     Any aDialogCtrl;
     aDialogCtrl <<= xDialogModel;
     Reference< XStringResourceResolver > xDummyStringResolver;
@@ -1084,7 +1084,7 @@ void LocalizationMgr::copyResourceForDialog(
     if( !xDialogModel.is() || !xSourceStringResolver.is() || 
!xTargetStringResourceManager.is() )
         return;
 
-    OUString aDummyName;
+    std::u16string_view aDummyName;
     Any aDialogCtrl;
     aDialogCtrl <<= xDialogModel;
     implHandleControlResourceProperties
diff --git a/chart2/source/controller/accessibility/AccessibleBase.cxx 
b/chart2/source/controller/accessibility/AccessibleBase.cxx
index 904c91e99365..4def612c215e 100644
--- a/chart2/source/controller/accessibility/AccessibleBase.cxx
+++ b/chart2/source/controller/accessibility/AccessibleBase.cxx
@@ -719,7 +719,7 @@ Color AccessibleBase::getColor( eColorType eColType )
     if( eType == OBJECTTYPE_LEGEND_ENTRY )
     {
         // for colors get the data series/point properties
-        OUString aParentParticle( ObjectIdentifier::getFullParentParticle( 
aObjectCID ));
+        std::u16string_view aParentParticle( 
ObjectIdentifier::getFullParentParticle( aObjectCID ));
         aObjectCID = ObjectIdentifier::createClassifiedIdentifierForParticle( 
aParentParticle );
     }
 
diff --git a/chart2/source/controller/main/ChartController_Properties.cxx 
b/chart2/source/controller/main/ChartController_Properties.cxx
index b04e43a82cfa..99c768da772e 100644
--- a/chart2/source/controller/main/ChartController_Properties.cxx
+++ b/chart2/source/controller/main/ChartController_Properties.cxx
@@ -678,7 +678,7 @@ OUString lcl_getFormatCIDforSelectedCID( const OUString& 
rSelectedCID )
     // some legend entries are handled as if they were data series
     if( eObjectType==OBJECTTYPE_LEGEND_ENTRY )
     {
-        OUString aParentParticle( ObjectIdentifier::getFullParentParticle( 
rSelectedCID ) );
+        std::u16string_view aParentParticle( 
ObjectIdentifier::getFullParentParticle( rSelectedCID ) );
         aFormatCID  = ObjectIdentifier::createClassifiedIdentifierForParticle( 
aParentParticle );
     }
 
diff --git a/chart2/source/controller/main/ChartController_Window.cxx 
b/chart2/source/controller/main/ChartController_Window.cxx
index a6bae9b002a7..8808da531bd2 100644
--- a/chart2/source/controller/main/ChartController_Window.cxx
+++ b/chart2/source/controller/main/ChartController_Window.cxx
@@ -711,7 +711,7 @@ void ChartController::execute_MouseButtonDown( const 
MouseEvent& rMEvt )
         }
         else
         {
-            OUString aDragMethodServiceName( 
ObjectIdentifier::getDragMethodServiceName( m_aSelection.getSelectedCID() ) );
+            std::u16string_view aDragMethodServiceName( 
ObjectIdentifier::getDragMethodServiceName( m_aSelection.getSelectedCID() ) );
             if( aDragMethodServiceName == 
ObjectIdentifier::getPieSegmentDragMethodServiceName() )
                 pDragMethod = new DragMethod_PieSegment( *pDrawViewWrapper, 
m_aSelection.getSelectedCID(), getChartModel() );
         }
@@ -1420,7 +1420,7 @@ bool ChartController::execute_KeyInput( const KeyEvent& 
rKEvt )
                 nCode == KEY_DOWN )
             {
                 bDrag = true;
-                OUString aParameter( ObjectIdentifier::getDragParameterString( 
m_aSelection.getSelectedCID() ));
+                std::u16string_view aParameter( 
ObjectIdentifier::getDragParameterString( m_aSelection.getSelectedCID() ));
                 sal_Int32 nOffsetPercentDummy( 0 );
                 awt::Point aMinimumPosition( 0, 0 );
                 awt::Point aMaximumPosition( 0, 0 );
diff --git a/chart2/source/controller/main/DragMethod_PieSegment.cxx 
b/chart2/source/controller/main/DragMethod_PieSegment.cxx
index 3adc6103e6ab..0859ada4ab23 100644
--- a/chart2/source/controller/main/DragMethod_PieSegment.cxx
+++ b/chart2/source/controller/main/DragMethod_PieSegment.cxx
@@ -46,7 +46,7 @@ DragMethod_PieSegment::DragMethod_PieSegment( 
DrawViewWrapper& rDrawViewWrapper
     , m_aDragDirection(1000.0,1000.0)
     , m_fDragRange( 1.0 )
 {
-    OUString aParameter( ObjectIdentifier::getDragParameterString( 
m_aObjectCID ) );
+    std::u16string_view aParameter( ObjectIdentifier::getDragParameterString( 
m_aObjectCID ) );
 
     sal_Int32 nOffsetPercent(0);
     awt::Point aMinimumPosition(0,0);
diff --git a/chart2/source/tools/ObjectIdentifier.cxx 
b/chart2/source/tools/ObjectIdentifier.cxx
index e1b05d023630..a117873b6e38 100644
--- a/chart2/source/tools/ObjectIdentifier.cxx
+++ b/chart2/source/tools/ObjectIdentifier.cxx
@@ -302,10 +302,10 @@ OUString 
ObjectIdentifier::createClassifiedIdentifierForObject(
     OUString aRet;
 
     enum ObjectType eObjectType = OBJECTTYPE_UNKNOWN;
-    const OUString aObjectID;
+    const std::u16string_view aObjectID;
     OUString aParentParticle;
-    const OUString aDragMethodServiceName;
-    const OUString aDragParameterString;
+    const std::u16string_view aDragMethodServiceName;
+    const std::u16string_view aDragParameterString;
 
     try
     {
@@ -697,8 +697,8 @@ bool ObjectIdentifier::isDragableObject( 
std::u16string_view rClassifiedIdentifi
             bReturn = true;
             break;
         default:
-            OUString aDragMethodServiceName( 
ObjectIdentifier::getDragMethodServiceName( rClassifiedIdentifier ) );
-            bReturn = !aDragMethodServiceName.isEmpty();
+            std::u16string_view aDragMethodServiceName( 
ObjectIdentifier::getDragMethodServiceName( rClassifiedIdentifier ) );
+            bReturn = !aDragMethodServiceName.empty();
             break;
     }
     return bReturn;
@@ -761,10 +761,10 @@ bool ObjectIdentifier::areSiblings( const OUString& 
rCID1, const OUString& rCID2
         bRet=false;
     else
     {
-        OUString aParent1( ObjectIdentifier::getFullParentParticle( rCID1 ) );
-        if( !aParent1.isEmpty() )
+        std::u16string_view aParent1( ObjectIdentifier::getFullParentParticle( 
rCID1 ) );
+        if( !aParent1.empty() )
         {
-            OUString aParent2( ObjectIdentifier::getFullParentParticle( rCID2 
) );
+            std::u16string_view aParent2( 
ObjectIdentifier::getFullParentParticle( rCID2 ) );
             bRet=aParent1 == aParent2;
         }
         //legend entries are special:
diff --git a/compilerplugins/clang/stringviewvar.cxx 
b/compilerplugins/clang/stringviewvar.cxx
new file mode 100644
index 000000000000..2aedde049bdf
--- /dev/null
+++ b/compilerplugins/clang/stringviewvar.cxx
@@ -0,0 +1,406 @@
+/* -*- 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 <cassert>
+#include <set>
+#include <vector>
+
+#include "config_clang.h"
+
+#include "check.hxx"
+#include "functionaddress.hxx"
+#include "plugin.hxx"
+
+// Find various of type  rtl::O[U]String that can be converted to 
std::[u16]string_view instead.
+
+// This can generate false positives e.g.
+//   OUString sSave( aToken );
+//   aToken.append("foo");
+//   aToken = sSave;
+// where the data that is backing the view is modified and then the view is 
used to assign to
+// the same source data.
+
+namespace
+{
+enum class StringType
+{
+    None,
+    RtlOstring,
+    RtlOustring
+};
+
+StringType relevantStringType(QualType type)
+{
+    loplugin::TypeCheck const c(type);
+    if (c.Class("OString").Namespace("rtl"))
+    {
+        return StringType::RtlOstring;
+    }
+    else if (c.Class("OUString").Namespace("rtl"))
+    {
+        return StringType::RtlOustring;
+    }
+    else
+    {
+        return StringType::None;
+    }
+}
+
+bool relevantVarDecl(VarDecl const* decl)
+{
+    auto const t1 = decl->getType();
+    if (relevantStringType(t1.getNonReferenceType()) == StringType::None)
+    {
+        return false;
+    }
+    if (isa<ParmVarDecl>(decl))
+    {
+        return false;
+    }
+    return true;
+}
+
+DeclRefExpr const* relevantDeclRefExpr(Expr const* expr)
+{
+    //TODO: Look through BO_Comma and AbstractConditionalOperator
+    auto const e = dyn_cast<DeclRefExpr>(expr->IgnoreParenImpCasts());
+    if (e == nullptr)
+    {
+        return nullptr;
+    }
+    auto const d = dyn_cast<VarDecl>(e->getDecl());
+    if (d == nullptr)
+    {
+        return nullptr;
+    }
+    if (!relevantVarDecl(d))
+    {
+        return nullptr;
+    }
+    return e;
+}
+
+bool isStringView(QualType qt)
+{
+    return 
bool(loplugin::TypeCheck(qt).ClassOrStruct("basic_string_view").StdNamespace());
+}
+
+DeclRefExpr const* relevantImplicitCastExpr(ImplicitCastExpr const* expr)
+{
+    if (!isStringView(expr->getType()))
+    {
+        return nullptr;
+    }
+    return relevantDeclRefExpr(expr->getSubExprAsWritten());
+}
+
+DeclRefExpr const* relevantCStyleCastExpr(CStyleCastExpr const* expr)
+{
+    if (expr->getCastKind() != CK_ToVoid)
+    {
+        return nullptr;
+    }
+    return relevantDeclRefExpr(expr->getSubExprAsWritten());
+}
+
+DeclRefExpr const* relevantCXXMemberCallExpr(CXXMemberCallExpr const* expr)
+{
+    StringType t = relevantStringType(expr->getObjectType());
+    if (t == StringType::None)
+    {
+        return nullptr;
+    }
+    bool good = false;
+    auto const d = expr->getMethodDecl();
+    if (d->getOverloadedOperator() == OO_Subscript)
+    {
+        good = true;
+    }
+    else if (auto const i = d->getIdentifier())
+    {
+        auto const n = i->getName();
+        if (n == "endsWith" || n == "isEmpty" || n == "startsWith" || n == 
"subView"
+            || n == "indexOf" || n == "lastIndexOf" || n == "compareTo" || n 
== "match"
+            || n == "trim" || n == "toInt32" || n == "toInt64" || n == 
"toDouble"
+            || n == "equalsIgnoreAsciiCase" || n == "compareToIgnoreAsciiCase" 
|| n == "getToken"
+            || n == "copy")
+        {
+            good = true;
+        }
+#if 0
+        //TODO: rtl::O[U]String::getLength would be awkward to replace with
+        // std::[u16]string_view::length/size due to the sal_Int32 vs. 
std::size_t return type
+        // mismatch (C++20 ssize might make that easier, though); and while 
rtl::OString::getStr is
+        // documented to be NUL-terminated (so not eligible for replacement 
with
+        // std::string_view::data in general), rtl::OUString::getStr is not 
(so should be eligible
+        // for replacement with std::u16string_view::data, but some call sites 
might nevertheless
+        // incorrectly rely on NUL termination, so any replacement would need 
careful review):
+        if (n == "getLength" || (t == StringType::RtlOustring && n == 
"getStr"))
+        {
+            good = true;
+        }
+#endif
+    }
+    if (!good)
+    {
+        return nullptr;
+    }
+    return relevantDeclRefExpr(expr->getImplicitObjectArgument());
+}
+
+SmallVector<DeclRefExpr const*, 2> wrap(DeclRefExpr const* expr)
+{
+    if (expr == nullptr)
+    {
+        return {};
+    }
+    return { expr };
+}
+
+SmallVector<DeclRefExpr const*, 2> 
relevantCXXOperatorCallExpr(CXXOperatorCallExpr const* expr)
+{
+    auto const op = expr->getOperator();
+    if (op == OO_Subscript)
+    {
+        auto const e = expr->getArg(0);
+        if (relevantStringType(e->getType()) == StringType::None)
+        {
+            return {};
+        }
+        return wrap(relevantDeclRefExpr(e));
+    }
+    if (expr->isComparisonOp() || (op == OO_Plus && expr->getNumArgs() == 2))
+    {
+        SmallVector<DeclRefExpr const*, 2> v;
+        if (auto const e = relevantDeclRefExpr(expr->getArg(0)))
+        {
+            v.push_back(e);
+        }
+        if (auto const e = relevantDeclRefExpr(expr->getArg(1)))
+        {
+            v.push_back(e);
+        }
+        return v;
+    }
+    if (op == OO_PlusEqual)
+    {
+        if (relevantStringType(expr->getArg(0)->getType()) != 
StringType::RtlOustring)
+        {
+            return {};
+        }
+        return wrap(relevantDeclRefExpr(expr->getArg(1)));
+    }
+    if (op == OO_Equal)
+    {
+        if (!isStringView(expr->getArg(1)->getType()))
+        {
+            return {};
+        }
+        return wrap(relevantDeclRefExpr(expr->getArg(0)));
+    }
+    return {};
+}
+
+static const Expr* IgnoreImplicitAndConversionOperator(const Expr* expr)
+{
+    expr = expr->IgnoreImplicit();
+    if (auto memberCall = dyn_cast<CXXMemberCallExpr>(expr))
+    {
+        if (auto conversionDecl = 
dyn_cast_or_null<CXXConversionDecl>(memberCall->getMethodDecl()))
+        {
+            if (!conversionDecl->isExplicit())
+                expr = 
memberCall->getImplicitObjectArgument()->IgnoreImplicit();
+        }
+    }
+    return expr;
+}
+
+class StringViewVar final
+    : public 
loplugin::FunctionAddress<loplugin::FilteringPlugin<StringViewVar>>
+{
+public:
+    explicit StringViewVar(loplugin::InstantiationData const& data)
+        : FunctionAddress(data)
+    {
+    }
+
+    bool VisitVarDecl(VarDecl* decl)
+    {
+        if (ignoreLocation(decl))
+        {
+            return true;
+        }
+        if (decl->hasGlobalStorage())
+        {
+            return true;
+        }
+        if (!decl->isThisDeclarationADefinition())
+        {
+            return true;
+        }
+        if (!relevantVarDecl(decl))
+        {
+            return true;
+        }
+        if (decl->getInit())
+        {
+            auto expr = IgnoreImplicitAndConversionOperator(decl->getInit());
+            if (auto castExpr = dyn_cast<CXXFunctionalCastExpr>(expr))
+            {
+                expr = 
IgnoreImplicitAndConversionOperator(castExpr->getSubExpr());
+            }
+            if (auto cxxConstruct = dyn_cast<CXXConstructExpr>(expr))
+            {
+                if (cxxConstruct->getNumArgs() == 0)
+                    currentVars_.insert(decl); // default constructor
+                else if (cxxConstruct->getNumArgs() == 1
+                         && isStringView(cxxConstruct->getArg(0)->getType()))
+                    currentVars_.insert(decl);
+            }
+        }
+        return true;
+    }
+
+    bool TraverseImplicitCastExpr(ImplicitCastExpr* expr)
+    {
+        if (ignoreLocation(expr))
+        {
+            return true;
+        }
+        auto const e = relevantImplicitCastExpr(expr);
+        if (e == nullptr)
+        {
+            return FunctionAddress::TraverseImplicitCastExpr(expr);
+        }
+        currentGoodUses_.insert(e);
+        auto const ret = FunctionAddress::TraverseImplicitCastExpr(expr);
+        currentGoodUses_.erase(e);
+        return ret;
+    }
+
+    bool TraverseCStyleCastExpr(CStyleCastExpr* expr)
+    {
+        if (ignoreLocation(expr))
+        {
+            return true;
+        }
+        auto const e = relevantCStyleCastExpr(expr);
+        if (e == nullptr)
+        {
+            return FunctionAddress::TraverseCStyleCastExpr(expr);
+        }
+        currentGoodUses_.insert(e);
+        auto const ret = FunctionAddress::TraverseCStyleCastExpr(expr);
+        currentGoodUses_.erase(e);
+        return ret;
+    }
+
+    bool TraverseCXXMemberCallExpr(CXXMemberCallExpr* expr)
+    {
+        if (ignoreLocation(expr))
+        {
+            return true;
+        }
+        auto const e = relevantCXXMemberCallExpr(expr);
+        if (e == nullptr)
+        {
+            return FunctionAddress::TraverseCXXMemberCallExpr(expr);
+        }
+        currentGoodUses_.insert(e);
+        auto const ret = FunctionAddress::TraverseCXXMemberCallExpr(expr);
+        currentGoodUses_.erase(e);
+        return ret;
+    }
+
+    bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr* expr)
+    {
+        if (ignoreLocation(expr))
+        {
+            return true;
+        }
+        auto const es = relevantCXXOperatorCallExpr(expr);
+        if (es.empty())
+        {
+            return FunctionAddress::TraverseCXXOperatorCallExpr(expr);
+        }
+        currentGoodUses_.insert(es.begin(), es.end());
+        auto const ret = FunctionAddress::TraverseCXXOperatorCallExpr(expr);
+        for (auto const i : es)
+        {
+            currentGoodUses_.erase(i);
+        }
+        return ret;
+    }
+
+    bool VisitDeclRefExpr(DeclRefExpr* expr)
+    {
+        if (!FunctionAddress::VisitDeclRefExpr(expr))
+        {
+            return false;
+        }
+        if (ignoreLocation(expr))
+        {
+            return true;
+        }
+        if (currentGoodUses_.find(expr) != currentGoodUses_.end())
+        {
+            return true;
+        }
+        if (auto const d = dyn_cast<VarDecl>(expr->getDecl()))
+        {
+            currentVars_.erase(d);
+        }
+        return true;
+    }
+
+private:
+    void run() override
+    {
+        if (!compiler.getLangOpts().CPlusPlus)
+        {
+            return;
+        }
+        if 
(compiler.getPreprocessor().getIdentifierInfo("NDEBUG")->hasMacroDefinition())
+        {
+            return;
+        }
+        StringRef fn(handler.getMainFileName());
+        // leave the string QA tests alone
+        if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sal/qa/"))
+        {
+            return;
+        }
+        // false +
+        if (loplugin::hasPathnamePrefix(fn, SRCDIR 
"/svtools/source/svrtf/parrtf.cxx"))
+        {
+            return;
+        }
+        if (!TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()))
+        {
+            return;
+        }
+        for (auto const i : currentVars_)
+        {
+            auto const t = 
relevantStringType(i->getType().getNonReferenceType());
+            report(DiagnosticsEngine::Warning,
+                   "replace var of type %0 with "
+                   "'%select{std::string_view|std::u16string_view}1'",
+                   i->getLocation())
+                << i->getType() << (int(t) - 1) << i->getSourceRange();
+        }
+    }
+
+    std::set<VarDecl const*> currentVars_;
+    std::set<DeclRefExpr const*> currentGoodUses_;
+};
+
+static loplugin::Plugin::Registration<StringViewVar> reg("stringviewvar");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/compilerplugins/clang/test/stringviewvar.cxx 
b/compilerplugins/clang/test/stringviewvar.cxx
new file mode 100644
index 000000000000..016f0fcc85a9
--- /dev/null
+++ b/compilerplugins/clang/test/stringviewvar.cxx
@@ -0,0 +1,65 @@
+/* -*- 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/.
+ */
+
+#undef NDEBUG
+
+#include "sal/config.h"
+#include <string_view>
+#include "rtl/string.hxx"
+#include "rtl/ustring.hxx"
+#include "rtl/ustrbuf.hxx"
+#include "sal/types.h"
+
+void f1(std::string_view sv)
+{
+    // expected-error@+1 {{replace var of type 'rtl::OString' with 
'std::string_view' [loplugin:stringviewvar]}}
+    OString s1(sv);
+    (void)s1;
+}
+
+void f2(const OString s1)
+{
+    // no warning expected
+    OString s2(s1);
+    (void)s2;
+}
+
+std::string_view f3a();
+void f3()
+{
+    // expected-error@+1 {{replace var of type 'rtl::OString' with 
'std::string_view' [loplugin:stringviewvar]}}
+    OString s1 = OString(f3a());
+    (void)s1;
+}
+
+void f4a(const OString&);
+void f4(std::string_view sv)
+{
+    // no warning expected
+    OString s1(sv);
+    f4a(s1);
+}
+
+void f5(std::string_view sv)
+{
+    // expected-error@+1 {{replace var of type 'rtl::OString' with 
'std::string_view' [loplugin:stringviewvar]}}
+    OString s1(sv);
+    if (s1 == "xxxx")
+        f5(sv);
+}
+
+void f6(std::u16string_view sv)
+{
+    // expected-error@+1 {{replace var of type 'rtl::OUString' with 
'std::u16string_view' [loplugin:stringviewvar]}}
+    OUString s6;
+    s6 = sv;
+    (void)s6;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/desktop/source/deployment/misc/dp_platform.cxx 
b/desktop/source/deployment/misc/dp_platform.cxx
index 90dee4a6d1c2..879e617b7258 100644
--- a/desktop/source/deployment/misc/dp_platform.cxx
+++ b/desktop/source/deployment/misc/dp_platform.cxx
@@ -173,12 +173,12 @@ bool platform_fits( std::u16string_view platform_string )
     sal_Int32 index = 0;
     for (;;)
     {
-        const OUString token(
+        const std::u16string_view token(
             o3tl::trim(o3tl::getToken(platform_string, 0, ',', index )) );
         // check if this platform:
-        if (token.equalsIgnoreAsciiCase( StrPlatform::get() ) ||
-            (token.indexOf( '_' ) < 0 && /* check OS part only */
-             token.equalsIgnoreAsciiCase( StrOperatingSystem::get() )))
+        if (o3tl::equalsIgnoreAsciiCase( token, StrPlatform::get() ) ||
+            (token.find( '_' ) == std::u16string_view::npos && /* check OS 
part only */
+             o3tl::equalsIgnoreAsciiCase( token, StrOperatingSystem::get() )))
         {
             return true;
         }
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index e017ec4d9985..7b99ed49fdc9 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -2837,7 +2837,8 @@ static int doc_saveAs(LibreOfficeKitDocument* pThis, 
const char* sUrl, const cha
 
         // Check if watermark for pdf is passed by filteroptions...
         // It is not a real filter option so it must be filtered out.
-        OUString watermarkText, sFullSheetPreview;
+        OUString watermarkText;
+        std::u16string_view sFullSheetPreview;
         int aIndex = -1;
         if ((aIndex = aFilterOptions.indexOf(",Watermark=")) >= 0)
         {
@@ -2853,7 +2854,7 @@ static int doc_saveAs(LibreOfficeKitDocument* pThis, 
const char* sUrl, const cha
             aFilterOptions = OUString::Concat(aFilterOptions.subView(0, 
aIndex)) + aFilterOptions.subView(bIndex+16);
         }
 
-        bool bFullSheetPreview = sFullSheetPreview == "true";
+        bool bFullSheetPreview = sFullSheetPreview == u"true";
 
         // Select a pdf version if specified a valid one. If not specified 
then ignore.
         // If invalid then fail.
@@ -2861,19 +2862,18 @@ static int doc_saveAs(LibreOfficeKitDocument* pThis, 
const char* sUrl, const cha
         if ((aIndex = aFilterOptions.indexOf(",PDFVer=")) >= 0)
         {
             int bIndex = aFilterOptions.indexOf("PDFVEREND");
-            OUString sPdfVer;
-            sPdfVer = aFilterOptions.subView(aIndex+8, bIndex-(aIndex+8));
+            std::u16string_view sPdfVer = aFilterOptions.subView(aIndex+8, 
bIndex-(aIndex+8));
             aFilterOptions = OUString::Concat(aFilterOptions.subView(0, 
aIndex)) + aFilterOptions.subView(bIndex+9);
 
-            if (sPdfVer.equalsIgnoreAsciiCase("PDF/A-1b"))
+            if (o3tl::equalsIgnoreAsciiCase(sPdfVer, u"PDF/A-1b"))
                 pdfVer = 1;
-            else if (sPdfVer.equalsIgnoreAsciiCase("PDF/A-2b"))
+            else if (o3tl::equalsIgnoreAsciiCase(sPdfVer, u"PDF/A-2b"))
                 pdfVer = 2;
-            else if (sPdfVer.equalsIgnoreAsciiCase("PDF/A-3b"))
+            else if (o3tl::equalsIgnoreAsciiCase(sPdfVer, u"PDF/A-3b"))
                 pdfVer = 3;
-            else if (sPdfVer.equalsIgnoreAsciiCase("PDF-1.5"))
+            else if (o3tl::equalsIgnoreAsciiCase(sPdfVer, u"PDF-1.5"))
                 pdfVer = 15;
-            else if (sPdfVer.equalsIgnoreAsciiCase("PDF-1.6"))
+            else if (o3tl::equalsIgnoreAsciiCase(sPdfVer, u"PDF-1.6"))
                 pdfVer = 16;
             else
             {
diff --git a/desktop/source/migration/migration.cxx 
b/desktop/source/migration/migration.cxx
index 42a02fa2cf76..6014d0e74935 100644
--- a/desktop/source/migration/migration.cxx
+++ b/desktop/source/migration/migration.cxx
@@ -941,8 +941,8 @@ void MigrationImpl::mergeOldToNewVersion(const 
uno::Reference< ui::XUIConfigurat
         OUString sParentNodeName = elem.m_sParentNodeName;
         sal_Int32 nIndex = 0;
         do {
-            OUString sToken( o3tl::trim(o3tl::getToken(sParentNodeName, 0, 
'|', nIndex)) );
-            if (sToken.isEmpty())
+            std::u16string_view sToken( 
o3tl::trim(o3tl::getToken(sParentNodeName, 0, '|', nIndex)) );
+            if (sToken.empty())
                 break;
 
             sal_Int32 nCount = xTemp->getCount();
diff --git a/filter/source/xsltdialog/typedetectionimport.cxx 
b/filter/source/xsltdialog/typedetectionimport.cxx
index 5fc5ae582951..be5766927fbc 100644
--- a/filter/source/xsltdialog/typedetectionimport.cxx
+++ b/filter/source/xsltdialog/typedetectionimport.cxx
@@ -136,14 +136,14 @@ std::unique_ptr<filter_info_impl> 
TypeDetectionImporter::createFilterForNode( No
     pFilter->maType = getSubdata( 1, aComma, aData  );
     pFilter->maDocumentService = getSubdata( 2, aComma, aData );
 
-    OUString aFilterService( getSubdata( 3, aComma, aData ) );
+    std::u16string_view aFilterService( getSubdata( 3, aComma, aData ) );
     pFilter->maFlags = o3tl::toInt32(getSubdata( 4, aComma, aData ));
 
     // parse filter user data
     sal_Unicode aDelim(';');
-    OUString aFilterUserData( getSubdata( 5, aComma, aData ) );
+    std::u16string_view aFilterUserData( getSubdata( 5, aComma, aData ) );
 
-    OUString aAdapterService( getSubdata( 0, aDelim, aFilterUserData ) );
+    std::u16string_view aAdapterService( getSubdata( 0, aDelim, 
aFilterUserData ) );
     //Import/ExportService
     pFilter->mbNeedsXSLT2 = OUString(getSubdata( 1, aDelim, aFilterUserData 
)).toBoolean();
     pFilter->maImportService = getSubdata( 2, aDelim, aFilterUserData );
@@ -182,10 +182,10 @@ std::unique_ptr<filter_info_impl> 
TypeDetectionImporter::createFilterForNode( No
     if( pFilter->maFlags == 0 )
         bOk = false;
 
-    if( aFilterService != "com.sun.star.comp.Writer.XmlFilterAdaptor" )
+    if( aFilterService != u"com.sun.star.comp.Writer.XmlFilterAdaptor" )
         bOk = false;
 
-    if( aAdapterService != "com.sun.star.documentconversion.XSLTFilter" )
+    if( aAdapterService != u"com.sun.star.documentconversion.XSLTFilter" )
         bOk = false;
 
     if( pFilter->maExtension.isEmpty() )
diff --git a/oox/source/dump/pptxdumper.cxx b/oox/source/dump/pptxdumper.cxx
index dba538593aae..c65b792063b2 100644
--- a/oox/source/dump/pptxdumper.cxx
+++ b/oox/source/dump/pptxdumper.cxx
@@ -24,6 +24,7 @@
 #include <oox/dump/xlsbdumper.hxx>
 #include <oox/helper/zipstorage.hxx>
 #include <oox/ole/olestorage.hxx>
+#include <o3tl/string_view.hxx>
 
 #ifdef DBG_UTIL
 
@@ -42,41 +43,41 @@ RootStorageObject::RootStorageObject( const DumperBase& 
rParent )
 
 void RootStorageObject::implDumpStream( const Reference< XInputStream >& 
rxStrm, const OUString& rStrgPath, const OUString& rStrmName, const OUString& 
rSysFileName )
 {
-    OUString aExt( InputOutputHelper::getFileNameExtension( rStrmName ) );
-    if( aExt.equalsIgnoreAsciiCase("pptx") ||
-        aExt.equalsIgnoreAsciiCase("potx") )
+    std::u16string_view aExt( InputOutputHelper::getFileNameExtension( 
rStrmName ) );
+    if( o3tl::equalsIgnoreAsciiCase(aExt, u"pptx") ||
+        o3tl::equalsIgnoreAsciiCase(aExt, u"potx") )
     {
         Dumper( getContext(), rxStrm, rSysFileName ).dump();
     }
 #ifdef FIXME
     else if(
-        aExt.equalsIgnoreAsciiCase("xlsb") ||
-        aExt.equalsIgnoreAsciiCase("xlsm") ||
-        aExt.equalsIgnoreAsciiCase("xlsx") ||
-        aExt.equalsIgnoreAsciiCase("xltm") ||
-        aExt.equalsIgnoreAsciiCase("xltx") )
+        o3tl::equalsIgnoreAsciiCase(aExt, u"xlsb") ||
+        o3tl::equalsIgnoreAsciiCase(aExt, u"xlsm") ||
+        o3tl::equalsIgnoreAsciiCase(aExt, u"xlsx") ||
+        o3tl::equalsIgnoreAsciiCase(aExt, u"xltm") ||
+        o3tl::equalsIgnoreAsciiCase(aExt, u"xltx") )
     {
         ::oox::dump::xlsb::Dumper( getContext(), rxStrm, rSysFileName ).dump();
     }
     else if(
-        aExt.equalsIgnoreAsciiCase("xla") ||
-        aExt.equalsIgnoreAsciiCase("xlc") ||
-        aExt.equalsIgnoreAsciiCase("xlm") ||
-        aExt.equalsIgnoreAsciiCase("xls") ||
-        aExt.equalsIgnoreAsciiCase("xlt") ||
-        aExt.equalsIgnoreAsciiCase("xlw") )
+        o3tl::equalsIgnoreAsciiCase(aExt, u"xla") ||
+        o3tl::equalsIgnoreAsciiCase(aExt, u"xlc") ||
+        o3tl::equalsIgnoreAsciiCase(aExt, u"xlm") ||
+        o3tl::equalsIgnoreAsciiCase(aExt, u"xls") ||
+        o3tl::equalsIgnoreAsciiCase(aExt, u"xlt") ||
+        o3tl::equalsIgnoreAsciiCase(aExt, u"xlw") )
     {
         ::oox::dump::biff::Dumper( getContext(), rxStrm, rSysFileName ).dump();
     }
 #endif
     else if(
-        aExt.equalsIgnoreAsciiCase("xml") ||
-        aExt.equalsIgnoreAsciiCase("vml") ||
-        aExt.equalsIgnoreAsciiCase("rels") )
+        o3tl::equalsIgnoreAsciiCase(aExt, u"xml") ||
+        o3tl::equalsIgnoreAsciiCase(aExt, u"vml") ||
+        o3tl::equalsIgnoreAsciiCase(aExt, u"rels") )
     {
         XmlStreamObject( *this, rxStrm, rSysFileName ).dump();
     }
-    else if( aExt.equalsIgnoreAsciiCase("bin") )
+    else if( o3tl::equalsIgnoreAsciiCase(aExt, u"bin") )
     {
         if( rStrgPath == "ppt" && rStrmName == "vbaProject.bin" )
         {
diff --git a/sc/source/core/tool/dbdata.cxx b/sc/source/core/tool/dbdata.cxx
index f7e22dea2a03..e060fb25e422 100644
--- a/sc/source/core/tool/dbdata.cxx
+++ b/sc/source/core/tool/dbdata.cxx
@@ -1016,13 +1016,13 @@ OUString 
lcl_IncrementNumberInNamedRange(ScDBCollection::NamedDBs& namedDBs,
     sal_Int32 nOldNumber = 1;
     if (nLastIndex >= 0)
     {
-        OUString sLastPart(sOldName.subView(nLastIndex));
-        nOldNumber = sLastPart.toInt32();
+        std::u16string_view sLastPart(sOldName.subView(nLastIndex));
+        nOldNumber = o3tl::toInt32(sLastPart);
 
         // When no number found, add number at the end.
         // When there is a literal "0" at the end, keep the "lastIndex" from 
above
         // (OUString::toInt32() also returns 0 on failure)
-        if (nOldNumber == 0 && sLastPart != "0")
+        if (nOldNumber == 0 && sLastPart != u"0")
         {
             nOldNumber = 1;
             nLastIndex = sOldName.getLength();
diff --git a/sfx2/source/sidebar/ResourceManager.cxx 
b/sfx2/source/sidebar/ResourceManager.cxx
index 56700a223fbb..320faf48fe5e 100644
--- a/sfx2/source/sidebar/ResourceManager.cxx
+++ b/sfx2/source/sidebar/ResourceManager.cxx
@@ -520,7 +520,7 @@ void ResourceManager::ReadContextList (
             continue;
         }
 
-        const OUString sInitialState(o3tl::trim(o3tl::getToken(sValue, 0, ',', 
nCharacterIndex)));
+        const std::u16string_view 
sInitialState(o3tl::trim(o3tl::getToken(sValue, 0, ',', nCharacterIndex)));
 
         // The fourth argument is optional.
         const OUString sMenuCommandOverride(
@@ -599,9 +599,9 @@ void ResourceManager::ReadContextList (
         // Setup the flag that controls whether a deck/pane is
         // initially visible/expanded.
         bool bIsInitiallyVisible;
-        if (sInitialState == "visible")
+        if (sInitialState == u"visible")
             bIsInitiallyVisible = true;
-        else if (sInitialState == "hidden")
+        else if (sInitialState == u"hidden")
             bIsInitiallyVisible = false;
         else
         {
diff --git a/solenv/CompilerTest_compilerplugins_clang.mk 
b/solenv/CompilerTest_compilerplugins_clang.mk
index 2520dd2192e9..123e6951edb3 100644
--- a/solenv/CompilerTest_compilerplugins_clang.mk
+++ b/solenv/CompilerTest_compilerplugins_clang.mk
@@ -94,6 +94,7 @@ $(eval $(call 
gb_CompilerTest_add_exception_objects,compilerplugins_clang, \
     compilerplugins/clang/test/stringstatic \
     compilerplugins/clang/test/stringview \
     compilerplugins/clang/test/stringviewparam \
+    compilerplugins/clang/test/stringviewvar \
     compilerplugins/clang/test/trivialconstructor \
     compilerplugins/clang/test/trivialdestructor \
     compilerplugins/clang/test/typedefparam \
diff --git a/svgio/source/svgreader/svgtextpathnode.cxx 
b/svgio/source/svgreader/svgtextpathnode.cxx
index 3b341eea3d40..9b177383677f 100644
--- a/svgio/source/svgreader/svgtextpathnode.cxx
+++ b/svgio/source/svgreader/svgtextpathnode.cxx
@@ -150,10 +150,10 @@ namespace svgio::svgreader
                 if(basegfx::fTools::more(fSnippetWidth, 0.0))
                 {
                     const OUString aText(getSource().getText());
-                    const OUString 
aTrimmedChars(o3tl::trim(aText.subView(nIndex, nLength)));
+                    const std::u16string_view 
aTrimmedChars(o3tl::trim(aText.subView(nIndex, nLength)));
                     const double fEndPos(mfPosition + fSnippetWidth);
 
-                    if(!aTrimmedChars.isEmpty() && (mfPosition < 
mfBasegfxPathLength || fEndPos > 0.0))
+                    if(!aTrimmedChars.empty() && (mfPosition < 
mfBasegfxPathLength || fEndPos > 0.0))
                     {
                         const double fHalfSnippetWidth(fSnippetWidth * 0.5);
 
diff --git a/sw/source/core/graphic/ndgrf.cxx b/sw/source/core/graphic/ndgrf.cxx
index 3eabac3a84b5..82cbb57c12f3 100644
--- a/sw/source/core/graphic/ndgrf.cxx
+++ b/sw/source/core/graphic/ndgrf.cxx
@@ -577,8 +577,8 @@ void SwGrfNode::InsertLink( std::u16string_view rGrfName, 
const OUString& rFltNa
     {
         sal_Int32 nTmp = 0;
         const OUString sApp{ o3tl::getToken(rGrfName, 0, 
sfx2::cTokenSeparator, nTmp ) };
-        const OUString sTopic{ o3tl::getToken(rGrfName, 0, 
sfx2::cTokenSeparator, nTmp ) };
-        const OUString sItem{ rGrfName.substr( nTmp ) };
+        const std::u16string_view sTopic{ o3tl::getToken(rGrfName, 0, 
sfx2::cTokenSeparator, nTmp ) };
+        const std::u16string_view sItem{ rGrfName.substr( nTmp ) };
         rIDLA.GetLinkManager().InsertDDELink( mxLink.get(), sApp, sTopic, 
sItem );
     }
     else
diff --git a/sw/source/filter/html/swhtml.cxx b/sw/source/filter/html/swhtml.cxx
index b40633119673..2c19733d66b3 100644
--- a/sw/source/filter/html/swhtml.cxx
+++ b/sw/source/filter/html/swhtml.cxx
@@ -2057,7 +2057,7 @@ void SwHTMLParser::NextToken( HtmlTokenId nToken )
             if( ' ' == aToken[ 3 ] &&
                 ' ' == aToken[ aToken.getLength()-3 ] )
             {
-                OUString aComment( aToken.subView( 3, aToken.getLength()-5 ) );
+                std::u16string_view aComment( aToken.subView( 3, 
aToken.getLength()-5 ) );
                 InsertComment(comphelper::string::strip(aComment, ' '));
             }
             else
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index 88df3b95f46d..c80ea4972e9a 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -8507,7 +8507,7 @@ void DocxAttributeOutput::HiddenField(const SwField& 
rField)
         OUString aTrueFalse = rField.GetPar2();
         sal_Int32 nPos = aTrueFalse.indexOf('|');
         OUString aTrue;
-        OUString aFalse;
+        std::u16string_view aFalse;
         if (nPos == -1)
         {
             aTrue = aTrueFalse;
diff --git a/vcl/source/font/FeatureParser.cxx 
b/vcl/source/font/FeatureParser.cxx
index 32e407671336..5182cea7aace 100644
--- a/vcl/source/font/FeatureParser.cxx
+++ b/vcl/source/font/FeatureParser.cxx
@@ -10,6 +10,7 @@
 
 #include <vcl/font/FeatureParser.hxx>
 #include <vcl/font/Feature.hxx>
+#include <o3tl/string_view.hxx>
 
 namespace vcl::font
 {
@@ -30,18 +31,18 @@ FeatureParser::FeatureParser(std::u16string_view rFontName)
     if (nPrefixIdx == std::u16string_view::npos)
         return;
 
-    OUString sName(rFontName.substr(++nPrefixIdx));
+    std::u16string_view sName(rFontName.substr(++nPrefixIdx));
     sal_Int32 nIndex = 0;
     do
     {
-        OUString sToken = sName.getToken(0, vcl::font::FeatureSeparator, 
nIndex);
+        std::u16string_view sToken = o3tl::getToken(sName, 0, 
vcl::font::FeatureSeparator, nIndex);
 
         sal_Int32 nInnerIdx{ 0 };
-        OUString sID = sToken.getToken(0, '=', nInnerIdx);
+        std::u16string_view sID = o3tl::getToken(sToken, 0, '=', nInnerIdx);
 
-        if (sID == "lang")
+        if (sID == u"lang")
         {
-            m_sLanguage = sToken.getToken(0, '=', nInnerIdx);
+            m_sLanguage = o3tl::getToken(sToken, 0, '=', nInnerIdx);
         }
         else
         {
diff --git a/xmloff/source/chart/SchXMLTools.cxx 
b/xmloff/source/chart/SchXMLTools.cxx
index 828d550e9f56..2e90a3e37f5e 100644
--- a/xmloff/source/chart/SchXMLTools.cxx
+++ b/xmloff/source/chart/SchXMLTools.cxx
@@ -48,6 +48,7 @@
 #include <comphelper/processfactory.hxx>
 #include <tools/diagnose_ex.h>
 #include <sal/log.hxx>
+#include <o3tl/string_view.hxx>
 #include <algorithm>
 #include <map>
 
@@ -94,8 +95,8 @@ sal_Int32 lcl_getBuildIDFromGenerator( std::u16string_view 
rGenerator )
     size_t nBegin = rGenerator.find( sBuildCompare );
     if( nBegin != std::u16string_view::npos )
     {
-        OUString sBuildId( rGenerator.substr( nBegin + 
sBuildCompare.getLength() ) );
-        nBuildId = sBuildId.toInt32();
+        std::u16string_view sBuildId = rGenerator.substr( nBegin + 
sBuildCompare.getLength() );
+        nBuildId = o3tl::toInt32(sBuildId);
     }
     return nBuildId;
 }

Reply via email to