ofz: Use-of-uninitialized-value
[LibreOffice.git] / sc / inc / formulacell.hxx
blob013a0058ba5d897b9c3cec94bbc42908b21455ba
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #pragma once
22 #include <map>
23 #include <memory>
24 #include <optional>
26 #include <formula/tokenarray.hxx>
27 #include <formula/errorcodes.hxx>
28 #include <svl/listener.hxx>
30 #include "types.hxx"
31 #include "interpretercontext.hxx"
32 #include "document.hxx"
33 #include "docoptio.hxx"
34 #include "formulalogger.hxx"
35 #include "formularesult.hxx"
36 #include "tokenarray.hxx"
38 namespace sc {
40 class StartListeningContext;
41 class EndListeningContext;
42 struct RefUpdateContext;
43 struct RefUpdateInsertTabContext;
44 struct RefUpdateDeleteTabContext;
45 struct RefUpdateMoveTabContext;
46 class CompileFormulaContext;
47 class FormulaGroupAreaListener;
48 class UpdatedRangeNames;
52 class ScFormulaCell;
53 class ScProgress;
54 enum class SvNumFormatType : sal_Int16;
56 struct AreaListenerKey
58 ScRange maRange;
59 bool mbStartFixed;
60 bool mbEndFixed;
62 AreaListenerKey( const ScRange& rRange, bool bStartFixed, bool bEndFixed ) :
63 maRange(rRange), mbStartFixed(bStartFixed), mbEndFixed(bEndFixed) {}
65 bool operator < ( const AreaListenerKey& r ) const;
68 typedef std::map<AreaListenerKey, std::unique_ptr<sc::FormulaGroupAreaListener>> AreaListenersType;
70 struct SC_DLLPUBLIC ScFormulaCellGroup
72 AreaListenersType m_AreaListeners;
73 public:
75 mutable size_t mnRefCount;
77 std::optional<ScTokenArray> mpCode;
78 ScFormulaCell *mpTopCell;
79 SCROW mnLength; // How many of these do we have ?
80 sal_Int32 mnWeight;
81 SvNumFormatType mnFormatType;
82 bool mbInvariant:1;
83 bool mbSubTotal:1;
84 bool mbPartOfCycle:1; // To flag FG's part of a cycle
86 sal_uInt8 meCalcState;
88 ScFormulaCellGroup();
89 ScFormulaCellGroup(const ScFormulaCellGroup&) = delete;
90 const ScFormulaCellGroup& operator=(const ScFormulaCellGroup&) = delete;
91 ~ScFormulaCellGroup();
93 void setCode( const ScTokenArray& rCode );
94 void compileCode(
95 ScDocument& rDoc, const ScAddress& rPos, formula::FormulaGrammar::Grammar eGram );
97 sc::FormulaGroupAreaListener* getAreaListener(
98 ScFormulaCell** ppTopCell, const ScRange& rRange, bool bStartFixed, bool bEndFixed );
100 void endAllGroupListening( ScDocument& rDoc );
103 inline void intrusive_ptr_add_ref(const ScFormulaCellGroup *p)
105 p->mnRefCount++;
108 inline void intrusive_ptr_release(const ScFormulaCellGroup *p)
110 if( --p->mnRefCount == 0 )
111 delete p;
114 enum class ScMatrixMode : sal_uInt8 {
115 NONE = 0, // No matrix formula
116 Formula = 1, // Upper left matrix formula cell
117 Reference = 2 // Remaining cells, via ocMatRef reference token
120 class SC_DLLPUBLIC ScFormulaCell final : public SvtListener
122 private:
123 ScFormulaCellGroupRef mxGroup; // Group of formulae we're part of
124 bool bDirty : 1; // Must be (re)calculated
125 bool bTableOpDirty : 1; // Dirty flag for TableOp
126 bool bChanged : 1; // Whether something changed regarding display/representation
127 bool bRunning : 1; // Already interpreting right now
128 bool bCompile : 1; // Must be (re)compiled
129 bool bSubTotal : 1; // Cell is part of or contains a SubTotal
130 bool bIsIterCell : 1; // Cell is part of a circular reference
131 bool bInChangeTrack : 1; // Cell is in ChangeTrack
132 bool bNeedListening : 1; // Listeners need to be re-established after UpdateReference
133 bool mbNeedsNumberFormat : 1; // set the calculated number format as hard number format
134 bool mbAllowNumberFormatChange : 1; /* allow setting further calculated
135 number formats as hard number format */
136 bool mbPostponedDirty : 1; // if cell needs to be set dirty later
137 bool mbIsExtRef : 1; // has references in ScExternalRefManager; never cleared after set
138 bool mbSeenInPath : 1; // For detecting cycle involving formula groups and singleton formulacells
139 bool mbFreeFlying : 1; // Cell is out of sheets interpreted, like in conditional format
140 ScMatrixMode cMatrixFlag : 8;
141 sal_uInt16 nSeenInIteration : 16; // Iteration cycle in which the cell was last encountered
142 SvNumFormatType nFormatType : 16;
143 ScFormulaResult aResult;
144 formula::FormulaGrammar::Grammar eTempGrammar; // used between string (creation) and (re)compilation
145 // If this cell is in a cell group (mxGroup!=nullptr), then this pCode is a not-owning pointer
146 // to the mxGroup's mpCode, which owns the array. If the cell is not in a group, this is an owning pointer.
147 ScTokenArray* pCode; // The token array
148 ScDocument& rDocument;
149 ScFormulaCell* pPrevious;
150 ScFormulaCell* pNext;
151 ScFormulaCell* pPreviousTrack;
152 ScFormulaCell* pNextTrack;
155 * Update reference in response to cell copy-n-paste.
157 bool UpdateReferenceOnCopy(
158 const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
160 ScFormulaCell( const ScFormulaCell& ) = delete;
162 bool CheckComputeDependencies(sc::FormulaLogger::GroupScope& rScope, bool fromFirstRow,
163 SCROW nStartOffset, SCROW nEndOffset, bool bCalcDependencyOnly = false);
164 bool InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope& aScope,
165 bool& bDependencyComputed,
166 bool& bDependencyCheckFailed,
167 SCROW nStartOffset, SCROW nEndOffset);
168 bool InterpretFormulaGroupOpenCL(sc::FormulaLogger::GroupScope& aScope,
169 bool& bDependencyComputed,
170 bool& bDependencyCheckFailed);
171 bool InterpretInvariantFormulaGroup();
173 public:
176 enum ScInterpretTailParameter
178 SCITP_NORMAL,
179 SCITP_FROM_ITERATION,
180 SCITP_CLOSE_ITERATION_CIRCLE
182 void InterpretTail( ScInterpreterContext&, ScInterpretTailParameter );
184 void HandleStuffAfterParallelCalculation(ScInterpreter* pInterpreter);
186 enum CompareState { NotEqual = 0, EqualInvariant, EqualRelativeRef };
188 ScAddress aPos;
190 virtual ~ScFormulaCell() override;
192 ScFormulaCell* Clone() const;
193 ScFormulaCell* Clone( const ScAddress& rPos ) const;
195 ScFormulaCell( ScDocument& rDoc, const ScAddress& rPos );
198 * Transfer the ownership of the passed token array instance to the
199 * formula cell being constructed. The caller <i>must not</i> pass a NULL
200 * token array pointer.
202 ScFormulaCell( ScDocument& rDoc, const ScAddress& rPos, std::unique_ptr<ScTokenArray> pArray,
203 const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT,
204 ScMatrixMode cMatInd = ScMatrixMode::NONE );
206 ScFormulaCell( ScDocument& rDoc, const ScAddress& rPos, const ScTokenArray& rArray,
207 const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT,
208 ScMatrixMode cMatInd = ScMatrixMode::NONE );
210 ScFormulaCell( ScDocument& rDoc, const ScAddress& rPos, const ScFormulaCellGroupRef& xGroup,
211 const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT,
212 ScMatrixMode = ScMatrixMode::NONE );
214 /** With formula string and grammar to compile with.
215 formula::FormulaGrammar::GRAM_DEFAULT effectively isformula::FormulaGrammar::GRAM_NATIVE_UI that
216 also includes formula::FormulaGrammar::CONV_UNSPECIFIED, therefore uses the address
217 convention associated with rPos::nTab by default. */
218 ScFormulaCell( ScDocument& rDoc, const ScAddress& rPos,
219 const OUString& rFormula,
220 const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT,
221 ScMatrixMode cMatInd = ScMatrixMode::NONE );
223 ScFormulaCell(const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, ScCloneFlags nCloneFlags = ScCloneFlags::Default);
225 void SetFreeFlying( bool b ) { mbFreeFlying = b; }
227 size_t GetHash() const;
229 OUString GetFormula( const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT,
230 const ScInterpreterContext* pContext = nullptr ) const;
231 OUString GetFormula( sc::CompileFormulaContext& rCxt, const ScInterpreterContext* pContext = nullptr ) const;
233 void SetDirty( bool bDirtyFlag=true );
234 void SetDirtyVar();
235 // If setting entire document dirty after load, no broadcasts but still append to FormulaTree.
236 void SetDirtyAfterLoad();
237 void ResetTableOpDirtyVar();
238 void SetTableOpDirty();
240 bool IsDirtyOrInTableOpDirty() const
242 return bDirty || (bTableOpDirty && rDocument.IsInInterpreterTableOp());
245 bool GetDirty() const { return bDirty; }
246 void ResetDirty();
247 bool NeedsListening() const { return bNeedListening; }
248 void SetNeedsListening( bool bVar );
249 void SetNeedsDirty( bool bVar );
250 void SetNeedNumberFormat( bool bVal );
251 bool NeedsNumberFormat() const { return mbNeedsNumberFormat;}
252 SvNumFormatType GetFormatType() const { return nFormatType; }
253 void Compile(const OUString& rFormula,
254 bool bNoListening,
255 const formula::FormulaGrammar::Grammar );
256 void Compile(
257 sc::CompileFormulaContext& rCxt, const OUString& rFormula, bool bNoListening = false );
259 void CompileTokenArray( bool bNoListening = false );
260 void CompileTokenArray( sc::CompileFormulaContext& rCxt, bool bNoListening = false );
261 void CompileXML( sc::CompileFormulaContext& rCxt, ScProgress& rProgress ); // compile temporary string tokens
262 void CalcAfterLoad( sc::CompileFormulaContext& rCxt, bool bStartListening );
263 bool MarkUsedExternalReferences();
264 bool Interpret(SCROW nStartOffset = -1, SCROW nEndOffset = -1);
265 bool IsIterCell() const { return bIsIterCell; }
266 sal_uInt16 GetSeenInIteration() const { return nSeenInIteration; }
268 bool HasOneReference( ScRange& r ) const;
269 /* Checks if the formula contains reference list that can be
270 expressed by one reference (like A1;A2;A3:A5 -> A1:A5). The
271 reference list is not required to be sorted (i.e. A3;A1;A2 is
272 still recognized as A1:A3), but no overlapping is allowed.
273 If one reference is recognized, the rRange is filled.
275 It is similar to HasOneReference(), but more general.
277 bool HasRefListExpressibleAsOneReference(ScRange& rRange) const;
279 enum class RelNameRef
281 NONE, ///< no relative reference from named expression
282 SINGLE, ///< only single cell relative reference
283 DOUBLE ///< at least one range relative reference from named expression
285 RelNameRef HasRelNameReference() const;
287 bool UpdateReference(
288 const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = nullptr, const ScAddress* pUndoCellPos = nullptr );
291 * Shift the position of formula cell as part of reference update.
293 * @return true if the position has shifted, false otherwise.
295 bool UpdatePosOnShift( const sc::RefUpdateContext& rCxt );
298 * Update reference in response to cell insertion or deletion.
300 bool UpdateReferenceOnShift(
301 const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
304 * Update reference in response to cell move.
306 bool UpdateReferenceOnMove(
307 const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
309 void TransposeReference();
310 void UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
311 ScDocument* pUndoDoc );
313 void UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY );
315 void UpdateInsertTab( const sc::RefUpdateInsertTabContext& rCxt );
316 void UpdateInsertTabAbs(SCTAB nTable);
317 void UpdateDeleteTab( const sc::RefUpdateDeleteTabContext& rCxt );
318 void UpdateMoveTab( const sc::RefUpdateMoveTabContext& rCxt, SCTAB nTabNo );
319 bool TestTabRefAbs(SCTAB nTable);
320 void UpdateCompile( bool bForceIfNameInUse );
321 void FindRangeNamesInUse(sc::UpdatedRangeNames& rIndexes) const;
322 bool IsSubTotal() const { return bSubTotal;}
323 bool IsChanged() const { return bChanged;}
324 void SetChanged(bool b);
325 bool IsEmpty(); // formula::svEmptyCell result
326 // display as empty string if formula::svEmptyCell result
327 bool IsEmptyDisplayedAsString();
328 bool IsValue(); // also true if formula::svEmptyCell
329 bool IsValueNoError();
330 bool IsValueNoError() const;
331 double GetValue();
332 const svl::SharedString & GetString();
335 * Get a numeric value without potentially triggering re-calculation.
337 double GetRawValue() const;
340 * Get a string value without potentially triggering re-calculation.
342 const svl::SharedString & GetRawString() const;
343 const ScMatrix* GetMatrix();
344 bool GetMatrixOrigin( const ScDocument& rDoc, ScAddress& rPos ) const;
345 void GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows );
346 sc::MatrixEdge GetMatrixEdge( const ScDocument& rDoc, ScAddress& rOrgPos ) const;
347 FormulaError GetErrCode(); // interpret first if necessary
348 FormulaError GetRawError() const; // don't interpret, just return code or result error
349 bool GetErrorOrValue( FormulaError& rErr, double& rVal );
350 sc::FormulaResultValue GetResult();
351 sc::FormulaResultValue GetResult() const;
352 ScMatrixMode GetMatrixFlag() const { return cMatrixFlag;}
353 ScTokenArray* GetCode() { return pCode;}
354 const ScTokenArray* GetCode() const { return pCode;}
356 void SetCode( std::unique_ptr<ScTokenArray> pNew );
358 bool IsRunning() const { return bRunning;}
359 void SetRunning( bool bVal );
360 void CompileDBFormula( sc::CompileFormulaContext& rCxt );
361 void CompileColRowNameFormula( sc::CompileFormulaContext& rCxt );
362 ScFormulaCell* GetPrevious() const { return pPrevious; }
363 ScFormulaCell* GetNext() const { return pNext; }
364 void SetPrevious( ScFormulaCell* pF );
365 void SetNext( ScFormulaCell* pF );
366 ScFormulaCell* GetPreviousTrack() const { return pPreviousTrack; }
367 ScFormulaCell* GetNextTrack() const { return pNextTrack; }
368 void SetPreviousTrack( ScFormulaCell* pF );
369 void SetNextTrack( ScFormulaCell* pF );
371 virtual void Notify( const SfxHint& rHint ) override;
372 virtual void Query( SvtListener::QueryBase& rQuery ) const override;
374 void SetCompile( bool bVal );
375 ScDocument& GetDocument() const { return rDocument;}
376 void SetMatColsRows( SCCOL nCols, SCROW nRows );
377 void GetMatColsRows( SCCOL& nCols, SCROW& nRows ) const;
379 // cell belongs to ChangeTrack and not to the real document
380 void SetInChangeTrack( bool bVal );
381 bool IsInChangeTrack() const { return bInChangeTrack;}
383 // For import filters!
384 void AddRecalcMode( ScRecalcMode );
385 /** For import only: set a double result. */
386 void SetHybridDouble( double n );
387 /** For import only: set a string result.
388 If for whatever reason you have to use both, SetHybridDouble() and
389 SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
390 for performance reasons.*/
391 void SetHybridString( const svl::SharedString& r );
392 /** For import only: set an empty cell result to be displayed as empty string.
393 If for whatever reason you have to use both, SetHybridDouble() and
394 SetHybridEmptyDisplayedAsString() or SetHybridFormula(), use
395 SetHybridDouble() first for performance reasons and use
396 SetHybridEmptyDisplayedAsString() last because SetHybridDouble() and
397 SetHybridString() will override it.*/
398 void SetHybridEmptyDisplayedAsString();
399 /** For import only: set a temporary formula string to be compiled later.
400 If for whatever reason you have to use both, SetHybridDouble() and
401 SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
402 for performance reasons.*/
403 void SetHybridFormula(
404 const OUString& r, const formula::FormulaGrammar::Grammar eGrammar );
406 OUString GetHybridFormula() const;
408 void SetResultMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, const formula::FormulaToken* pUL );
410 /** For import only: set a double result.
411 Use this instead of SetHybridDouble() if there is no (temporary)
412 formula string because the formula is present as a token array, as it
413 is the case for binary Excel import.
415 void SetResultDouble( double n );
417 void SetResultToken( const formula::FormulaToken* pToken );
419 const svl::SharedString & GetResultString() const;
421 bool HasHybridStringResult() const;
423 /* Sets the shared code array to error state in addition to the cell result */
424 void SetErrCode( FormulaError n );
426 /* Sets just the result to error */
427 void SetResultError( FormulaError n );
429 bool IsHyperLinkCell() const;
430 std::unique_ptr<EditTextObject> CreateURLObject();
431 void GetURLResult( OUString& rURL, OUString& rCellText );
433 /** Determines whether or not the result string contains more than one paragraph */
434 bool IsMultilineResult();
436 bool NeedsInterpret() const
438 if (bIsIterCell)
439 // Shortcut to force return of current value and not enter Interpret()
440 // as we're looping over all iteration cells.
441 return false;
443 if (!IsDirtyOrInTableOpDirty())
444 return false;
446 return (rDocument.GetAutoCalc() || (cMatrixFlag != ScMatrixMode::NONE));
449 void MaybeInterpret()
451 if (NeedsInterpret())
453 if (bRunning && !rDocument.GetDocOptions().IsIter() && rDocument.IsThreadedGroupCalcInProgress())
455 // This is actually copied from Interpret()'s if(bRunning)
456 // block that once caught this circular reference but now is
457 // prepended with various threaded group calc things which the
458 // assert() below is supposed to fail on when entering again.
459 // Nevertheless, we need some state here the caller can obtain.
460 aResult.SetResultError( FormulaError::CircularReference );
462 else
464 assert(!rDocument.IsThreadedGroupCalcInProgress());
465 Interpret();
471 * Turn a non-grouped cell into the top of a grouped cell.
473 ScFormulaCellGroupRef CreateCellGroup( SCROW nLen, bool bInvariant );
474 const ScFormulaCellGroupRef& GetCellGroup() const { return mxGroup;}
475 void SetCellGroup( const ScFormulaCellGroupRef &xRef );
477 CompareState CompareByTokenArray( const ScFormulaCell& rOther ) const;
479 bool InterpretFormulaGroup(SCROW nStartOffset = -1, SCROW nEndOffset = -1);
481 // nOnlyNames may be one or more of SC_LISTENING_NAMES_*
482 void StartListeningTo( ScDocument& rDoc );
483 void StartListeningTo( sc::StartListeningContext& rCxt );
484 void EndListeningTo(
485 ScDocument& rDoc, ScTokenArray* pArr = nullptr, ScAddress aPos = ScAddress() );
486 void EndListeningTo( sc::EndListeningContext& rCxt );
488 bool IsShared() const;
489 bool IsSharedTop() const;
490 SCROW GetSharedTopRow() const;
491 SCROW GetSharedLength() const;
493 // An estimate of the number of cells referenced by the formula
494 sal_Int32 GetWeight() const;
496 ScTokenArray* GetSharedCode();
497 const ScTokenArray* GetSharedCode() const;
499 void SyncSharedCode();
501 bool IsPostponedDirty() const { return mbPostponedDirty;}
503 void SetIsExtRef() { mbIsExtRef = true; }
504 bool GetSeenInPath() const { return mbSeenInPath; }
505 void SetSeenInPath(bool bSet) { mbSeenInPath = bSet; }
507 #if DUMP_COLUMN_STORAGE
508 void Dump() const;
509 #endif
512 inline bool ScDocument::IsInFormulaTree( const ScFormulaCell* pCell ) const { return pCell->GetPrevious() || pFormulaTree == pCell; }
513 inline bool ScDocument::IsInFormulaTrack( const ScFormulaCell* pCell ) const { return pCell->GetPreviousTrack() || pFormulaTrack == pCell; }
515 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */