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; }