diff options
author | Kohei Yoshida <kohei.yoshida@gmail.com> | 2013-08-08 00:27:15 -0400 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@gmail.com> | 2013-08-12 19:46:28 -0400 |
commit | 6f8b0d419b99a02050a9dd8bdf04a6c86a48fe61 (patch) | |
tree | 8122e08abaf50230ba9f19778253cd20bf5bef8f | |
parent | 0c7dd40e63bd6aa401fb731f9ac9daeb30c6e8f1 (diff) |
Detect self-referencing groups, and disable group-calculation.
And re-enable group-calculation on named ranges.
Change-Id: I4957ff05bac23bd266bbc96fe5619ad5f0a65688
-rw-r--r-- | sc/source/core/data/formulacell.cxx | 99 | ||||
-rw-r--r-- | sc/source/core/tool/token.cxx | 3 |
2 files changed, 96 insertions, 6 deletions
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index fd103bc9c844..c87b04501a0f 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -3279,6 +3279,49 @@ class GroupTokenConverter ScDocument& mrDoc; ScFormulaCell& mrCell; const ScAddress& mrPos; + + bool isSelfReferenceRelative(const ScAddress& rRefPos, SCROW nRelRow) + { + if (rRefPos.Col() != mrPos.Col()) + return false; + + SCROW nLen = mrCell.GetCellGroup()->mnLength; + SCROW nEndRow = mrPos.Row() + nLen - 1; + + if (nRelRow < 0) + { + SCROW nTest = nEndRow; + nTest += nRelRow; + if (nTest >= mrPos.Row()) + return true; + } + else if (nRelRow > 0) + { + SCROW nTest = mrPos.Row(); // top row. + nTest += nRelRow; + if (nTest <= nEndRow) + return true; + } + + return false; + } + + bool isSelfReferenceAbsolute(const ScAddress& rRefPos) + { + if (rRefPos.Col() != mrPos.Col()) + return false; + + SCROW nLen = mrCell.GetCellGroup()->mnLength; + SCROW nEndRow = mrPos.Row() + nLen - 1; + + if (rRefPos.Row() < mrPos.Row()) + return false; + + if (rRefPos.Row() > nEndRow) + return false; + + return true; + } public: GroupTokenConverter(sc::FormulaGroupContext& rCxt, ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell, const ScAddress& rPos) : mrCxt(rCxt), mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell), mrPos(rPos) {} @@ -3302,6 +3345,7 @@ public: // absolute reference state for row directions. const ScToken* pToken = static_cast<const ScToken*>(p); + SCROW nLen = mrCell.GetCellGroup()->mnLength; switch (pToken->GetType()) { case svSingleRef: @@ -3310,20 +3354,26 @@ public: ScAddress aRefPos = aRef.toAbs(mrPos); if (aRef.IsRowRel()) { + if (isSelfReferenceRelative(aRefPos, aRef.Row())) + return false; + // Fetch double array guarantees that the length of the // returned array equals or greater than the requested // length. - const double* pArray = mrDoc.FetchDoubleArray(mrCxt, aRefPos, mrCell.GetCellGroup()->mnLength); + const double* pArray = mrDoc.FetchDoubleArray(mrCxt, aRefPos, nLen); if (!pArray) return false; - formula::SingleVectorRefToken aTok(pArray, mrCell.GetCellGroup()->mnLength); + formula::SingleVectorRefToken aTok(pArray, nLen); mrGroupTokens.AddToken(aTok); } else { // Absolute row reference. + if (isSelfReferenceAbsolute(aRefPos)) + return false; + formula::FormulaTokenRef pNewToken = mrDoc.ResolveStaticReference(aRefPos); if (!pNewToken) return false; @@ -3337,6 +3387,23 @@ public: ScComplexRefData aRef = pToken->GetDoubleRef(); ScRange aAbs = aRef.toAbs(mrCell.aPos); + // Check for self reference. + if (aRef.Ref1.IsRowRel()) + { + if (isSelfReferenceRelative(aAbs.aStart, aRef.Ref1.Row())) + return false; + } + else if (isSelfReferenceAbsolute(aAbs.aStart)) + return false; + + if (aRef.Ref2.IsRowRel()) + { + if (isSelfReferenceRelative(aAbs.aEnd, aRef.Ref2.Row())) + return false; + } + else if (isSelfReferenceAbsolute(aAbs.aEnd)) + return false; + // Row reference is relative. bool bAbsFirst = !aRef.Ref1.IsRowRel(); bool bAbsLast = !aRef.Ref2.IsRowRel(); @@ -3344,7 +3411,7 @@ public: size_t nCols = aAbs.aEnd.Col() - aAbs.aStart.Col() + 1; std::vector<const double*> aArrays; aArrays.reserve(nCols); - SCROW nArrayLength = mrCell.GetCellGroup()->mnLength; + SCROW nArrayLength = nLen; SCROW nRefRowSize = aAbs.aEnd.Row() - aAbs.aStart.Row() + 1; if (!bAbsLast) { @@ -3366,6 +3433,32 @@ public: mrGroupTokens.AddToken(aTok); } break; + case svIndex: + { + // Named range. + ScRangeName* pNames = mrDoc.GetRangeName(); + if (!pNames) + // This should never fail. + return false; + + ScRangeData* pRange = pNames->findByIndex(p->GetIndex()); + if (!pRange) + // No named range exists by that index. + return false; + + ScTokenArray* pNamedTokens = pRange->GetCode(); + if (!pNamedTokens) + // This named range is empty. + return false; + + mrGroupTokens.AddOpCode(ocOpen); + + if (!convert(*pNamedTokens)) + return false; + + mrGroupTokens.AddOpCode(ocClose); + } + break; default: mrGroupTokens.AddToken(*pToken); } diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index 9f5838013c6a..d74182d9a065 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -1347,9 +1347,6 @@ void ScTokenArray::CheckToken( const FormulaToken& r ) ; } } - - if (eOp == ocName) - meVectorState = FormulaVectorDisabled; } bool ScTokenArray::ImplGetReference( ScRange& rRange, const ScAddress& rPos, bool bValidOnly ) const |