formula/source/core/api/FormulaCompiler.cxx |  143 +++++++++++++++++++++++-----
 include/formula/FormulaCompiler.hxx         |   42 ++++++--
 sc/source/core/tool/calcconfig.cxx          |   13 ++
 3 files changed, 167 insertions(+), 31 deletions(-)

New commits:
commit 28c4c72a4e81821d9e567757725937f74a6d114f
Author:     Eike Rathke <er...@redhat.com>
AuthorDate: Fri Aug 5 12:43:36 2022 +0200
Commit:     Eike Rathke <er...@redhat.com>
CommitDate: Sat Aug 6 11:19:01 2022 +0200

    Related: tdf#135993 Destroy temporary OpCodeMap when reading config
    
    Initialized at FormulaCompiler base class instance it lacks AddIn
    mapping and a still existing OpCodeMap prevents necessary
    reinitialization from derived ScCompiler instance later.
    
    Change-Id: I0c2db41dd45829abfb8460730264f097ab76ab2e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137881
    Tested-by: Jenkins
    Reviewed-by: Eike Rathke <er...@redhat.com>

diff --git a/formula/source/core/api/FormulaCompiler.cxx 
b/formula/source/core/api/FormulaCompiler.cxx
index be926e7d521a..2b0db73d1a39 100644
--- a/formula/source/core/api/FormulaCompiler.cxx
+++ b/formula/source/core/api/FormulaCompiler.cxx
@@ -823,37 +823,37 @@ FormulaCompiler::OpCodeMapPtr 
FormulaCompiler::GetOpCodeMap( const sal_Int32 nLa
     {
         case FormulaLanguage::ODFF :
             if (!mxSymbolsODFF)
-                InitSymbolsODFF();
+                InitSymbolsODFF( InitSymbols::INIT);
             xMap = mxSymbolsODFF;
             break;
         case FormulaLanguage::ODF_11 :
             if (!mxSymbolsPODF)
-                InitSymbolsPODF();
+                InitSymbolsPODF( InitSymbols::INIT);
             xMap = mxSymbolsPODF;
             break;
         case FormulaLanguage::ENGLISH :
             if (!mxSymbolsEnglish)
-                InitSymbolsEnglish();
+                InitSymbolsEnglish( InitSymbols::INIT);
             xMap = mxSymbolsEnglish;
             break;
         case FormulaLanguage::NATIVE :
             if (!mxSymbolsNative)
-                InitSymbolsNative();
+                InitSymbolsNative( InitSymbols::INIT);
             xMap = mxSymbolsNative;
             break;
         case FormulaLanguage::XL_ENGLISH:
             if (!mxSymbolsEnglishXL)
-                InitSymbolsEnglishXL();
+                InitSymbolsEnglishXL( InitSymbols::INIT);
             xMap = mxSymbolsEnglishXL;
             break;
         case FormulaLanguage::OOXML:
             if (!mxSymbolsOOXML)
-                InitSymbolsOOXML();
+                InitSymbolsOOXML( InitSymbols::INIT);
             xMap = mxSymbolsOOXML;
             break;
         case FormulaLanguage::API :
             if (!mxSymbolsAPI)
-                InitSymbolsAPI();
+                InitSymbolsAPI( InitSymbols::INIT);
             xMap = mxSymbolsAPI;
             break;
         default:
@@ -862,6 +862,62 @@ FormulaCompiler::OpCodeMapPtr 
FormulaCompiler::GetOpCodeMap( const sal_Int32 nLa
     return xMap;
 }
 
+void FormulaCompiler::DestroyOpCodeMap( const sal_Int32 nLanguage )
+{
+    using namespace sheet;
+    switch (nLanguage)
+    {
+        case FormulaLanguage::ODFF :
+            InitSymbolsODFF( InitSymbols::DESTROY);
+            break;
+        case FormulaLanguage::ODF_11 :
+            InitSymbolsPODF( InitSymbols::DESTROY);
+            break;
+        case FormulaLanguage::ENGLISH :
+            InitSymbolsEnglish( InitSymbols::DESTROY);
+            break;
+        case FormulaLanguage::NATIVE :
+            InitSymbolsNative( InitSymbols::DESTROY);
+            break;
+        case FormulaLanguage::XL_ENGLISH:
+            InitSymbolsEnglishXL( InitSymbols::DESTROY);
+            break;
+        case FormulaLanguage::OOXML:
+            InitSymbolsOOXML( InitSymbols::DESTROY);
+            break;
+        case FormulaLanguage::API :
+            InitSymbolsAPI( InitSymbols::DESTROY);
+            break;
+        default:
+            ;   // nothing
+    }
+}
+
+bool FormulaCompiler::HasOpCodeMap( const sal_Int32 nLanguage ) const
+{
+    using namespace sheet;
+    switch (nLanguage)
+    {
+        case FormulaLanguage::ODFF :
+            return InitSymbolsODFF( InitSymbols::ASK);
+        case FormulaLanguage::ODF_11 :
+            return InitSymbolsPODF( InitSymbols::ASK);
+        case FormulaLanguage::ENGLISH :
+            return InitSymbolsEnglish( InitSymbols::ASK);
+        case FormulaLanguage::NATIVE :
+            return InitSymbolsNative( InitSymbols::ASK);
+        case FormulaLanguage::XL_ENGLISH:
+            return InitSymbolsEnglishXL( InitSymbols::ASK);
+        case FormulaLanguage::OOXML:
+            return InitSymbolsOOXML( InitSymbols::ASK);
+        case FormulaLanguage::API :
+            return InitSymbolsAPI( InitSymbols::ASK);
+        default:
+            ;   // nothing
+    }
+    return false;
+}
+
 OUString FormulaCompiler::FindAddInFunction( const OUString& /*rUpperName*/, 
bool /*bLocalFirst*/ ) const
 {
     return OUString();
@@ -898,12 +954,16 @@ FormulaCompiler::OpCodeMapPtr 
FormulaCompiler::CreateOpCodeMap(
     return xMap;
 }
 
-static void lcl_fillNativeSymbols( FormulaCompiler::NonConstOpCodeMapPtr& 
xMap, bool bDestroy = false )
+static bool lcl_fillNativeSymbols( FormulaCompiler::NonConstOpCodeMapPtr& 
xMap, FormulaCompiler::InitSymbols eWhat = FormulaCompiler::InitSymbols::INIT )
 {
     static OpCodeMapData aSymbolMap;
     osl::MutexGuard aGuard(&aSymbolMap.maMtx);
 
-    if ( bDestroy )
+    if (eWhat == FormulaCompiler::InitSymbols::ASK)
+    {
+        return bool(aSymbolMap.mxSymbolMap);
+    }
+    else if (eWhat == FormulaCompiler::InitSymbols::DESTROY)
     {
         aSymbolMap.mxSymbolMap.reset();
     }
@@ -919,6 +979,8 @@ static void lcl_fillNativeSymbols( 
FormulaCompiler::NonConstOpCodeMapPtr& xMap,
     }
 
     xMap = aSymbolMap.mxSymbolMap;
+
+    return true;
 }
 
 const OUString& FormulaCompiler::GetNativeSymbol( OpCode eOp )
@@ -933,54 +995,80 @@ sal_Unicode FormulaCompiler::GetNativeSymbolChar( OpCode 
eOp )
     return GetNativeSymbol(eOp)[0];
 }
 
-void FormulaCompiler::InitSymbolsNative() const
+bool FormulaCompiler::InitSymbolsNative( FormulaCompiler::InitSymbols eWhat ) 
const
 {
-    lcl_fillNativeSymbols( mxSymbolsNative);
+    return lcl_fillNativeSymbols( mxSymbolsNative, eWhat);
 }
 
-void FormulaCompiler::InitSymbolsEnglish() const
+bool FormulaCompiler::InitSymbolsEnglish( FormulaCompiler::InitSymbols eWhat ) 
const
 {
     static OpCodeMapData aMap;
     osl::MutexGuard aGuard(&aMap.maMtx);
-    if (!aMap.mxSymbolMap)
+    if (eWhat == InitSymbols::ASK)
+        return bool(aMap.mxSymbolMap);
+    else if (eWhat == InitSymbols::DESTROY)
+        aMap.mxSymbolMap.reset();
+    else if (!aMap.mxSymbolMap)
         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, 
FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
     mxSymbolsEnglish = aMap.mxSymbolMap;
+    return true;
 }
 
-void FormulaCompiler::InitSymbolsPODF() const
+bool FormulaCompiler::InitSymbolsPODF( FormulaCompiler::InitSymbols eWhat ) 
const
 {
     static OpCodeMapData aMap;
     osl::MutexGuard aGuard(&aMap.maMtx);
-    if (!aMap.mxSymbolMap)
+    if (eWhat == InitSymbols::ASK)
+        return bool(aMap.mxSymbolMap);
+    else if (eWhat == InitSymbols::DESTROY)
+        aMap.mxSymbolMap.reset();
+    else if (!aMap.mxSymbolMap)
         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_PODF, 
FormulaGrammar::GRAM_PODF, aMap.mxSymbolMap, SeparatorType::RESOURCE_BASE);
     mxSymbolsPODF = aMap.mxSymbolMap;
+    return true;
 }
 
-void FormulaCompiler::InitSymbolsAPI() const
+bool FormulaCompiler::InitSymbolsAPI( FormulaCompiler::InitSymbols eWhat ) 
const
 {
     static OpCodeMapData aMap;
     osl::MutexGuard aGuard(&aMap.maMtx);
-    if (!aMap.mxSymbolMap)
+    if (eWhat == InitSymbols::ASK)
+        return bool(aMap.mxSymbolMap);
+    else if (eWhat == InitSymbols::DESTROY)
+        aMap.mxSymbolMap.reset();
+    else if (!aMap.mxSymbolMap)
         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_API, 
FormulaGrammar::GRAM_API, aMap.mxSymbolMap, SeparatorType::RESOURCE_BASE);
     mxSymbolsAPI = aMap.mxSymbolMap;
+    return true;
 }
 
