compilerplugins/clang/optionalbool.cxx                 |   88 +++++++++++++++++
 compilerplugins/clang/test/optionalbool.cxx            |   27 +++++
 cppcanvas/source/mtfrenderer/implrenderer.cxx          |    4 
 cui/source/options/treeopt.cxx                         |    2 
 dbaccess/source/core/dataaccess/documentdefinition.cxx |    4 
 dbaccess/source/ui/browser/genericcontroller.cxx       |    6 -
 dbaccess/source/ui/browser/unodatbr.cxx                |    8 -
 dbaccess/source/ui/dlg/advancedsettings.cxx            |    2 
 dbaccess/source/ui/dlg/optionalboolitem.hxx            |    2 
 dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx   |    6 -
 oox/source/drawingml/misccontexts.cxx                  |    2 
 oox/source/vml/vmltextboxcontext.cxx                   |    6 -
 reportdesign/source/ui/report/ReportController.cxx     |    2 
 sc/inc/fonthelper.hxx                                  |   10 -
 sc/source/core/data/dptabsrc.cxx                       |    2 
 sc/source/core/data/patattr.cxx                        |    2 
 sc/source/filter/oox/autofilterbuffer.cxx              |    2 
 sc/source/filter/orcus/interface.cxx                   |    2 
 sc/source/ui/unoobj/miscuno.cxx                        |    2 
 sc/source/ui/view/editsh.cxx                           |    2 
 sd/source/ui/view/drviews7.cxx                         |    2 
 sfx2/source/sidebar/SidebarController.cxx              |   12 +-
 solenv/CompilerTest_compilerplugins_clang.mk           |    1 
 starmath/source/unomodel.cxx                           |    8 -
 svx/source/form/fmmodel.cxx                            |    2 
 svx/source/xoutdev/xattr.cxx                           |    4 
 sw/source/core/text/frmpaint.cxx                       |    2 
 sw/source/core/txtnode/attrcontentcontrol.cxx          |    2 
 sw/source/core/unocore/unofield.cxx                    |    4 
 sw/source/core/unocore/unoobj.cxx                      |    8 -
 sw/source/filter/html/htmlforw.cxx                     |    8 -
 sw/source/filter/xml/swxml.cxx                         |    4 
 sw/source/ui/vba/vbacontentcontrol.cxx                 |    8 -
 sw/source/uibase/uno/unomod.cxx                        |    4 
 sw/source/uibase/uno/unotxdoc.cxx                      |   12 +-
 ucb/source/ucp/ext/ucpext_content.cxx                  |    2 
 vcl/source/font/LogicalFontInstance.cxx                |    2 
 37 files changed, 191 insertions(+), 75 deletions(-)

New commits:
commit 68e797402692c5c8abf1b2c4374e12a8d2707d07
Author:     Noel Grandin <[email protected]>
AuthorDate: Wed Aug 23 13:47:40 2023 +0200
Commit:     Noel Grandin <[email protected]>
CommitDate: Mon Aug 28 09:43:40 2023 +0200

    new loplugin:optionalbool
    
    which warns against using the 'operator bool' conversion of
    std::optional<bool> which can lead to interesting bugs
    
    The bugs that this plugin have been submitted independantly,
    so this change is just using has_value() in relevant places.
    
    Change-Id: I259b837feeecddcb8cd1d7e5db1e85bf505907cb
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155978
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <[email protected]>

