cid#1640468 Dereference after null check
[LibreOffice.git] / sc / source / core / tool / recursionhelper.cxx
blob59601f37a0a6be722c9cc291c852f6fa74de92d7
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/.
8 */
10 #include <recursionhelper.hxx>
11 #include <formulacell.hxx>
13 void ScRecursionHelper::Init()
15 nRecursionCount = 0;
16 nDependencyComputationLevel = 0;
17 bInRecursionReturn = bDoingRecursion = bInIterationReturn = false;
18 bAbortingDependencyComputation = false;
19 aInsertPos = GetIterationEnd();
20 ResetIteration();
21 // Must not force clear aFGList ever.
24 void ScRecursionHelper::ResetIteration()
26 aLastIterationStart = GetIterationEnd();
27 nIteration = 0;
28 bConverging = false;
31 ScRecursionHelper::ScRecursionHelper()
33 pFGSet = nullptr;
34 bGroupsIndependent = true;
35 Init();
38 void ScRecursionHelper::SetInRecursionReturn( bool b )
40 // Do not use IsInRecursionReturn() here, it decouples iteration.
41 if (b && !bInRecursionReturn)
42 aInsertPos = aRecursionFormulas.begin();
43 bInRecursionReturn = b;
46 void ScRecursionHelper::Insert(
47 ScFormulaCell* p, bool bOldRunning, const ScFormulaResult & rRes )
49 aRecursionFormulas.insert( aInsertPos, ScFormulaRecursionEntry( p,
50 bOldRunning, rRes));
53 void ScRecursionHelper::SetInIterationReturn( bool b )
55 // An iteration return is always coupled to a recursion return.
56 SetInRecursionReturn( b);
57 bInIterationReturn = b;
60 void ScRecursionHelper::StartIteration()
62 SetInIterationReturn( false);
63 nIteration = 1;
64 bConverging = false;
65 aLastIterationStart = GetIterationStart();
68 void ScRecursionHelper::ResumeIteration()
70 SetInIterationReturn( false);
71 aLastIterationStart = GetIterationStart();
74 void ScRecursionHelper::IncIteration()
76 ++nIteration;
79 void ScRecursionHelper::EndIteration()
81 aRecursionFormulas.erase( GetIterationStart(), GetIterationEnd());
82 ResetIteration();
85 ScFormulaRecursionList::iterator ScRecursionHelper::GetIterationStart()
87 return aRecursionFormulas.begin();
90 ScFormulaRecursionList::iterator ScRecursionHelper::GetIterationEnd()
92 return aRecursionFormulas.end();
95 void ScRecursionHelper::Clear()
97 aRecursionFormulas.clear();
98 while (!aRecursionInIterationStack.empty())
99 aRecursionInIterationStack.pop();
100 Init();
103 static ScFormulaCell* lcl_GetTopCell(ScFormulaCell* pCell)
105 if (!pCell)
106 return nullptr;
108 const ScFormulaCellGroupRef& mxGroup = pCell->GetCellGroup();
109 if (!mxGroup)
110 return pCell;
111 return mxGroup->mpTopCell;
114 bool ScRecursionHelper::PushFormulaGroup(ScFormulaCell* pCell)
116 assert(pCell);
118 if (pCell->GetSeenInPath())
120 // Found a simple cycle of formula-groups.
121 // Disable group calc for all elements of this cycle.
122 sal_Int32 nIdx = aFGList.size();
123 assert(nIdx > 0);
126 --nIdx;
127 assert(nIdx >= 0);
128 const ScFormulaCellGroupRef& mxGroup = aFGList[nIdx]->GetCellGroup();
129 if (mxGroup)
130 mxGroup->mbPartOfCycle = true;
131 } while (aFGList[nIdx] != pCell);
133 return false;
136 pCell->SetSeenInPath(true);
137 aFGList.push_back(pCell);
138 aInDependencyEvalMode.push_back(false);
139 return true;
142 void ScRecursionHelper::PopFormulaGroup()
144 assert(aFGList.size() == aInDependencyEvalMode.size());
145 if (aFGList.empty())
146 return;
147 ScFormulaCell* pCell = aFGList.back();
148 pCell->SetSeenInPath(false);
149 aFGList.pop_back();
150 aInDependencyEvalMode.pop_back();
153 bool ScRecursionHelper::AnyCycleMemberInDependencyEvalMode(const ScFormulaCell* pCell)
155 assert(pCell);
157 if (pCell->GetSeenInPath())
159 // Found a simple cycle of formula-groups.
160 sal_Int32 nIdx = aFGList.size();
161 assert(nIdx > 0);
164 --nIdx;
165 assert(nIdx >= 0);
166 const ScFormulaCellGroupRef& mxGroup = aFGList[nIdx]->GetCellGroup();
167 // Found a cycle member FG that is in dependency evaluation mode.
168 if (mxGroup && aInDependencyEvalMode[nIdx])
169 return true;
170 } while (aFGList[nIdx] != pCell);
172 return false;
175 return false;
178 bool ScRecursionHelper::AnyParentFGInCycle()
180 sal_Int32 nIdx = aFGList.size() - 1;
181 while (nIdx >= 0)
183 const ScFormulaCellGroupRef& mxGroup = aFGList[nIdx]->GetCellGroup();
184 if (mxGroup)
185 return mxGroup->mbPartOfCycle;
186 --nIdx;
188 return false;
191 void ScRecursionHelper::SetFormulaGroupDepEvalMode(bool bSet)
193 assert(aFGList.size());
194 assert(aFGList.size() == aInDependencyEvalMode.size());
195 assert(aFGList.back()->GetCellGroup());
196 aInDependencyEvalMode.back() = bSet;
199 void ScRecursionHelper::AbortDependencyComputation()
201 assert( nDependencyComputationLevel > 0 );
202 bAbortingDependencyComputation = true;
205 void ScRecursionHelper::IncDepComputeLevel()
207 ++nDependencyComputationLevel;
210 void ScRecursionHelper::DecDepComputeLevel()
212 --nDependencyComputationLevel;
213 bAbortingDependencyComputation = false;
216 void ScRecursionHelper::AddTemporaryGroupCell(ScFormulaCell* cell)
218 aTemporaryGroupCells.push_back( cell );
221 void ScRecursionHelper::CleanTemporaryGroupCells()
223 if( GetRecursionCount() == 0 )
225 for( ScFormulaCell* cell : aTemporaryGroupCells )
226 cell->SetCellGroup( nullptr );
227 aTemporaryGroupCells.clear();
231 bool ScRecursionHelper::CheckFGIndependence(ScFormulaCellGroup* pFG)
233 if (pFGSet && pFGSet->count(pFG))
235 bGroupsIndependent = false;
236 return false;
239 return true;
242 ScFormulaGroupCycleCheckGuard::ScFormulaGroupCycleCheckGuard(ScRecursionHelper& rRecursionHelper, ScFormulaCell* pCell) :
243 mrRecHelper(rRecursionHelper)
245 if (pCell)
247 pCell = lcl_GetTopCell(pCell);
248 mbShouldPop = mrRecHelper.PushFormulaGroup(pCell);
250 else
251 mbShouldPop = false;
254 ScFormulaGroupCycleCheckGuard::~ScFormulaGroupCycleCheckGuard()
256 if (mbShouldPop)
257 mrRecHelper.PopFormulaGroup();
260 ScFormulaGroupDependencyComputeGuard::ScFormulaGroupDependencyComputeGuard(ScRecursionHelper& rRecursionHelper) :
261 mrRecHelper(rRecursionHelper)
263 mrRecHelper.IncDepComputeLevel();
264 mrRecHelper.SetFormulaGroupDepEvalMode(true);
267 ScFormulaGroupDependencyComputeGuard::~ScFormulaGroupDependencyComputeGuard()
269 mrRecHelper.SetFormulaGroupDepEvalMode(false);
270 mrRecHelper.DecDepComputeLevel();
273 ScCheckIndependentFGGuard::ScCheckIndependentFGGuard(ScRecursionHelper& rRecursionHelper,
274 o3tl::sorted_vector<ScFormulaCellGroup*>* pSet) :
275 mrRecHelper(rRecursionHelper),
276 mbUsedFGSet(false)
278 if (!mrRecHelper.HasFormulaGroupSet())
280 mrRecHelper.SetFormulaGroupSet(pSet);
281 mrRecHelper.SetGroupsIndependent(true);
282 mbUsedFGSet = true;
286 ScCheckIndependentFGGuard::~ScCheckIndependentFGGuard()
288 if (mbUsedFGSet)
290 // Reset to defaults.
291 mrRecHelper.SetFormulaGroupSet(nullptr);
292 mrRecHelper.SetGroupsIndependent(true);
296 bool ScCheckIndependentFGGuard::AreGroupsIndependent()
298 if (!mbUsedFGSet)
299 return false;
301 return mrRecHelper.AreGroupsIndependent();
304 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */