formula/source/core/api/FormulaCompiler.cxx |  154 +++++++++++++++++++++++-----
 include/formula/FormulaCompiler.hxx         |   42 ++++++-
 sc/inc/addincol.hxx                         |   10 +
 sc/inc/compiler.hxx                         |    4 
 sc/inc/funcdesc.hxx                         |    2 
 sc/source/core/data/funcdesc.cxx            |    4 
 sc/source/core/data/global.cxx              |    3 
 sc/source/core/tool/addincol.cxx            |   64 ++++++-----
 sc/source/core/tool/calcconfig.cxx          |   13 ++
 sc/source/core/tool/compiler.cxx            |   10 +
 sc/source/ui/docshell/docsh6.cxx            |    3 
 11 files changed, 240 insertions(+), 69 deletions(-)

New commits:
commit 32019fae7730fc8d94f14d47ebaccbdc6775340a
Author:     Eike Rathke <[email protected]>
AuthorDate: Fri Aug 5 12:43:36 2022 +0200
Commit:     Xisco Fauli <[email protected]>
CommitDate: Mon Sep 5 16:18:47 2022 +0200

    Resolves: tdf#135993 Create ScFunctionList and ScFuncDesc with English names
    
     This is a combination of 4 commits.
    
    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.
    
    xChange-Id: I0c2db41dd45829abfb8460730264f097ab76ab2e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137881
    Tested-by: Jenkins
    Reviewed-by: Eike Rathke <[email protected]>
    (cherry picked from commit 28c4c72a4e81821d9e567757725937f74a6d114f)
    
    Related: tdf#135993 Use ScCompiler to create English OpCodeMap with AddIns
    
    ... instead of formula::FormulaCompiler base class that doesn't
    know anything about AddIns, and copy AddIns along to new resulting
    native map.
    
    xChange-Id: I9e4ece2f7450a561ac502ca1dbddaa5a697fa2fe
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137882
    Tested-by: Eike Rathke <[email protected]>
    Reviewed-by: Eike Rathke <[email protected]>
    (cherry picked from commit 0a78f11fdd13d914d5f063007b2df9796e6dce9d)
    
    Resolves: tdf#135993 Create ScFunctionList and ScFuncDesc with English names
    
    Used in Function Wizard and formula tooltips. Without, no matching
    name is found for AddIn English name and no
    tooltip/description/arguments are displayed.
    
    xChange-Id: Ib0cf419c476dae495467c444f1ee1f84a55633a7
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137883
    Tested-by: Jenkins
    Reviewed-by: Eike Rathke <[email protected]>
    (cherry picked from commit d778c6fd5c2ba8e27df46ec9e183a61ad29e30d5)
    
    Use CharClass::uppercase() for AddIns' English UI names, tdf#135993 
follow-up
    
    ... instead of OUString::toAsciiUpperCase(). English names should
    consist of ASCII alphanumeric only, but we don't know what an
    AddIn's author comes up with. Lookup in ScCompiler is done with
    CharClass as well.
    
    For this, use the static ScCompiler::GetCharClassEnglish()
    instance made public and guard creation with a mutex.
    
    xChange-Id: Icb79d49d4c7339c8d01b141de2a34715d794dd92
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138004
    Reviewed-by: Eike Rathke <[email protected]>
    Tested-by: Jenkins
    (cherry picked from commit 33c8c9d0dc8e76bc7dacb92175047a89f7d39a3c)
    
    Change-Id: Ib0cf419c476dae495467c444f1ee1f84a55633a7
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/139229
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <[email protected]>

diff --git a/formula/source/core/api/FormulaCompiler.cxx 
b/formula/source/core/api/FormulaCompiler.cxx
index be926e7d521a..591b28744289 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;
 }
 
 
@@ -1201,7 +1296,16 @@ void FormulaCompiler::OpCodeMap::copyFrom( const 
OpCodeMap& r )
         }
     }
 
-    // TODO: maybe copy the external maps too?
+    // This was meant to copy to native map that does not have AddIn symbols
+    // but needs them from the source map. It is unclear what should happen if
+    // the destination already had externals, so do it only if it doesn't.
+    if (!hasExternals())
+    {
+        maExternalHashMap = r.maExternalHashMap;
+        maReverseExternalHashMap = r.maReverseExternalHashMap;
+        mbCore = r.mbCore;
+        mbEnglish = r.mbEnglish;
+    }
 }
 
 
@@ -2588,7 +2692,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/inc/addincol.hxx b/sc/inc/addincol.hxx
index 14af12006637..bb89f8d3c87a 100644
--- a/sc/inc/addincol.hxx
+++ b/sc/inc/addincol.hxx
@@ -87,6 +87,7 @@ private:
     OUString            aLocalName;         ///< for display
     OUString            aUpperName;         ///< for entering formulas
     OUString            aUpperLocal;        ///< for entering formulas
+    OUString            aUpperEnglish;      ///< for Function Wizard and 
tooltips
     OUString            aDescription;
     css::uno::Reference< css::reflection::XIdlMethod> xFunction;
     css::uno::Any       aObject;
@@ -113,6 +114,7 @@ public:
     const OUString&  GetLocalName() const        { return aLocalName; }
     const OUString&  GetUpperName() const        { return aUpperName; }
     const OUString&  GetUpperLocal() const       { return aUpperLocal; }
+    const OUString&  GetUpperEnglish() const     { return aUpperEnglish; }
     const css::uno::Reference< css::reflection::XIdlMethod>&   GetFunction() 
const
                                                         { return xFunction; }
     const css::uno::Any& GetObject() const   { return aObject; }
@@ -132,6 +134,9 @@ public:
     void    SetArguments( tools::Long nNewCount, const ScAddInArgDesc* 
pNewDescs );
     void    SetCallerPos( tools::Long nNewPos );
     void    SetCompNames( ::std::vector< LocalizedName >&& rNew );
+
+    /// Takes care of handling an empty name *after* upper local name was set.
+    void    SetEnglishName( const OUString& rEnglishName );
 };
 
 class SC_DLLPUBLIC ScUnoAddInCollection
@@ -175,9 +180,10 @@ public:
     void                LocalizeString( OUString& rName );    ///< modify 
rName - input: exact name
 
     tools::Long                GetFuncCount();
-    bool                FillFunctionDesc( tools::Long nFunc, ScFuncDesc& rDesc 
);
+    bool                FillFunctionDesc( tools::Long nFunc, ScFuncDesc& 
rDesc, bool bEnglishFunctionNames );
 
-    static bool         FillFunctionDescFromData( const ScUnoAddInFuncData& 
rFuncData, ScFuncDesc& rDesc );
+    static bool         FillFunctionDescFromData( const ScUnoAddInFuncData& 
rFuncData, ScFuncDesc& rDesc,
+                                                  bool bEnglishFunctionNames );
                   /// leave rRetExcelName unchanged, if no matching name is 
found
     bool                GetExcelName( const OUString& rCalcName, LanguageType 
eDestLang, OUString& rRetExcelName );
                   /// leave rRetCalcName unchanged, if no matching name is 
found
diff --git a/sc/inc/compiler.hxx b/sc/inc/compiler.hxx
index 0cd48fccc92e..5f6c521d11cf 100644
--- a/sc/inc/compiler.hxx
+++ b/sc/inc/compiler.hxx
@@ -257,6 +257,7 @@ public:
 
 private:
 
+    static osl::Mutex           maMutex;
     static const CharClass      *pCharClassEnglish;     // character 
classification for en_US locale
     static const CharClass      *pCharClassLocalized;   // character 
classification for UI locale
     static const Convention     *pConventions[ 
formula::FormulaGrammar::CONV_LAST ];
@@ -377,8 +378,9 @@ private:
 
     bool HasPossibleNamedRangeConflict(SCTAB nTab) const;
 
-    static const CharClass* GetCharClassEnglish();
     static const CharClass* GetCharClassLocalized();
+public:
+    static const CharClass* GetCharClassEnglish();
 
 public:
     ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos,
diff --git a/sc/inc/funcdesc.hxx b/sc/inc/funcdesc.hxx
index 58c6957316b3..0f37e924d941 100644
--- a/sc/inc/funcdesc.hxx
+++ b/sc/inc/funcdesc.hxx
@@ -241,7 +241,7 @@ public:
 class ScFunctionList
 {
 public:
-    ScFunctionList();
+    explicit ScFunctionList( bool bEnglishFunctionNames );
     ~ScFunctionList();
 
     sal_uInt32 GetCount() const
diff --git a/sc/source/core/data/funcdesc.cxx b/sc/source/core/data/funcdesc.cxx
index dfbfd9a3a78e..c8045e6c1abf 100644
--- a/sc/source/core/data/funcdesc.cxx
+++ b/sc/source/core/data/funcdesc.cxx
@@ -397,7 +397,7 @@ bool ScFuncDesc::compareByName(const ScFuncDesc* a, const 
ScFuncDesc* b)
 
 #define ENTRY(CODE) CODE, SAL_N_ELEMENTS(CODE)
 
-ScFunctionList::ScFunctionList()
+ScFunctionList::ScFunctionList( bool bEnglishFunctionNames )
 {
     sal_Int32  nMaxFuncNameLen = 0; // Length of longest function name
 
@@ -958,7 +958,7 @@ ScFunctionList::ScFunctionList()
         pDesc = new ScFuncDesc;
         pDesc->nFIndex = nNextId++;
 
-        if ( pUnoAddIns->FillFunctionDesc( nFunc, *pDesc ) )
+        if ( pUnoAddIns->FillFunctionDesc( nFunc, *pDesc, 
bEnglishFunctionNames ) )
         {
             tmpFuncVector.push_back(pDesc);
             nStrLen = pDesc->mxFuncName->getLength();
diff --git a/sc/source/core/data/global.cxx b/sc/source/core/data/global.cxx
index a338c0c76c31..46277a807db0 100644
--- a/sc/source/core/data/global.cxx
+++ b/sc/source/core/data/global.cxx
@@ -74,6 +74,7 @@
 #include <editutil.hxx>
 #include <docsh.hxx>
 #include <sharedstringpoolpurge.hxx>
+#include <formulaopt.hxx>
 
 tools::SvRef<ScDocShell>  ScGlobal::xDrawClipDocShellRef;
 std::unique_ptr<SvxSearchItem> ScGlobal::xSearchItem;
@@ -621,7 +622,7 @@ ScFunctionList* ScGlobal::GetStarCalcFunctionList()
 {
     assert(!bThreadedGroupCalcInProgress);
     if ( !xStarCalcFunctionList )
-        xStarCalcFunctionList.reset(new ScFunctionList);
+        xStarCalcFunctionList.reset( new ScFunctionList( 
SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName()));
 
     return xStarCalcFunctionList.get();
 }
diff --git a/sc/source/core/tool/addincol.cxx b/sc/source/core/tool/addincol.cxx
index ea2184233f62..9027f0456ff4 100644
--- a/sc/source/core/tool/addincol.cxx
+++ b/sc/source/core/tool/addincol.cxx
@@ -59,6 +59,7 @@
 #include <funcdesc.hxx>
 #include <svl/sharedstring.hxx>
 #include <formulaopt.hxx>
+#include <compiler.hxx>
 #include <memory>
 
 using namespace com::sun::star;
@@ -138,6 +139,19 @@ void ScUnoAddInFuncData::SetCompNames( ::std::vector< 
ScUnoAddInFuncData::Locali
     bCompInitialized = true;
 }
 
+void ScUnoAddInFuncData::SetEnglishName( const OUString& rEnglishName )
+{
+    if (!rEnglishName.isEmpty())
+        aUpperEnglish = 
ScCompiler::GetCharClassEnglish()->uppercase(rEnglishName);
+    else
+    {
+        // A dumb fallback to not have an empty name, mainly just for the
+        // assignment to ScFuncDesc::mxFuncName for the Function Wizard and
+        // formula input tooltips.
+        aUpperEnglish = aUpperLocal;
+    }
+}
+
 bool ScUnoAddInFuncData::GetExcelName( const LanguageTag& rDestLang, OUString& 
rRetExcelName, bool bFallbackToAny ) const
 {
     const ::std::vector<LocalizedName>& rCompNames = GetCompNames();
@@ -544,9 +558,10 @@ void ScUnoAddInCollection::ReadConfiguration()
                 else
                 {
                     pEnglishHashMap->emplace(
-                            aEnglishName.toAsciiUpperCase(),
+                            
ScCompiler::GetCharClassEnglish()->uppercase(aEnglishName),
                             pData );
                 }
+                pData->SetEnglishName(aEnglishName);    // takes care of 
handling empty
             }
         }
     }
@@ -720,12 +735,11 @@ void ScUnoAddInCollection::ReadFromAddIn( const 
uno::Reference<uno::XInterface>&
     if ( !(xAddIn.is() && xName.is()) )
         return;
 
-    // fdo50118 when GetUseEnglishFunctionName() returns true, set the
-    // locale to en-US to get English function names
-    if ( SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName() )
-        xAddIn->setLocale( lang::Locale( "en", "US", ""));
-    else
-        xAddIn->setLocale( 
Application::GetSettings().GetUILanguageTag().getLocale());
+    // Even if GetUseEnglishFunctionName() would return true, do not set the
+    // locale to en-US to get English function names as that also would mix in
+    // English descriptions and parameter names. English function names are now
+    // handled below.
+    xAddIn->setLocale( 
Application::GetSettings().GetUILanguageTag().getLocale());
 
     OUString aServiceName( xName->getServiceName() );
     ScUnoAddInHelpIdGenerator aHelpIdGenerator( aServiceName );
@@ -919,8 +933,7 @@ void ScUnoAddInCollection::ReadFromAddIn( const 
uno::Reference<uno::XInterface>&
                         xFunc, aObject,
                         nVisibleCount, pVisibleArgs.get(), nCallerPos ) );
 
-                    const ScUnoAddInFuncData* pData =
-                        ppFuncData[nFuncPos+nOld].get();
+                    ScUnoAddInFuncData* pData = 
ppFuncData[nFuncPos+nOld].get();
                     pExactHashMap->emplace(
                                 pData->GetOriginalName(),
                                 pData );
@@ -937,18 +950,21 @@ void ScUnoAddInCollection::ReadFromAddIn( const 
uno::Reference<uno::XInterface>&
                     else
                     {
                         pEnglishHashMap->emplace(
-                                aEnglishName.toAsciiUpperCase(),
+                                
ScCompiler::GetCharClassEnglish()->uppercase(aEnglishName),
                                 pData );
                     }
+                    pData->SetEnglishName(aEnglishName);    // takes care of 
handling empty
                 }
             }
         }
     }
 }
 