diff --git a/compilerplugins/clang/optionalbool.cxx 
b/compilerplugins/clang/optionalbool.cxx
new file mode 100644
index 000000000000..013bf1b4725c
--- /dev/null
+++ b/compilerplugins/clang/optionalbool.cxx
@@ -0,0 +1,88 @@
+/* -*- 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/.
+ */
+
+#ifndef LO_CLANG_SHARED_PLUGINS
+
+#include <cassert>
+#include <stack>
+
+#include "check.hxx"
+#include "plugin.hxx"
+#include "config_clang.h"
+
+// Check for uses of std::optional<bool> being assigned to bool, which 
generally does not do
+// what you would expect.
+
+namespace
+{
+class OptionalBool final : public loplugin::FilteringPlugin<OptionalBool>
+{
+public:
+    explicit OptionalBool(loplugin::InstantiationData const& data)
+        : FilteringPlugin(data)
+    {
+    }
+
+    bool preRun() override
+    {
+        if (!compiler.getLangOpts().CPlusPlus)
+            return false;
+        return true;
+    }
+
+    void run() override
+    {
+        if (preRun())
+            TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
+    }
+
+    bool VisitIfStmt(const IfStmt* ifStmt)
+    {
+        if (ignoreLocation(ifStmt))
+            return true;
+        m_ignoreIfCondition = ifStmt->getCond()->IgnoreImplicit();
+        return true;
+    }
+
+    bool VisitCXXMemberCallExpr(const CXXMemberCallExpr* memberCall)
+    {
+        if (ignoreLocation(memberCall))
+            return true;
+        if (m_ignoreIfCondition == memberCall)
+            return true;
+        // check if we are calling a 'operator bool' conversion method
+        auto conversionDecl = 
dyn_cast_or_null<CXXConversionDecl>(memberCall->getMethodDecl());
+        if (!conversionDecl || 
!conversionDecl->getConversionType()->isBooleanType())
+            return true;
+        auto ctsd = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
+            memberCall->getObjectType()->getAsRecordDecl());
+        if (!ctsd || ctsd->getTemplateArgs().size() < 1)
+            return true;
+        if (ctsd->getName() != "optional")
+            return true;
+        if (!ctsd->getTemplateArgs().get(0).getAsType()->isBooleanType())
+            return true;
+        report(DiagnosticsEngine::Warning,
+               "using conversion call to convert std::optional<bool> to bool 
probably does not do "
+               "what you expect, rather use has_value() or value_or()",
+               memberCall->getBeginLoc())
+            << memberCall->getSourceRange();
+        return true;
+    }
+
+private:
+    const Expr* m_ignoreIfCondition = nullptr;
+};
+
+loplugin::Plugin::Registration<OptionalBool> optionalbool("optionalbool");
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/compilerplugins/clang/test/optionalbool.cxx 
b/compilerplugins/clang/test/optionalbool.cxx
new file mode 100644
index 000000000000..02c3a84cf962
--- /dev/null
+++ b/compilerplugins/clang/test/optionalbool.cxx
@@ -0,0 +1,27 @@
+/* -*- 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 "config_clang.h"
+#include <optional>
+
+namespace test1
+{
+std::optional<bool> get_optional_bool();
+void foo1()
+{
+    // expected-error@+1 {{using conversion call to convert 
std::optional<bool> to bool probably does not do what you expect, rather use 
has_value() or value_or() [loplugin:optionalbool]}}
+    bool foo(get_optional_bool());
+    (void)foo;
+
+    // no warning expected
+    if (std::optional<bool> b = get_optional_bool())
+        return;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/cppcanvas/source/mtfrenderer/implrenderer.cxx 
b/cppcanvas/source/mtfrenderer/implrenderer.cxx
index 9d224f1146c4..e898d739d216 100644
--- a/cppcanvas/source/mtfrenderer/implrenderer.cxx
+++ b/cppcanvas/source/mtfrenderer/implrenderer.cxx
@@ -1495,7 +1495,7 @@ namespace cppcanvas::internal
                         // TODO(Q2): define and use appropriate enumeration 
types
                         rState.textReliefStyle          = rFont.GetRelief();
                         rState.textOverlineStyle        = 
static_cast<sal_Int8>(rFont.GetOverline());
-                        rState.textUnderlineStyle       = 
rParms.maFontUnderline ?
+                        rState.textUnderlineStyle       = 
rParms.maFontUnderline.has_value() ?
                             (*rParms.maFontUnderline ? 
sal_Int8(LINESTYLE_SINGLE) : sal_Int8(LINESTYLE_NONE)) :
                             static_cast<sal_Int8>(rFont.GetUnderline());
                         rState.textStrikeoutStyle       = 
static_cast<sal_Int8>(rFont.GetStrikeout());
@@ -2932,7 +2932,7 @@ namespace cppcanvas::internal
             if( rParams.maFontName ||
                 rParams.maFontWeight ||
                 rParams.maFontLetterForm ||
-                rParams.maFontUnderline )
+                rParams.maFontUnderline.has_value() )
             {
                 ::cppcanvas::internal::OutDevState& rState = 
aStateStack.getState();
 
diff --git a/cui/source/options/treeopt.cxx b/cui/source/options/treeopt.cxx
index 3a637145e13d..1b419f22ea21 100644
--- a/cui/source/options/treeopt.cxx
+++ b/cui/source/options/treeopt.cxx
@@ -233,7 +233,7 @@ namespace {
 bool MailMergeCfgIsEmailSupported()
 {
     std::optional<bool> b = 
officecfg::Office::Writer::MailMergeWizard::EMailSupported::get();
-    return b && *b;
+    return b.has_value() && *b;
 }
 
 }
diff --git a/dbaccess/source/core/dataaccess/documentdefinition.cxx 
b/dbaccess/source/core/dataaccess/documentdefinition.cxx
index 28152e6c3b9a..242cfd5c9e1c 100644
--- a/dbaccess/source/core/dataaccess/documentdefinition.cxx
+++ b/dbaccess/source/core/dataaccess/documentdefinition.cxx
@@ -1387,7 +1387,7 @@ namespace
 {
     void    lcl_putLoadArgs( ::comphelper::NamedValueCollection& _io_rArgs, 
const optional_bool& _bSuppressMacros, const optional_bool& _bReadOnly )
     {
-        if ( !!_bSuppressMacros )
+        if ( _bSuppressMacros.has_value() )
         {
             if ( *_bSuppressMacros )
             {
@@ -1404,7 +1404,7 @@ namespace
             }
         }
 
-        if ( !!_bReadOnly )
+        if ( _bReadOnly.has_value() )
             _io_rArgs.put( "ReadOnly", *_bReadOnly );
     }
 }
diff --git a/dbaccess/source/ui/browser/genericcontroller.cxx 
b/dbaccess/source/ui/browser/genericcontroller.cxx
index 654ad2ff1525..54d58824ee45 100644
--- a/dbaccess/source/ui/browser/genericcontroller.cxx
+++ b/dbaccess/source/ui/browser/genericcontroller.cxx
@@ -331,9 +331,9 @@ namespace
         //          framework's implementation details
         if ( !!_rFeatureState.sTitle )
             _out_rStates.push_back( Any( *_rFeatureState.sTitle ) );
-        if ( !!_rFeatureState.bChecked )
+        if ( _rFeatureState.bChecked.has_value() )
             _out_rStates.push_back( Any( *_rFeatureState.bChecked ) );
-        if ( !!_rFeatureState.bInvisible )
+        if ( _rFeatureState.bInvisible.has_value() )
             _out_rStates.push_back( Any( Visibility( 
!*_rFeatureState.bInvisible ) ) );
         if ( _rFeatureState.aValue.hasValue() )
             _out_rStates.push_back( _rFeatureState.aValue );
@@ -1111,7 +1111,7 @@ bool OGenericUnoController::isCommandChecked(sal_uInt16 
_nCommandId) const
 {
     FeatureState aState = GetState( _nCommandId );
 
-    return aState.bChecked && *aState.bChecked;
+    return aState.bChecked.has_value() && *aState.bChecked;
 }
 
 bool OGenericUnoController::isCommandEnabled( const OUString& 
_rCompleteCommandURL ) const
diff --git a/dbaccess/source/ui/browser/unodatbr.cxx 
b/dbaccess/source/ui/browser/unodatbr.cxx
index 06081b665108..5fb250c4bde3 100644
--- a/dbaccess/source/ui/browser/unodatbr.cxx
+++ b/dbaccess/source/ui/browser/unodatbr.cxx
@@ -193,8 +193,8 @@ Any SAL_CALL SbaTableQueryBrowser::queryInterface(const 
Type& _rType)
 {
     if ( _rType.equals( cppu::UnoType<XScriptInvocationContext>::get() ) )
     {
-        OSL_PRECOND( !!m_aDocScriptSupport, 
"SbaTableQueryBrowser::queryInterface: did not initialize this, yet!" );
-        if ( !!m_aDocScriptSupport && *m_aDocScriptSupport )
+        OSL_PRECOND( m_aDocScriptSupport.has_value(), 
"SbaTableQueryBrowser::queryInterface: did not initialize this, yet!" );
+        if ( m_aDocScriptSupport.has_value() && *m_aDocScriptSupport )
             return Any( Reference< XScriptInvocationContext >( this ) );
         return Any();
     }
@@ -212,8 +212,8 @@ Sequence< Type > SAL_CALL SbaTableQueryBrowser::getTypes(  )
         SbaTableQueryBrowser_Base::getTypes()
     ) );
 
-    OSL_PRECOND( !!m_aDocScriptSupport, "SbaTableQueryBrowser::getTypes: did 
not initialize this, yet!" );
-    if ( !m_aDocScriptSupport || !*m_aDocScriptSupport )
+    OSL_PRECOND( m_aDocScriptSupport.has_value(), 
"SbaTableQueryBrowser::getTypes: did not initialize this, yet!" );
+    if ( !m_aDocScriptSupport.has_value() || !*m_aDocScriptSupport )
     {
         auto [begin, end] = asNonConstRange(aTypes);
         auto newEnd = std::remove_if( begin, end,
diff --git a/dbaccess/source/ui/dlg/advancedsettings.cxx 
b/dbaccess/source/ui/dlg/advancedsettings.cxx
index 0770970d1b7e..935a5370de11 100644
--- a/dbaccess/source/ui/dlg/advancedsettings.cxx
+++ b/dbaccess/source/ui/dlg/advancedsettings.cxx
@@ -217,7 +217,7 @@ namespace dbaui
             else
                 OSL_FAIL( "SpecialSettingsPage::implInitControls: unknown 
boolean item type!" );
 
-            if ( !aValue )
+            if ( !aValue.has_value() )
             {
                 booleanSetting.xControl->set_state(TRISTATE_INDET);
             }
diff --git a/dbaccess/source/ui/dlg/optionalboolitem.hxx 
b/dbaccess/source/ui/dlg/optionalboolitem.hxx
index c500dfa2ac60..1c1d039e2650 100644
--- a/dbaccess/source/ui/dlg/optionalboolitem.hxx
+++ b/dbaccess/source/ui/dlg/optionalboolitem.hxx
@@ -37,7 +37,7 @@ namespace dbaui
         virtual bool             operator==( const SfxPoolItem& _rItem ) const 
override;
         virtual OptionalBoolItem* Clone( SfxItemPool* _pPool = nullptr ) const 
override;
 
-        bool    HasValue() const                { return !!m_aValue; }
+        bool    HasValue() const                { return m_aValue.has_value(); 
}
         void    ClearValue()                    { m_aValue.reset(); }
         bool    GetValue() const                { return *m_aValue; }
         void    SetValue(bool _bValue)          { m_aValue = _bValue; }
diff --git a/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx 
b/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx
index 12a73c78877f..759f202c0d4b 100644
--- a/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx
+++ b/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx
@@ -152,14 +152,14 @@ namespace dbaui
 
         bool    documentHasScriptSupport() const
         {
-            OSL_PRECOND( !!m_aDocScriptSupport,
+            OSL_PRECOND( m_aDocScriptSupport.has_value(),
                 "DBSubComponentController_Impl::documentHasScriptSupport: not 
completely initialized, yet - don't know!?" );
-            return !!m_aDocScriptSupport && *m_aDocScriptSupport;
+            return m_aDocScriptSupport.has_value() && *m_aDocScriptSupport;
         }
 
         void    setDocumentScriptSupport( const bool _bSupport )
         {
-            OSL_PRECOND( !m_aDocScriptSupport,
+            OSL_PRECOND( !m_aDocScriptSupport.has_value(),
                 "DBSubComponentController_Impl::setDocumentScriptSupport: 
already initialized!" );
             m_aDocScriptSupport = ::std::optional< bool >( _bSupport );
         }
diff --git a/oox/source/drawingml/misccontexts.cxx 
b/oox/source/drawingml/misccontexts.cxx
index 417b4f35e8a6..2eef9ab6133a 100644
--- a/oox/source/drawingml/misccontexts.cxx
+++ b/oox/source/drawingml/misccontexts.cxx
@@ -57,7 +57,7 @@ 
GradientFillContext::GradientFillContext(ContextHandler2Helper const & rParent,
     auto oRotateWithShape = rAttribs.getBool(XML_rotWithShape);
     mrGradientProps.moShadeFlip = rAttribs.getToken( XML_flip );
     mrGradientProps.moRotateWithShape = oRotateWithShape;
-    if (mpGradientFill && oRotateWithShape)
+    if (mpGradientFill && oRotateWithShape.has_value())
         mpGradientFill->mbRotateWithShape = *oRotateWithShape;
 }
 
diff --git a/oox/source/vml/vmltextboxcontext.cxx 
b/oox/source/vml/vmltextboxcontext.cxx
index b7b41cfc06f0..0a3f255d766d 100644
--- a/oox/source/vml/vmltextboxcontext.cxx
+++ b/oox/source/vml/vmltextboxcontext.cxx
@@ -60,15 +60,15 @@ TextPortionContext::TextPortionContext( 
ContextHandler2Helper const & rParent,
             maFont.monEscapement = nElement;
         break;
         case XML_b:
-            OSL_ENSURE( !maFont.mobBold, 
"TextPortionContext::TextPortionContext - nested <b> elements" );
+            OSL_ENSURE( !maFont.mobBold.has_value(), 
"TextPortionContext::TextPortionContext - nested <b> elements" );
             maFont.mobBold = true;
         break;
         case XML_i:
-            OSL_ENSURE( !maFont.mobItalic, 
"TextPortionContext::TextPortionContext - nested <i> elements" );
+            OSL_ENSURE( !maFont.mobItalic.has_value(), 
"TextPortionContext::TextPortionContext - nested <i> elements" );
             maFont.mobItalic = true;
         break;
         case XML_s:
-            OSL_ENSURE( !maFont.mobStrikeout, 
"TextPortionContext::TextPortionContext - nested <s> elements" );
+            OSL_ENSURE( !maFont.mobStrikeout.has_value(), 
"TextPortionContext::TextPortionContext - nested <s> elements" );
             maFont.mobStrikeout = true;
         break;
         case OOX_TOKEN(dml, blip):
diff --git a/reportdesign/source/ui/report/ReportController.cxx 
b/reportdesign/source/ui/report/ReportController.cxx
index 873d17c353c1..bb869d7061e5 100644
--- a/reportdesign/source/ui/report/ReportController.cxx
+++ b/reportdesign/source/ui/report/ReportController.cxx
@@ -2714,7 +2714,7 @@ uno::Any SAL_CALL OReportController::getViewData()
         sCommandURL = sCommandURL.copy( 5 );
 
         Any aCommandState;
-        if ( !!aFeatureState.bChecked )
+        if ( aFeatureState.bChecked.has_value() )
             aCommandState <<= *aFeatureState.bChecked;
         else if ( aFeatureState.aValue.hasValue() )
             aCommandState = aFeatureState.aValue;
diff --git a/sc/inc/fonthelper.hxx b/sc/inc/fonthelper.hxx
index ae4a778570a9..1cf36baaf2c2 100644
--- a/sc/inc/fonthelper.hxx
+++ b/sc/inc/fonthelper.hxx
@@ -37,11 +37,11 @@ struct SC_DLLPUBLIC ScDxfFont
 
     bool isEmpty() const
     {
-        return !(pFontAttr || nFontHeight ||
-            eWeight || eItalic || eUnder ||
-            eOver || bWordLine || eStrike ||
-            bOutline || bShadow || eEmphasis ||
-            eRelief || aColor || eLang);
+        return !(pFontAttr.has_value() || nFontHeight.has_value() ||
+            eWeight.has_value() || eItalic.has_value() || eUnder.has_value() ||
+            eOver.has_value() || bWordLine.has_value() || eStrike.has_value() 
||
+            bOutline.has_value() || bShadow.has_value() || 
eEmphasis.has_value() ||
+            eRelief.has_value() || aColor.has_value() || eLang.has_value());
     }
 };
 
diff --git a/sc/source/core/data/dptabsrc.cxx b/sc/source/core/data/dptabsrc.cxx
index c9438671570d..f589e1b538e8 100644
--- a/sc/source/core/data/dptabsrc.cxx
+++ b/sc/source/core/data/dptabsrc.cxx
@@ -88,7 +88,7 @@ SC_SIMPLE_SERVICE_INFO( ScDPMember,      "ScDPMember",      
"com.sun.star.sheet.
 static bool lcl_GetBoolFromAny( const uno::Any& aAny )
 {
     auto b = o3tl::tryAccess<bool>(aAny);
-    return b && *b;
+    return b.has_value() && *b;
 }
 
 ScDPSource::ScDPSource( ScDPTableData* pD ) :
diff --git a/sc/source/core/data/patattr.cxx b/sc/source/core/data/patattr.cxx
index e2cd22a390c6..7638652e6857 100644
--- a/sc/source/core/data/patattr.cxx
+++ b/sc/source/core/data/patattr.cxx
@@ -1200,7 +1200,7 @@ ScPatternAttr* ScPatternAttr::PutInPool( ScDocument* 
pDestDoc, ScDocument* pSrcD
 
 bool ScPatternAttr::IsVisible() const
 {
-    if (!mxVisible)
+    if (!mxVisible.has_value())
         mxVisible = CalcVisible();
     return *mxVisible;
 }
diff --git a/sc/source/filter/oox/autofilterbuffer.cxx 
b/sc/source/filter/oox/autofilterbuffer.cxx
index ca0f031923a9..9c9328176095 100644
--- a/sc/source/filter/oox/autofilterbuffer.cxx
+++ b/sc/source/filter/oox/autofilterbuffer.cxx
@@ -773,7 +773,7 @@ void AutoFilter::finalizeImport( const Reference< 
XDatabaseRange >& rxDatabaseRa
             the global mode in obNeedsRegExp. If either one is still in
             don't-care state, all is fine. If both are set, they must be
             equal. */
