[Libreoffice-commits] core.git: Branch 'feature/formula-core-rework' - sc/source

Kohei Yoshida kohei.yoshida at gmail.com
Wed Aug 7 21:54:48 PDT 2013


 sc/source/core/data/formulacell.cxx |   99 ++++++++++++++++++++++++++++++++++--
 sc/source/core/tool/token.cxx       |    3 -
 2 files changed, 96 insertions(+), 6 deletions(-)

New commits:
commit a14b77f904d9ca905c6665523cca9ab452f2e4d4
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Thu Aug 8 00:27:15 2013 -0400

    Detect self-referencing groups, and disable group-calculation.
    
    And re-enable group-calculation on named ranges.
    
    Change-Id: I4957ff05bac23bd266bbc96fe5619ad5f0a65688

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index fd103bc..c87b045 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 9f58380..d74182d 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


More information about the Libreoffice-commits mailing list