-static void lcl_UpdateFunctionList( const ScFunctionList& rFunctionList, const 
ScUnoAddInFuncData& rFuncData )
+static void lcl_UpdateFunctionList( const ScFunctionList& rFunctionList, const 
ScUnoAddInFuncData& rFuncData,
+        bool bEnglishFunctionNames )
 {
-    const OUString& aCompare = rFuncData.GetUpperLocal();    // as used in 
FillFunctionDescFromData
+    // as used in FillFunctionDescFromData
+    const OUString& aCompare = (bEnglishFunctionNames ? 
rFuncData.GetUpperEnglish() : rFuncData.GetUpperLocal());
 
     sal_uLong nCount = rFunctionList.GetCount();
     for (sal_uLong nPos=0; nPos<nCount; nPos++)
@@ -956,7 +972,8 @@ static void lcl_UpdateFunctionList( const ScFunctionList& 
rFunctionList, const S
         const ScFuncDesc* pDesc = rFunctionList.GetFunction( nPos );
         if ( pDesc && pDesc->mxFuncName && *pDesc->mxFuncName == aCompare )
         {
-            ScUnoAddInCollection::FillFunctionDescFromData( rFuncData, 
*const_cast<ScFuncDesc*>(pDesc) );
+            ScUnoAddInCollection::FillFunctionDescFromData( rFuncData, 
*const_cast<ScFuncDesc*>(pDesc),
+                    bEnglishFunctionNames);
             break;
         }
     }
@@ -977,16 +994,10 @@ static const ScAddInArgDesc* lcl_FindArgDesc( const 
ScUnoAddInFuncData& rFuncDat
 void ScUnoAddInCollection::UpdateFromAddIn( const 
uno::Reference<uno::XInterface>& xInterface,
                                             std::u16string_view rServiceName )
 {
+    const bool bEnglishFunctionNames = 
SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName();
     uno::Reference<lang::XLocalizable> xLoc( xInterface, uno::UNO_QUERY );
     if ( xLoc.is() )        // optional in new add-ins
-    {
-        // fdo50118 when GetUseEnglishFunctionName() returns true, set the
-        // locale to en-US to get English function names
-        if ( SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName() )
-            xLoc->setLocale( lang::Locale( "en", "US", ""));
-        else
-            xLoc->setLocale( 
Application::GetSettings().GetUILanguageTag().getLocale());
-    }
+        xLoc->setLocale( 
Application::GetSettings().GetUILanguageTag().getLocale());
 
     // if function list was already initialized, it must be updated
 
@@ -1092,7 +1103,7 @@ void ScUnoAddInCollection::UpdateFromAddIn( const 
uno::Reference<uno::XInterface
                     pOldData->SetCallerPos( nCallerPos );
 
                     if ( pFunctionList )
-                        lcl_UpdateFunctionList( *pFunctionList, *pOldData );
+                        lcl_UpdateFunctionList( *pFunctionList, *pOldData, 
bEnglishFunctionNames );
                 }
             }
         }
@@ -1193,7 +1204,7 @@ tools::Long ScUnoAddInCollection::GetFuncCount()
     return nFuncCount;
 }
 