-void FormulaCompiler::InitSymbolsODFF() const
+bool FormulaCompiler::InitSymbolsODFF( FormulaCompiler::InitSymbols eWhat ) 
const
 {
     static OpCodeMapData aMap;
     osl::MutexGuard aGuard(&aMap.maMtx);
-    if (!aMap.mxSymbolMap)
+    if (eWhat == InitSymbols::ASK)
+        return bool(aMap.mxSymbolMap);
+    else if (eWhat == InitSymbols::DESTROY)
+        aMap.mxSymbolMap.reset();
+    else if (!aMap.mxSymbolMap)
         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF, 
FormulaGrammar::GRAM_ODFF, aMap.mxSymbolMap, SeparatorType::RESOURCE_BASE);
     mxSymbolsODFF = aMap.mxSymbolMap;
+    return true;
 }
 
-void FormulaCompiler::InitSymbolsEnglishXL() const
+bool FormulaCompiler::InitSymbolsEnglishXL( FormulaCompiler::InitSymbols eWhat 
) const
 {
     static OpCodeMapData aMap;
     osl::MutexGuard aGuard(&aMap.maMtx);
-    if (!aMap.mxSymbolMap)
+    if (eWhat == InitSymbols::ASK)
+        return bool(aMap.mxSymbolMap);
+    else if (eWhat == InitSymbols::DESTROY)
+        aMap.mxSymbolMap.reset();
+    else if (!aMap.mxSymbolMap)
         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, 
FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
     mxSymbolsEnglishXL = aMap.mxSymbolMap;
+    if (eWhat != InitSymbols::INIT)
+        return true;
 
     // TODO: For now, just replace the separators to the Excel English
     // variants. Later, if we want to properly map Excel functions with Calc
@@ -988,15 +1076,22 @@ void FormulaCompiler::InitSymbolsEnglishXL() const
     mxSymbolsEnglishXL->putOpCode( OUString(','), ocSep, nullptr);
     mxSymbolsEnglishXL->putOpCode( OUString(','), ocArrayColSep, nullptr);
     mxSymbolsEnglishXL->putOpCode( OUString(';'), ocArrayRowSep, nullptr);
+
+    return true;
 }
 