-        bool bRegExpCompatible = !obNeedsRegExp || !aSettings.mobNeedsRegExp 
|| (obNeedsRegExp.value() == aSettings.mobNeedsRegExp.value());
+        bool bRegExpCompatible = !obNeedsRegExp.has_value() || 
!aSettings.mobNeedsRegExp.has_value() || (obNeedsRegExp.value() == 
aSettings.mobNeedsRegExp.value());
 
         // check whether fields are connected by 'or' (see comments above).
         if( rColumnFields.size() >= 2 )
diff --git a/sc/source/filter/orcus/interface.cxx 
b/sc/source/filter/orcus/interface.cxx
index 52907f5f69c2..a61d545d9151 100644
--- a/sc/source/filter/orcus/interface.cxx
+++ b/sc/source/filter/orcus/interface.cxx
@@ -1505,7 +1505,7 @@ void ScOrcusBorder::applyToItemSet( SfxItemSet& rSet ) 
const
 
 void ScOrcusProtection::applyToItemSet( SfxItemSet& rSet ) const
 {
-    if (!mbLocked && !mbHidden && !mbPrintContent && !mbFormulaHidden)
+    if (!mbLocked.has_value() && !mbHidden.has_value() && 
!mbPrintContent.has_value() && !mbFormulaHidden.has_value())
         return;
 
     bool bLocked = mbLocked.value_or(true); // defaults to true.
diff --git a/sc/source/ui/unoobj/miscuno.cxx b/sc/source/ui/unoobj/miscuno.cxx
index 30104586e3ca..5c875bc0b751 100644
--- a/sc/source/ui/unoobj/miscuno.cxx
+++ b/sc/source/ui/unoobj/miscuno.cxx
@@ -139,7 +139,7 @@ OUString ScUnoHelpFunctions::GetStringProperty(
 bool ScUnoHelpFunctions::GetBoolFromAny( const uno::Any& aAny )
 {
     auto b = o3tl::tryAccess<bool>(aAny);
-    return b && *b;
+    return b.has_value() && *b;
 }
 
 sal_Int16 ScUnoHelpFunctions::GetInt16FromAny( const uno::Any& aAny )
diff --git a/sc/source/ui/view/editsh.cxx b/sc/source/ui/view/editsh.cxx
index 74d4add556b9..493ab18f78cc 100644
--- a/sc/source/ui/view/editsh.cxx
+++ b/sc/source/ui/view/editsh.cxx
@@ -837,7 +837,7 @@ void ScEditShell::GetState( SfxItemSet& rSet )
             case SID_REMOVE_HYPERLINK:
                 {
                     bool bDisableEditHyperlink;
-                    if (!moAtContextMenu_DisableEditHyperlink)
+                    if (!moAtContextMenu_DisableEditHyperlink.has_value())
                         bDisableEditHyperlink = ShouldDisableEditHyperlink();
                     else
                     {
diff --git a/sd/source/ui/view/drviews7.cxx b/sd/source/ui/view/drviews7.cxx
index a2f12e9ccaef..3bace958df28 100644
--- a/sd/source/ui/view/drviews7.cxx
+++ b/sd/source/ui/view/drviews7.cxx
@@ -1480,7 +1480,7 @@ void DrawViewShell::GetMenuState( SfxItemSet &rSet )
     // Menuoption: Edit->Hyperlink
     // Disable, if there is no hyperlink
     bool bDisableEditHyperlink;
-    if (!moAtContextMenu_DisableEditHyperlink)
+    if (!moAtContextMenu_DisableEditHyperlink.has_value())
         bDisableEditHyperlink = ShouldDisableEditHyperlink();
     else
     {
diff --git a/sfx2/source/sidebar/SidebarController.cxx 
b/sfx2/source/sidebar/SidebarController.cxx
index 666870147875..4798e1a33435 100644
--- a/sfx2/source/sidebar/SidebarController.cxx
+++ b/sfx2/source/sidebar/SidebarController.cxx
@@ -502,7 +502,7 @@ void SidebarController::NotifyResize()
 
 void SidebarController::ProcessNewWidth (const sal_Int32 nNewWidth)
 {
-    if ( ! mbIsDeckRequestedOpen)
+    if ( ! mbIsDeckRequestedOpen.has_value())
         return;
 
     if (*mbIsDeckRequestedOpen)
@@ -680,7 +680,7 @@ void SidebarController::SwitchToDeck (
     std::u16string_view rsDeckId)
 {
     if (  msCurrentDeckId != rsDeckId
-        || ! mbIsDeckOpen
+        || ! mbIsDeckOpen.has_value()
         || mnRequestedForceFlags!=SwitchFlag_NoForce)
     {
         std::shared_ptr<DeckDescriptor> xDeckDescriptor = 
mpResourceManager->GetDeckDescriptor(rsDeckId);
@@ -1272,17 +1272,17 @@ bool SidebarController::IsDeckOpen(const sal_Int32 
nIndex)
         OUString asDeckId(mpTabBar->GetDeckIdForIndex(nIndex));
         return IsDeckVisible(asDeckId);
     }
-    return mbIsDeckOpen && *mbIsDeckOpen;
+    return mbIsDeckOpen.has_value() && *mbIsDeckOpen;
 }
 
 bool SidebarController::IsDeckVisible(std::u16string_view rsDeckId)
 {
-    return mbIsDeckOpen && *mbIsDeckOpen && msCurrentDeckId == rsDeckId;
+    return mbIsDeckOpen.has_value() && *mbIsDeckOpen && msCurrentDeckId == 
rsDeckId;
 }
 
 void SidebarController::UpdateDeckOpenState()
 {
-    if ( ! mbIsDeckRequestedOpen)
+    if ( ! mbIsDeckRequestedOpen.has_value() )
         // No state requested.
         return;
 
@@ -1290,7 +1290,7 @@ void SidebarController::UpdateDeckOpenState()
 
     // Update (change) the open state when it either has not yet been 
initialized
     // or when its value differs from the requested state.
-    if ( mbIsDeckOpen && *mbIsDeckOpen == *mbIsDeckRequestedOpen )
+    if ( mbIsDeckOpen.has_value() && *mbIsDeckOpen == *mbIsDeckRequestedOpen )
         return;
 
     if (*mbIsDeckRequestedOpen)
diff --git a/solenv/CompilerTest_compilerplugins_clang.mk 
b/solenv/CompilerTest_compilerplugins_clang.mk
index cb48a66f4884..6404b5323ddf 100644
--- a/solenv/CompilerTest_compilerplugins_clang.mk
+++ b/solenv/CompilerTest_compilerplugins_clang.mk
@@ -52,6 +52,7 @@ $(eval $(call 
gb_CompilerTest_add_exception_objects,compilerplugins_clang, \
     compilerplugins/clang/test/noexcept \
     compilerplugins/clang/test/noexceptmove \
     compilerplugins/clang/test/nullptr \
+    compilerplugins/clang/test/optionalbool \
     compilerplugins/clang/test/oslendian-1 \
     compilerplugins/clang/test/oslendian-2 \
     compilerplugins/clang/test/oslendian-3 \
diff --git a/starmath/source/unomodel.cxx b/starmath/source/unomodel.cxx
index 5857c3832579..64ca28e692e1 100644
--- a/starmath/source/unomodel.cxx
+++ b/starmath/source/unomodel.cxx
@@ -455,8 +455,8 @@ void SmModel::_setPropertyValues(const PropertyMapEntry** 
ppEntries, const Any*
             case HANDLE_FONT_NUMBERS_POSTURE     :
             case HANDLE_FONT_TEXT_POSTURE        :
             {
-                auto bVal = o3tl::tryAccess<bool>(*pValues);
-                if(!bVal)
+                std::optional<const bool> bVal = 
o3tl::tryAccess<bool>(*pValues);
+                if(!bVal.has_value())
                     throw IllegalArgumentException();
                 vcl::Font aNewFont(aFormat.GetFont((*ppEntries)->mnMemberId));
                 aNewFont.SetItalic(*bVal ? ITALIC_NORMAL : ITALIC_NONE);
@@ -472,8 +472,8 @@ void SmModel::_setPropertyValues(const PropertyMapEntry** 
ppEntries, const Any*
             case HANDLE_FONT_NUMBERS_WEIGHT      :
             case HANDLE_FONT_TEXT_WEIGHT         :
             {
-                auto bVal = o3tl::tryAccess<bool>(*pValues);
-                if(!bVal)
+                std::optional<const bool> bVal = 
o3tl::tryAccess<bool>(*pValues);
+                if(!bVal.has_value())
                     throw IllegalArgumentException();
                 vcl::Font aNewFont(aFormat.GetFont((*ppEntries)->mnMemberId));
                 aNewFont.SetWeight(*bVal ? WEIGHT_BOLD : WEIGHT_NORMAL);
diff --git a/svx/source/form/fmmodel.cxx b/svx/source/form/fmmodel.cxx
index 58155f874c77..71fa374c04b3 100644
--- a/svx/source/form/fmmodel.cxx
+++ b/svx/source/form/fmmodel.cxx
@@ -151,7 +151,7 @@ bool FmFormModel::OpenInDesignModeIsDefaulted( )
 
 bool FmFormModel::ControlsUseRefDevice() const
 {
-    if ( !m_pImpl->aControlsUseRefDevice )
+    if ( !m_pImpl->aControlsUseRefDevice.has_value() )
     {
         DocumentType eDocType = eUnknownDocumentType;
         if ( m_pObjShell )
diff --git a/svx/source/xoutdev/xattr.cxx b/svx/source/xoutdev/xattr.cxx
index abf72bd6d6d4..5f5c51655f3e 100644
--- a/svx/source/xoutdev/xattr.cxx
+++ b/svx/source/xoutdev/xattr.cxx
@@ -1813,7 +1813,7 @@ bool XLineStartCenterItem::QueryValue( css::uno::Any& 
rVal, sal_uInt8 /*nMemberI
 bool XLineStartCenterItem::PutValue( const css::uno::Any& rVal, sal_uInt8 
/*nMemberId*/)
 {
     auto b = o3tl::tryAccess<bool>(rVal);
-    if( !b )
+    if( !b.has_value() )
         return false;
 
     SetValue( *b );
@@ -1852,7 +1852,7 @@ bool XLineEndCenterItem::QueryValue( css::uno::Any& rVal, 
sal_uInt8 /*nMemberId*
 bool XLineEndCenterItem::PutValue( const css::uno::Any& rVal, sal_uInt8 
/*nMemberId*/)
 {
     auto b = o3tl::tryAccess<bool>(rVal);
-    if( !b )
+    if( !b.has_value() )
         return false;
 
     SetValue( *b );
diff --git a/sw/source/core/text/frmpaint.cxx b/sw/source/core/text/frmpaint.cxx
index e7e779eb0ea4..43f5922999d4 100644
--- a/sw/source/core/text/frmpaint.cxx
+++ b/sw/source/core/text/frmpaint.cxx
@@ -177,7 +177,7 @@ SwExtraPainter::SwExtraPainter( const SwTextFrame *pFrame, 
SwViewShell *pVwSh,
 
     if( text::HoriOrientation::INSIDE == eHor || 
text::HoriOrientation::OUTSIDE == eHor )
     {
-        if (!oIsRightPage)
+        if (!oIsRightPage.has_value())
             oIsRightPage = pFrame->FindPageFrame()->OnRightPage();
         if (*oIsRightPage)
             eHor = eHor == text::HoriOrientation::INSIDE ? 
text::HoriOrientation::LEFT : text::HoriOrientation::RIGHT;
diff --git a/sw/source/core/txtnode/attrcontentcontrol.cxx 
b/sw/source/core/txtnode/attrcontentcontrol.cxx
index c167f8da33e9..c8a76e4041df 100644
--- a/sw/source/core/txtnode/attrcontentcontrol.cxx
+++ b/sw/source/core/txtnode/attrcontentcontrol.cxx
@@ -501,7 +501,7 @@ std::optional<bool> SwContentControl::GetLock(bool 
bControl) const
     else if (m_aLock.equalsIgnoreAsciiCase("contentLocked"))
         oLock = !bControl;
 
-    assert(oLock && "invalid or unknown lock state");
+    assert(oLock.has_value() && "invalid or unknown lock state");
     return oLock;
 }
 
diff --git a/sw/source/core/unocore/unofield.cxx 
b/sw/source/core/unocore/unofield.cxx
index 78b43b3158bd..d9924bcd834a 100644
--- a/sw/source/core/unocore/unofield.cxx
+++ b/sw/source/core/unocore/unofield.cxx
@@ -2275,8 +2275,8 @@ SwXTextField::setPropertyValue(
         }
         if (pBool)
         {
-            auto b = o3tl::tryAccess<bool>(rValue);
-            if( !b )
+            std::optional<const bool> b = o3tl::tryAccess<bool>(rValue);
+            if( !b.has_value() )
                 throw lang::IllegalArgumentException();
             *pBool = *b;
 
diff --git a/sw/source/core/unocore/unoobj.cxx 
b/sw/source/core/unocore/unoobj.cxx
index 14cceaee3f38..69ba9d3a6dbc 100644
--- a/sw/source/core/unocore/unoobj.cxx
+++ b/sw/source/core/unocore/unoobj.cxx
@@ -2927,8 +2927,8 @@ bool SwUnoCursorHelper::ConvertSortProperties(
             bOldSortdescriptor = true;
             sal_uInt16 nIndex = rPropName[13];
             nIndex = nIndex - '0';
-            auto bTemp = o3tl::tryAccess<bool>(aValue);
-            if (bTemp && nIndex < 3)
+            std::optional<const bool> bTemp = o3tl::tryAccess<bool>(aValue);
+            if (bTemp.has_value() && nIndex < 3)
             {
                 aKeys[nIndex]->bIsNumeric = *bTemp;
             }
@@ -2944,8 +2944,8 @@ bool SwUnoCursorHelper::ConvertSortProperties(
             bOldSortdescriptor = true;
             sal_uInt16 nIndex = rPropName[15];
             nIndex -= '0';
-            auto bTemp = o3tl::tryAccess<bool>(aValue);
-            if (bTemp && nIndex < 3)
+            std::optional<const bool> bTemp = o3tl::tryAccess<bool>(aValue);
+            if (bTemp.has_value() && nIndex < 3)
             {
                 aKeys[nIndex]->eSortOrder = (*bTemp)
                     ? SwSortOrder::Ascending : SwSortOrder::Descending;
diff --git a/sw/source/filter/html/htmlforw.cxx 
b/sw/source/filter/html/htmlforw.cxx
index ce0bfe7bb2cf..b35cd76a24a8 100644
--- a/sw/source/filter/html/htmlforw.cxx
+++ b/sw/source/filter/html/htmlforw.cxx
@@ -809,8 +809,8 @@ SwHTMLWriter& OutHTML_DrawFrameFormatAsControl( 
SwHTMLWriter& rWrt,
             if( xPropSetInfo->hasPropertyByName( sMultiLine ) )
             {
                 aTmp = xPropSet->getPropertyValue( sMultiLine );
-                auto b = o3tl::tryAccess<bool>(aTmp);
-                bMultiLine = b && *b;
+                std::optional<const bool> b = o3tl::tryAccess<bool>(aTmp);
+                bMultiLine = b.has_value() && *b;
             }
 
             if( bMultiLine )
@@ -837,8 +837,8 @@ SwHTMLWriter& OutHTML_DrawFrameFormatAsControl( 
SwHTMLWriter& rWrt,
                 {
                     const char *pWrapStr = nullptr;
                     auto aTmp2 = xPropSet->getPropertyValue( "HardLineBreaks" 
);
-                    auto b = o3tl::tryAccess<bool>(aTmp2);
-                    pWrapStr = (b && *b) ? OOO_STRING_SVTOOLS_HTML_WW_hard
+                    std::optional<const bool> b = o3tl::tryAccess<bool>(aTmp2);
+                    pWrapStr = (b.has_value() && *b) ? 
OOO_STRING_SVTOOLS_HTML_WW_hard
                                          : OOO_STRING_SVTOOLS_HTML_WW_soft;
                     sOptions += OString::Concat(" " 
OOO_STRING_SVTOOLS_HTML_O_wrap "=\"") +
                         pWrapStr + "\"";
diff --git a/sw/source/filter/xml/swxml.cxx b/sw/source/filter/xml/swxml.cxx
index 4664748292e6..648f7fbbe083 100644
--- a/sw/source/filter/xml/swxml.cxx
+++ b/sw/source/filter/xml/swxml.cxx
@@ -314,8 +314,8 @@ ErrCode ReadThroughComponent(
 
         Any aAny = xProps->getPropertyValue("Encrypted");
 
-        auto b = o3tl::tryAccess<bool>(aAny);
-        bool bEncrypted = b && *b;
+        std::optional<const bool> b = o3tl::tryAccess<bool>(aAny);
+        bool bEncrypted = b.has_value() && *b;
 
         uno::Reference <io::XInputStream> xInputStream = 
xStream->getInputStream();
 
diff --git a/sw/source/ui/vba/vbacontentcontrol.cxx 
b/sw/source/ui/vba/vbacontentcontrol.cxx
index 8e8d8a12382b..dc4e4afc236a 100644
--- a/sw/source/ui/vba/vbacontentcontrol.cxx
+++ b/sw/source/ui/vba/vbacontentcontrol.cxx
@@ -481,20 +481,20 @@ sal_Int32 SwVbaContentControl::getLevel()
 sal_Bool SwVbaContentControl::getLockContentControl()
 {
     std::optional<bool> oLock = m_pCC->GetLock(/*bControl=*/true);
-    return oLock && *oLock;
+    return oLock.has_value() && *oLock;
 }
 
 void SwVbaContentControl::setLockContentControl(sal_Bool bSet)
 {
     std::optional<bool> oLock = m_pCC->GetLock(/*bControl=*/false);
-    m_pCC->SetLock(/*bContents=*/oLock && *oLock, /*bControl=*/bSet);
+    m_pCC->SetLock(/*bContents=*/oLock.has_value() && *oLock, 
/*bControl=*/bSet);
 }
 
 sal_Bool SwVbaContentControl::getLockContents()
 {
     // If the theoretical design model says it is locked, then report as 
locked.
     std::optional<bool> oLock = m_pCC->GetLock(/*bControl=*/false);
-    if (oLock && *oLock)
+    if (oLock.has_value() && *oLock)
         return true;
 
     // Now check the real implementation.
@@ -513,7 +513,7 @@ void SwVbaContentControl::setLockContents(sal_Bool bSet)
 {
     // Set the lock both theoretically and actually.
     std::optional<bool> oLock = m_pCC->GetLock(/*bControl=*/true);
-    m_pCC->SetLock(/*bContents=*/bSet, /*bControl=*/oLock && *oLock);
+    m_pCC->SetLock(/*bContents=*/bSet, /*bControl=*/oLock.has_value() && 
*oLock);
 
     // Checkbox/DropDown/Picture are normally locked in LO implementation - 
don't unlock them.
     if (m_pCC->GetType() == SwContentControlType::CHECKBOX
diff --git a/sw/source/uibase/uno/unomod.cxx b/sw/source/uibase/uno/unomod.cxx
index 4599d8386b93..499f4ebea0e7 100644
--- a/sw/source/uibase/uno/unomod.cxx
+++ b/sw/source/uibase/uno/unomod.cxx
@@ -286,8 +286,8 @@ namespace
 {
     bool tryBoolAccess(const uno::Any &rValue)
     {
-        const auto xPrSet = o3tl::tryAccess<bool>(rValue);
-        if (!xPrSet)
+        const std::optional<const bool> xPrSet = o3tl::tryAccess<bool>(rValue);
+        if (!xPrSet.has_value())
             throw lang::IllegalArgumentException();
         return *xPrSet;
     }
diff --git a/sw/source/uibase/uno/unotxdoc.cxx 
b/sw/source/uibase/uno/unotxdoc.cxx
index 6a4177f6e50d..397bf0cdb205 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -1060,8 +1060,8 @@ void SwXTextDocument::setPagePrintSettings(const 
Sequence< beans::PropertyValue
         }
         else if(sName == "IsLandscape")
         {
-            auto b = o3tl::tryAccess<bool>(rVal);
-            bException = !b;
+            std::optional<const bool> b = o3tl::tryAccess<bool>(rVal);
+            bException = !b.has_value();
             if (b)
             {
                 aData.SetLandscape(*b);
@@ -1118,8 +1118,8 @@ void SwXTextDocument::printPages(const Sequence< 
beans::PropertyValue >& xOption
         // Collate-Property
         else if ( rProp.Name == UNO_NAME_COLLATE )
         {
-            auto b = o3tl::tryAccess<bool>(rProp.Value);
-            if ( !b )
+            std::optional<const bool> b = o3tl::tryAccess<bool>(rProp.Value);
+            if ( !b.has_value() )
                 throw IllegalArgumentException();
             aReq.AppendItem(SfxBoolItem( SID_PRINT_COLLATE, *b ) );
 
@@ -1128,8 +1128,8 @@ void SwXTextDocument::printPages(const Sequence< 
beans::PropertyValue >& xOption
         // Sort-Property
         else if ( rProp.Name == UNO_NAME_SORT )
         {
-            auto b = o3tl::tryAccess<bool>(rProp.Value);
-            if ( !b )
+            std::optional<const bool> b = o3tl::tryAccess<bool>(rProp.Value);
+            if ( !b.has_value() )
                 throw IllegalArgumentException();
 
             aReq.AppendItem(SfxBoolItem( SID_PRINT_SORT, *b ) );
diff --git a/ucb/source/ucp/ext/ucpext_content.cxx 
b/ucb/source/ucp/ext/ucpext_content.cxx
index 24101016810f..ee9966a52b30 100644
--- a/ucb/source/ucp/ext/ucpext_content.cxx
+++ b/ucb/source/ucp/ext/ucpext_content.cxx
@@ -577,7 +577,7 @@ namespace ucb::ucp::ext
 
     bool Content::impl_isFolder()
     {
-        if ( !!m_aIsFolder )
+        if ( m_aIsFolder.has_value() )
             return *m_aIsFolder;
 
         bool bIsFolder = false;
diff --git a/vcl/source/font/LogicalFontInstance.cxx 
b/vcl/source/font/LogicalFontInstance.cxx
index ec9740fd8812..0c21cba47548 100644
--- a/vcl/source/font/LogicalFontInstance.cxx
+++ b/vcl/source/font/LogicalFontInstance.cxx
@@ -237,7 +237,7 @@ double LogicalFontInstance::GetGlyphWidth(sal_GlyphId 
nGlyph, bool bVertical, bo
 
 bool LogicalFontInstance::IsGraphiteFont()
 {
-    if (!m_xbIsGraphiteFont)
+    if (!m_xbIsGraphiteFont.has_value())
     {
         m_xbIsGraphiteFont
             = hb_graphite2_face_get_gr_face(hb_font_get_face(GetHbFont())) != 
nullptr;

Reply via email to