-bool ScUnoAddInCollection::FillFunctionDesc( tools::Long nFunc, ScFuncDesc& 
rDesc )
+bool ScUnoAddInCollection::FillFunctionDesc( tools::Long nFunc, ScFuncDesc& 
rDesc, bool bEnglishFunctionNames )
 {
     if (!bInitialized)
         Initialize();
@@ -1203,10 +1214,11 @@ bool ScUnoAddInCollection::FillFunctionDesc( 
tools::Long nFunc, ScFuncDesc& rDes
 
     const ScUnoAddInFuncData& rFuncData = *ppFuncData[nFunc];
 
-    return FillFunctionDescFromData( rFuncData, rDesc );
+    return FillFunctionDescFromData( rFuncData, rDesc, bEnglishFunctionNames );
 }
 
-bool ScUnoAddInCollection::FillFunctionDescFromData( const ScUnoAddInFuncData& 
rFuncData, ScFuncDesc& rDesc )
+bool ScUnoAddInCollection::FillFunctionDescFromData( const ScUnoAddInFuncData& 
rFuncData, ScFuncDesc& rDesc,
+        bool bEnglishFunctionNames )
 {
     rDesc.Clear();
 
@@ -1221,7 +1233,7 @@ bool ScUnoAddInCollection::FillFunctionDescFromData( 
const ScUnoAddInFuncData& r
 
     // nFIndex is set from outside
 
-    rDesc.mxFuncName = rFuncData.GetUpperLocal();     //TODO: upper?
+    rDesc.mxFuncName = (bEnglishFunctionNames ? rFuncData.GetUpperEnglish() : 
rFuncData.GetUpperLocal());
     rDesc.nCategory = rFuncData.GetCategory();
     rDesc.sHelpId = rFuncData.GetHelpId();
 
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;
 }
 
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index d7b628615d63..b6784f861f71 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -77,6 +77,7 @@ using namespace formula;
 using namespace ::com::sun::star;
 using ::std::vector;
 
+osl::Mutex                          ScCompiler::maMutex;
 const CharClass*                    ScCompiler::pCharClassEnglish = nullptr;
 const CharClass*                    ScCompiler::pCharClassLocalized = nullptr;
 const ScCompiler::Convention*       ScCompiler::pConventions[ ]   = { nullptr, 
nullptr, nullptr, nullptr, nullptr, nullptr };
@@ -225,9 +226,12 @@ const CharClass* ScCompiler::GetCharClassEnglish()
 {
     if (!pCharClassEnglish)
     {
-        css::lang::Locale aLocale( "en", "US", "");
-        pCharClassEnglish = new CharClass(
-                ::comphelper::getProcessComponentContext(), LanguageTag( 
aLocale));
+        osl::MutexGuard aGuard(maMutex);
+        if (!pCharClassEnglish)
+        {
+            pCharClassEnglish = new CharClass( 
::comphelper::getProcessComponentContext(),
+                    LanguageTag( LANGUAGE_ENGLISH_US));
+        }
     }
     return pCharClassEnglish;
 }
diff --git a/sc/source/ui/docshell/docsh6.cxx b/sc/source/ui/docshell/docsh6.cxx
index 738c85110967..caefdfc0fed3 100644
--- a/sc/source/ui/docshell/docsh6.cxx
+++ b/sc/source/ui/docshell/docsh6.cxx
@@ -445,7 +445,8 @@ void ScDocShell::SetFormulaOptions( const ScFormulaOptions& 
rOpt, bool bForLoadi
             if (rOpt.GetUseEnglishFuncName())
             {
                 // switch native symbols to English.
-                formula::FormulaCompiler aComp;
+                ScAddress aAddress;
+                ScCompiler aComp( *m_pDocument, aAddress);
                 ScCompiler::OpCodeMapPtr xMap = 
aComp.GetOpCodeMap(css::sheet::FormulaLanguage::ENGLISH);
                 ScCompiler::SetNativeSymbols(xMap);
             }

Reply via email to