-void FormulaCompiler::InitSymbolsOOXML() const
+bool FormulaCompiler::InitSymbolsOOXML( FormulaCompiler::InitSymbols eWhat ) 
const
 {
     static OpCodeMapData aMap;
     osl::MutexGuard aGuard(&aMap.maMtx);
-    if (!aMap.mxSymbolMap)
+    if (eWhat == InitSymbols::ASK)
+        return bool(aMap.mxSymbolMap);
+    else if (eWhat == InitSymbols::DESTROY)
+        aMap.mxSymbolMap.reset();
+    else if (!aMap.mxSymbolMap)
         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML, 
FormulaGrammar::GRAM_OOXML, aMap.mxSymbolMap, SeparatorType::RESOURCE_BASE);
     mxSymbolsOOXML = aMap.mxSymbolMap;
+    return true;
 }
 
 
@@ -2588,7 +2683,7 @@ void FormulaCompiler::UpdateSeparatorsNative(
 void FormulaCompiler::ResetNativeSymbols()
 {
     NonConstOpCodeMapPtr xSymbolsNative;
-    lcl_fillNativeSymbols( xSymbolsNative, true);
+    lcl_fillNativeSymbols( xSymbolsNative, InitSymbols::DESTROY);
     lcl_fillNativeSymbols( xSymbolsNative);
 }
 
diff --git a/include/formula/FormulaCompiler.hxx 
b/include/formula/FormulaCompiler.hxx
index 5544ff8786c0..36632035602e 100644
--- a/include/formula/FormulaCompiler.hxx
+++ b/include/formula/FormulaCompiler.hxx
@@ -203,6 +203,26 @@ public:
      */
     OpCodeMapPtr GetOpCodeMap( const sal_Int32 nLanguage ) const;
 
+    /** Destroy the singleton OpCodeMap for formula language.
+
+        This unconditionally destroys the underlying singleton instance of the
+        map to be reinitialized again later on the next GetOpCodeMap() call.
+        Use if the base class FormulaCompiler::GetOpCodeMap() was called and
+        created the map (i.e. HasOpCodeMap() before returned false) and later a
+        derived class like ScCompiler shall initialize it including AddIns.
+
+        @param nLanguage
+            One of css::sheet::FormulaLanguage constants.
+     */
+    void DestroyOpCodeMap( const sal_Int32 nLanguage );
+
+    /** Whether the singleton OpCodeMap for formula language exists already.
+
+        @param nLanguage
+            One of css::sheet::FormulaLanguage constants.
+     */
+    bool HasOpCodeMap( const sal_Int32 nLanguage ) const;
+
     /** Create an internal symbol map from API mapping.
         @param bEnglish
             Use English number parser / formatter instead of native.
@@ -370,14 +390,22 @@ protected:
     bool mbComputeII;  // whether to attempt computing implicit intersection 
ranges while building the RPN array.
     bool mbMatrixFlag; // whether the formula is a matrix formula (needed for 
II computation)
 
+public:
+    enum InitSymbols
+    {
+        ASK = 0,
+        INIT,
+        DESTROY
+    };
+
 private:
-    void InitSymbolsNative() const;    /// only SymbolsNative, on first 
document creation
-    void InitSymbolsEnglish() const;   /// only SymbolsEnglish, maybe later
-    void InitSymbolsPODF() const;      /// only SymbolsPODF, on demand
-    void InitSymbolsAPI() const;       /// only SymbolsAPI, on demand
-    void InitSymbolsODFF() const;      /// only SymbolsODFF, on demand
-    void InitSymbolsEnglishXL() const; /// only SymbolsEnglishXL, on demand
-    void InitSymbolsOOXML() const;     /// only SymbolsOOXML, on demand
+    bool InitSymbolsNative( InitSymbols ) const;    /// only SymbolsNative, on 
first document creation
+    bool InitSymbolsEnglish( InitSymbols ) const;   /// only SymbolsEnglish, 
maybe later
+    bool InitSymbolsPODF( InitSymbols ) const;      /// only SymbolsPODF, on 
demand
+    bool InitSymbolsAPI( InitSymbols ) const;       /// only SymbolsAPI, on 
demand
+    bool InitSymbolsODFF( InitSymbols ) const;      /// only SymbolsODFF, on 
demand
+    bool InitSymbolsEnglishXL( InitSymbols ) const; /// only SymbolsEnglishXL, 
on demand
+    bool InitSymbolsOOXML( InitSymbols ) const;     /// only SymbolsOOXML, on 
demand
 
     void loadSymbols(const std::pair<const char*, int>* pSymbols, 
FormulaGrammar::Grammar eGrammar, NonConstOpCodeMapPtr& rxMap,
             SeparatorType eSepType = SeparatorType::SEMICOLON_BASE) const;
diff --git a/sc/source/core/tool/calcconfig.cxx 
b/sc/source/core/tool/calcconfig.cxx
index f1673e0ebe68..27836704dab9 100644
--- a/sc/source/core/tool/calcconfig.cxx
+++ b/sc/source/core/tool/calcconfig.cxx
@@ -187,7 +187,11 @@ bool ScCalcConfig::operator!= (const ScCalcConfig& r) const
 OUString ScOpCodeSetToSymbolicString(const ScCalcConfig::OpCodeSet& rOpCodes)
 {
     OUStringBuffer result(256);
+    // If GetOpCodeMap() initializes the map at base class
+    // formula::FormulaCompiler before any ScCompiler did, all AddIn mapping
+    // would be missing also in future. So if it didn't exist destroy it again.
     formula::FormulaCompiler aCompiler;
+    const bool bTemporary = 
!aCompiler.HasOpCodeMap(css::sheet::FormulaLanguage::ENGLISH);
     formula::FormulaCompiler::OpCodeMapPtr 
pOpCodeMap(aCompiler.GetOpCodeMap(css::sheet::FormulaLanguage::ENGLISH));
 
     for (auto i = rOpCodes->begin(); i != rOpCodes->end(); ++i)
@@ -197,13 +201,18 @@ OUString ScOpCodeSetToSymbolicString(const 
ScCalcConfig::OpCodeSet& rOpCodes)
         result.append(pOpCodeMap->getSymbol(*i));
     }
 
+    if (bTemporary)
+        aCompiler.DestroyOpCodeMap(css::sheet::FormulaLanguage::ENGLISH);
+
     return result.makeStringAndClear();
 }
 
 ScCalcConfig::OpCodeSet ScStringToOpCodeSet(std::u16string_view rOpCodes)
 {
     ScCalcConfig::OpCodeSet result = std::make_shared<o3tl::sorted_vector< 
OpCode >>();
+    // Same as above.
     formula::FormulaCompiler aCompiler;
+    const bool bTemporary = 
!aCompiler.HasOpCodeMap(css::sheet::FormulaLanguage::ENGLISH);
     formula::FormulaCompiler::OpCodeMapPtr 
pOpCodeMap(aCompiler.GetOpCodeMap(css::sheet::FormulaLanguage::ENGLISH));
 
     const formula::OpCodeHashMap& rHashMap(pOpCodeMap->getHashMap());
@@ -234,6 +243,10 @@ ScCalcConfig::OpCodeSet 
ScStringToOpCodeSet(std::u16string_view rOpCodes)
     // HACK: Both unary and binary minus have the same string but different 
opcodes.
     if( result->find( ocSub ) != result->end())
         result->insert( ocNegSub );
+
+    if (bTemporary)
+        aCompiler.DestroyOpCodeMap(css::sheet::FormulaLanguage::ENGLISH);
+
     return result;
 }
 

Reply via email to