[Libreoffice-commits] core.git: 2 commits - sc/inc sc/qa sc/source

Noel Grandin (via logerrit) logerrit at kemper.freedesktop.org
Fri Dec 13 18:42:41 UTC 2019


 sc/inc/address.hxx                     |    6 ++
 sc/inc/compiler.hxx                    |    8 +--
 sc/inc/document.hxx                    |   44 ++++++++++++----
 sc/inc/token.hxx                       |    7 +-
 sc/inc/tokenarray.hxx                  |    8 ++-
 sc/qa/unit/ucalc.hxx                   |    2 
 sc/qa/unit/ucalc_formula.cxx           |   20 +++++++
 sc/source/core/data/documen2.cxx       |    8 +--
 sc/source/core/tool/compiler.cxx       |   66 ++++++++++++-------------
 sc/source/core/tool/interpr2.cxx       |    6 +-
 sc/source/core/tool/interpr4.cxx       |   14 ++---
 sc/source/core/tool/reftokenhelper.cxx |    8 +--
 sc/source/core/tool/token.cxx          |   86 ++++++++++++++++++---------------
 sc/source/ui/unoobj/chart2uno.cxx      |   10 +--
 14 files changed, 177 insertions(+), 116 deletions(-)

New commits:
commit 113444f59dc7690850919155b9b164b1a686bbe7
Author:     Noel Grandin <noel.grandin at collabora.co.uk>
AuthorDate: Fri Dec 13 15:59:51 2019 +0200
Commit:     Noel Grandin <noel.grandin at collabora.co.uk>
CommitDate: Fri Dec 13 19:41:59 2019 +0100

    sc: rowcol: tdf#50916 create ScSheetLimits to hold by rtl::Reference
    
    ScTokenArray sometimes outlives the ScDocument that created it, which
    means it accesses dead data when it tries to validate columns and rows.
    
    So create the ScSheetLimits class, which ScTokenArray can hold by
    reference counted pointer.
    
    Change-Id: Ic5771734fe4962d12f024fc1b29232124c14208a
    Reviewed-on: https://gerrit.libreoffice.org/85117
    Tested-by: Jenkins
    Reviewed-by: Michael Meeks <michael.meeks at collabora.com>

diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx
index 1d6680cb8ebf..5a1f7d91f2ab 100644
--- a/sc/inc/address.hxx
+++ b/sc/inc/address.hxx
@@ -90,11 +90,13 @@ const SCROW MAXROW_30         = 8191;
 
 [[nodiscard]] inline bool ValidCol( SCCOL nCol, SCCOL nMaxCol = MAXCOL )
 {
+    assert(nMaxCol == MAXCOL); // temporary to debug jumbo sheets work
     return nCol >= 0 && nCol <= nMaxCol;
 }
 
 [[nodiscard]] inline bool ValidRow( SCROW nRow, SCROW nMaxRow = MAXROW)
 {
+    assert(nMaxRow == MAXROW); // temporary to debug jumbo sheets work
     return nRow >= 0 && nRow <= nMaxRow;
 }
 
@@ -110,21 +112,25 @@ const SCROW MAXROW_30         = 8191;
 
 [[nodiscard]] inline bool ValidColRow( SCCOL nCol, SCROW nRow, SCCOL nMaxCol = MAXCOL, SCROW nMaxRow = MAXROW )
 {
+    assert(nMaxRow == MAXROW); // temporary to debug jumbo sheets work
     return ValidCol(nCol,nMaxCol) && ValidRow(nRow,nMaxRow);
 }
 
 [[nodiscard]] inline bool ValidColRowTab( SCCOL nCol, SCROW nRow, SCTAB nTab, SCCOL nMaxCol = MAXCOL, SCROW nMaxRow = MAXROW )
 {
+    assert(nMaxRow == MAXROW); // temporary to debug jumbo sheets work
     return ValidCol(nCol,nMaxCol) && ValidRow(nRow,nMaxRow) && ValidTab( nTab);
 }
 
 [[nodiscard]] inline SCCOL SanitizeCol( SCCOL nCol, SCCOL nMaxCol = MAXCOL )
 {
+    assert(nMaxCol == MAXCOL); // temporary to debug jumbo sheets work
     return nCol < 0 ? 0 : (nCol > nMaxCol ? nMaxCol : nCol);
 }
 
 [[nodiscard]] inline SCROW SanitizeRow( SCROW nRow, SCROW nMaxRow = MAXROW )
 {
+    assert(nMaxRow == MAXROW); // temporary to debug jumbo sheets work
     return nRow < 0 ? 0 : (nRow > nMaxRow ? nMaxRow : nRow);
 }
 
diff --git a/sc/inc/compiler.hxx b/sc/inc/compiler.hxx
index dce569c2b68a..623f94945943 100644
--- a/sc/inc/compiler.hxx
+++ b/sc/inc/compiler.hxx
@@ -39,6 +39,8 @@
 
 #include <formula/FormulaCompiler.hxx>
 
+struct ScSheetLimits;
+
 // constants and data types also for external modules (ScInterpreter et al)
 
 #define MAXSTRLEN    1024   /* maximum length of input string of one symbol */
@@ -167,7 +169,7 @@ public:
      */
     bool IsValidReference(const ScDocument* pDoc) const;
 
-    formula::FormulaToken* CreateToken(const ScDocument* pDoc) const;   // create typified token
+    formula::FormulaToken* CreateToken(ScSheetLimits& rLimits) const;   // create typified token
 };
 
 class SC_DLLPUBLIC ScCompiler : public formula::FormulaCompiler
@@ -189,7 +191,7 @@ public:
         virtual ~Convention();
 
         virtual void makeRefStr(
-            const ScDocument* pDoc,
+            ScSheetLimits& rLimits,
             OUStringBuffer& rBuffer,
             formula::FormulaGrammar::Grammar eGram,
             const ScAddress& rPos,
@@ -220,7 +222,7 @@ public:
             const OUString& rTabName, const ScSingleRefData& rRef ) const = 0;
 
         virtual void makeExternalRefStr(
-            const ScDocument* pDoc,
+            ScSheetLimits& rLimits,
             OUStringBuffer& rBuffer, const ScAddress& rPos,
             sal_uInt16 nFileId, const OUString& rFileName, const std::vector<OUString>& rTabNames,
             const OUString& rTabName, const ScComplexRefData& rRef ) const = 0;
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index e160c8d4b735..94c9b2820c17 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -20,6 +20,7 @@
 #ifndef INCLUDED_SC_INC_DOCUMENT_HXX
 #define INCLUDED_SC_INC_DOCUMENT_HXX
 
+#include <salhelper/simplereferenceobject.hxx>
 #include <vcl/idle.hxx>
 #include <vcl/errcode.hxx>
 #include <com/sun/star/uno/Reference.hxx>
@@ -280,6 +281,25 @@ const sal_uInt8 SC_DDE_ENGLISH       = 1;
 const sal_uInt8 SC_DDE_TEXT          = 2;
 const sal_uInt8 SC_DDE_IGNOREMODE    = 255;       /// For usage in FindDdeLink() only!
 
+// Because some stuff needs this info, and those objects lifetimes sometimes exceeds the lifetime
+// of the ScDocument.
+struct ScSheetLimits : public salhelper::SimpleReferenceObject
+{
+    const SCCOL mnMaxCol; /// Maximum addressable column
+    const SCROW mnMaxRow; /// Maximum addressable row
+
+    ScSheetLimits(SCCOL nMaxCol, SCROW nMaxRow) : mnMaxCol(nMaxCol), mnMaxRow(nMaxRow) {}
+
+    [[nodiscard]] bool ValidCol(SCCOL nCol) const { return ::ValidCol(nCol, mnMaxCol); }
+    [[nodiscard]] bool ValidRow(SCROW nRow) const { return ::ValidRow(nRow, mnMaxRow); }
+    [[nodiscard]] bool ValidColRow(SCCOL nCol, SCROW nRow) const { return ::ValidColRow(nCol, nRow, mnMaxCol, mnMaxRow); }
+    [[nodiscard]] bool ValidColRowTab(SCCOL nCol, SCROW nRow, SCTAB nTab) const { return ::ValidColRowTab(nCol, nRow, nTab, mnMaxCol, mnMaxRow); }
+    [[nodiscard]] bool ValidRange(const ScRange& rRange) const { return ::ValidRange(rRange, mnMaxCol, mnMaxRow); }
+    [[nodiscard]] bool ValidAddress(const ScAddress& rAddress) const { return ::ValidAddress(rAddress, mnMaxCol, mnMaxRow); }
+    [[nodiscard]] SCCOL SanitizeCol( SCCOL nCol ) const { return ::SanitizeCol(nCol, mnMaxCol); }
+    [[nodiscard]] SCROW SanitizeRow( SCROW nRow ) const { return ::SanitizeRow(nRow, mnMaxRow); }
+};
+
 // During threaded calculation fields being mutated are kept in this struct
 struct ScDocumentThreadSpecific
 {
@@ -371,8 +391,7 @@ private:
     std::unique_ptr<ScValidationDataList> pValidationList;              // validity
     SvNumberFormatterIndexTable* pFormatExchangeList;    // for application of number formats
     TableContainer maTabs;
-    SCCOL mnMaxCol; /// Maximum addressable column
-    SCROW mnMaxRow; /// Maximum addressable row
+    rtl::Reference<ScSheetLimits> mxSheetLimits;
     std::vector<OUString> maTabNames;               // for undo document, we need the information tab name <-> index
     mutable std::unique_ptr<ScRangeName>    pRangeName;
     std::unique_ptr<ScDBCollection>         pDBCollection;
@@ -856,16 +875,17 @@ public:
     SC_DLLPUBLIC bool GetCodeName( SCTAB nTab, OUString& rName ) const;
     SC_DLLPUBLIC bool SetCodeName( SCTAB nTab, const OUString& rName );
     SC_DLLPUBLIC bool GetTable( const OUString& rName, SCTAB& rTab ) const;
-    SC_DLLPUBLIC SCCOL MaxCol() const { return mnMaxCol; }
-    SC_DLLPUBLIC SCROW MaxRow() const { return mnMaxRow; }
-    [[nodiscard]] bool ValidCol(SCCOL nCol) const { return ::ValidCol(nCol, mnMaxCol); }
-    [[nodiscard]] bool ValidRow(SCROW nRow) const { return ::ValidRow(nRow, mnMaxRow); }
-    [[nodiscard]] bool ValidColRow(SCCOL nCol, SCROW nRow) const { return ::ValidColRow(nCol, nRow, mnMaxCol, mnMaxRow); }
-    [[nodiscard]] bool ValidColRowTab(SCCOL nCol, SCROW nRow, SCTAB nTab) const { return ::ValidColRowTab(nCol, nRow, nTab, mnMaxCol, mnMaxRow); }
-    [[nodiscard]] bool ValidRange(const ScRange& rRange) const { return ::ValidRange(rRange, mnMaxCol, mnMaxRow); }
-    [[nodiscard]] bool ValidAddress(const ScAddress& rAddress) const { return ::ValidAddress(rAddress, mnMaxCol, mnMaxRow); }
-    [[nodiscard]] SCCOL SanitizeCol( SCCOL nCol ) const { return ::SanitizeCol(nCol, mnMaxCol); }
-    [[nodiscard]] SCROW SanitizeRow( SCROW nRow ) const { return ::SanitizeRow(nRow, mnMaxRow); }
+    SC_DLLPUBLIC SCCOL MaxCol() const { return mxSheetLimits->mnMaxCol; }
+    SC_DLLPUBLIC SCROW MaxRow() const { return mxSheetLimits->mnMaxRow; }
+    ScSheetLimits& GetSheetLimits() const { return *mxSheetLimits; }
+    [[nodiscard]] bool ValidCol(SCCOL nCol) const { return ::ValidCol(nCol, mxSheetLimits->mnMaxCol); }
+    [[nodiscard]] bool ValidRow(SCROW nRow) const { return ::ValidRow(nRow, mxSheetLimits->mnMaxRow); }
+    [[nodiscard]] bool ValidColRow(SCCOL nCol, SCROW nRow) const { return ::ValidColRow(nCol, nRow, MaxCol(), MaxRow()); }
+    [[nodiscard]] bool ValidColRowTab(SCCOL nCol, SCROW nRow, SCTAB nTab) const { return ::ValidColRowTab(nCol, nRow, nTab, MaxCol(), MaxRow()); }
+    [[nodiscard]] bool ValidRange(const ScRange& rRange) const { return ::ValidRange(rRange, MaxCol(), MaxRow()); }
+    [[nodiscard]] bool ValidAddress(const ScAddress& rAddress) const { return ::ValidAddress(rAddress, MaxCol(), MaxRow()); }
+    [[nodiscard]] SCCOL SanitizeCol( SCCOL nCol ) const { return ::SanitizeCol(nCol, MaxCol()); }
+    [[nodiscard]] SCROW SanitizeRow( SCROW nRow ) const { return ::SanitizeRow(nRow, MaxRow()); }
 
     SC_DLLPUBLIC std::vector<OUString> GetAllTableNames() const;
 
diff --git a/sc/inc/token.hxx b/sc/inc/token.hxx
index 58adad226284..ff52adac2031 100644
--- a/sc/inc/token.hxx
+++ b/sc/inc/token.hxx
@@ -35,6 +35,7 @@
 
 class ScJumpMatrix;
 class ScMatrix;
+struct ScSheetLimits;
 
 typedef ::std::vector< ScComplexRefData > ScRefList;
 
@@ -54,14 +55,14 @@ void DumpToken(formula::FormulaToken const & rToken);
         A reused or new'ed ScDoubleRefToken, or a NULL TokenRef if rTok1 or
         rTok2 are not of sv(Single|Double)Ref
 */
-formula::FormulaTokenRef extendRangeReference( const ScDocument* pDoc, formula::FormulaToken & rTok1, formula::FormulaToken & rTok2, const ScAddress & rPos, bool bReuseDoubleRef );
+formula::FormulaTokenRef extendRangeReference( ScSheetLimits& rLimits, formula::FormulaToken & rTok1, formula::FormulaToken & rTok2, const ScAddress & rPos, bool bReuseDoubleRef );
 
 class ScSingleRefToken final : public formula::FormulaToken
 {
 private:
     ScSingleRefData   aSingleRef;
 public:
-                                ScSingleRefToken( const ScDocument* /*pDoc*/, const ScSingleRefData& r, OpCode e = ocPush ) :
+                                ScSingleRefToken( ScSheetLimits& , const ScSingleRefData& r, OpCode e = ocPush ) :
                                     FormulaToken( formula::svSingleRef, e ), aSingleRef( r ) {}
     virtual const ScSingleRefData*    GetSingleRef() const override;
     virtual ScSingleRefData*      GetSingleRef() override;
@@ -75,7 +76,7 @@ class ScDoubleRefToken final : public formula::FormulaToken
 private:
     ScComplexRefData  aDoubleRef;
 public:
-                                ScDoubleRefToken( const ScDocument* /*pDoc*/, const ScComplexRefData& r, OpCode e = ocPush  ) :
+                                ScDoubleRefToken( ScSheetLimits&, const ScComplexRefData& r, OpCode e = ocPush  ) :
                                     FormulaToken( formula::svDoubleRef, e ), aDoubleRef( r ) {}
     virtual const ScSingleRefData*    GetSingleRef() const override;
     virtual ScSingleRefData*      GetSingleRef() override;
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index ae6eb22a593f..37ccf6b67c06 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -21,6 +21,7 @@
 #define INCLUDED_SC_INC_TOKENARRAY_HXX
 
 #include <formula/token.hxx>
+#include <rtl/ref.hxx>
 #include "scdllapi.h"
 #include "types.hxx"
 #include "calcmacros.hxx"
@@ -43,14 +44,16 @@ class ColRowReorderMapType;
 struct ScRawToken;
 struct ScSingleRefData;
 struct ScComplexRefData;
+struct ScSheetLimits;
 
 class SAL_WARN_UNUSED SC_DLLPUBLIC ScTokenArray final : public formula::FormulaTokenArray
 {
     friend class ScCompiler;
 
-    bool ImplGetReference( const ScDocument* pDoc, ScRange& rRange, const ScAddress& rPos, bool bValidOnly ) const;
+    bool ImplGetReference( ScRange& rRange, const ScAddress& rPos, bool bValidOnly ) const;
 
-    const ScDocument* mpDoc;
+    // hold a reference to the limits because sometimes our lifetime exceeds the lifetime of the associated ScDocument
+    rtl::Reference<ScSheetLimits> mxSheetLimits;
     size_t mnHashValue;
     ScFormulaVectorState meVectorState : 4; // Only 4 bits
     bool mbOpenCLEnabled : 1;
@@ -60,6 +63,7 @@ class SAL_WARN_UNUSED SC_DLLPUBLIC ScTokenArray final : public formula::FormulaT
 
 public:
     ScTokenArray(const ScDocument* pDoc);
+    ScTokenArray(ScSheetLimits&);
     /** Assignment with incrementing references of FormulaToken entries
         (not copied!) */
     ScTokenArray( const ScTokenArray& ) = default;
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index a779371f83b7..af09ab3f21c7 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -100,8 +100,7 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
         mpPrinter( nullptr ),
         mpVirtualDevice_100th_mm( nullptr ),
         pFormatExchangeList( nullptr ),
-        mnMaxCol(MAXCOL),
-        mnMaxRow(MAXROW),
+        mxSheetLimits(new ScSheetLimits(MAXCOL, MAXROW)),
         pFormulaTree( nullptr ),
         pEOFormulaTree( nullptr ),
         pFormulaTrack( nullptr ),
@@ -173,10 +172,9 @@ ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
     const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
     if (rOpt.GetInitJumboSheets())
     {
-        mnMaxCol = 16384;
-        mnMaxRow = 16 * 1000 * 1000;
+        mxSheetLimits = new ScSheetLimits(16384, 16 * 1000 * 1000);
     }
-    maPreviewSelection = { mnMaxRow, mnMaxCol };
+    maPreviewSelection = { MaxRow(), MaxCol() };
     aCurTextWidthCalcPos = { MaxCol(), 0, 0 };
 
     SetStorageGrammar( formula::FormulaGrammar::GRAM_STORAGE_DEFAULT);
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index 3d4a2def3552..7f1460db8f51 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -832,7 +832,7 @@ struct ConventionOOO_A1 : public Convention_A1
         }
     }
 
-    static SingletonDisplay getSingletonDisplay( const ScDocument* pDoc, const ScAddress& rAbs1, const ScAddress& rAbs2,
+    static SingletonDisplay getSingletonDisplay( ScSheetLimits& rLimits, const ScAddress& rAbs1, const ScAddress& rAbs2,
             const ScComplexRefData& rRef, bool bFromRangeName )
     {
         // If any part is error, display as such.
@@ -846,7 +846,7 @@ struct ConventionOOO_A1 : public Convention_A1
 
         // Same if not in named expression and both rows of entire columns are
         // relative references.
-        if (!bFromRangeName && rAbs1.Row() == 0 && rAbs2.Row() == pDoc->MaxRow() &&
+        if (!bFromRangeName && rAbs1.Row() == 0 && rAbs2.Row() == rLimits.mnMaxRow &&
                 rRef.Ref1.IsRowRel() && rRef.Ref2.IsRowRel())
             return SINGLETON_COL;
 
@@ -856,7 +856,7 @@ struct ConventionOOO_A1 : public Convention_A1
 
         // Same if not in named expression and both columns of entire rows are
         // relative references.
-        if (!bFromRangeName && rAbs1.Col() == 0 && rAbs2.Col() == pDoc->MaxCol() &&
+        if (!bFromRangeName && rAbs1.Col() == 0 && rAbs2.Col() == rLimits.mnMaxCol &&
                 rRef.Ref1.IsColRel() && rRef.Ref2.IsColRel())
             return SINGLETON_ROW;
 
@@ -864,7 +864,7 @@ struct ConventionOOO_A1 : public Convention_A1
     }
 
     virtual void makeRefStr(
-                     const ScDocument* pDoc,
+                     ScSheetLimits& rLimits,
                      OUStringBuffer&   rBuffer,
                      formula::FormulaGrammar::Grammar /*eGram*/,
                      const ScAddress& rPos,
@@ -880,7 +880,7 @@ struct ConventionOOO_A1 : public Convention_A1
             aAbs2 = rRef.Ref2.toAbs(rPos);
 
         SingletonDisplay eSingleton = bSingleRef ? SINGLETON_NONE :
-            getSingletonDisplay( pDoc, aAbs1, aAbs2, rRef, bFromRangeName);
+            getSingletonDisplay( rLimits, aAbs1, aAbs2, rRef, bFromRangeName);
         MakeOneRefStrImpl(rBuffer, rErrRef, rTabNames, rRef.Ref1, aAbs1, false, false, eSingleton);
         if (!bSingleRef)
         {
@@ -1009,7 +1009,7 @@ struct ConventionOOO_A1 : public Convention_A1
     }
 
     virtual void makeExternalRefStr(
-        const ScDocument* /*pDoc*/,
+        ScSheetLimits&,
         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
         const std::vector<OUString>& rTabNames, const OUString& rTabName,
         const ScComplexRefData& rRef ) const override
@@ -1023,7 +1023,7 @@ struct ConventionOOO_A1_ODF : public ConventionOOO_A1
     ConventionOOO_A1_ODF() : ConventionOOO_A1 (FormulaGrammar::CONV_ODF) { }
 
     virtual void makeRefStr(
-                     const ScDocument* pDoc,
+                     ScSheetLimits& rLimits,
                      OUStringBuffer&   rBuffer,
                      formula::FormulaGrammar::Grammar eGram,
                      const ScAddress& rPos,
@@ -1050,7 +1050,7 @@ struct ConventionOOO_A1_ODF : public ConventionOOO_A1
         else
         {
             SingletonDisplay eSingleton = bSingleRef ? SINGLETON_NONE :
-                getSingletonDisplay( pDoc, aAbs1, aAbs2, rRef, bFromRangeName);
+                getSingletonDisplay( rLimits, aAbs1, aAbs2, rRef, bFromRangeName);
             MakeOneRefStrImpl(rBuffer, rErrRef, rTabNames, rRef.Ref1, aAbs1, false, true, eSingleton);
             if (!bSingleRef)
             {
@@ -1076,7 +1076,7 @@ struct ConventionOOO_A1_ODF : public ConventionOOO_A1
     }
 
     virtual void makeExternalRefStr(
-        const ScDocument* /*pDoc*/,
+        ScSheetLimits& ,
         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
         const std::vector<OUString>& rTabNames,
         const OUString& rTabName, const ScComplexRefData& rRef ) const override
@@ -1271,7 +1271,7 @@ struct ConventionXL_A1 : public Convention_A1, public ConventionXL
     }
 
     virtual void makeRefStr(
-                     const ScDocument* pDoc,
+                     ScSheetLimits& rLimits,
                      OUStringBuffer&   rBuf,
                      formula::FormulaGrammar::Grammar /*eGram*/,
                      const ScAddress& rPos,
@@ -1303,7 +1303,7 @@ struct ConventionXL_A1 : public Convention_A1, public ConventionXL
                 return;
             }
 
-            if (aAbs1.Col() == 0 && aAbs2.Col() >= pDoc->MaxCol())
+            if (aAbs1.Col() == 0 && aAbs2.Col() >= rLimits.mnMaxCol)
             {
                 if (!aRef.Ref1.IsRowRel())
                     rBuf.append( '$' );
@@ -1315,7 +1315,7 @@ struct ConventionXL_A1 : public Convention_A1, public ConventionXL
                 return;
             }
 
-            if (aAbs1.Row() == 0 && aAbs2.Row() >= pDoc->MaxRow())
+            if (aAbs1.Row() == 0 && aAbs2.Row() >= rLimits.mnMaxRow)
             {
                 if (!aRef.Ref1.IsColRel())
                     rBuf.append( '$' );
@@ -1394,7 +1394,7 @@ struct ConventionXL_A1 : public Convention_A1, public ConventionXL
     }
 
     virtual void makeExternalRefStr(
-        const ScDocument* /*pDoc*/,
+        ScSheetLimits&,
         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
         const std::vector<OUString>& rTabNames, const OUString& rTabName,
         const ScComplexRefData& rRef ) const override
@@ -1418,7 +1418,7 @@ struct ConventionXL_OOX : public ConventionXL_A1
 {
     ConventionXL_OOX() : ConventionXL_A1( FormulaGrammar::CONV_XL_OOX ) { }
 
-    virtual void makeRefStr( const ScDocument* pDoc,
+    virtual void makeRefStr( ScSheetLimits& rLimits,
                      OUStringBuffer&   rBuf,
                      formula::FormulaGrammar::Grammar eGram,
                      const ScAddress& rPos,
@@ -1450,7 +1450,7 @@ struct ConventionXL_OOX : public ConventionXL_A1
             return;
         }
 
-        ConventionXL_A1::makeRefStr( pDoc, rBuf, eGram, aPos, rErrRef, rTabNames, rRef, bSingleRef, bFromRangeName);
+        ConventionXL_A1::makeRefStr( rLimits, rBuf, eGram, aPos, rErrRef, rTabNames, rRef, bSingleRef, bFromRangeName);
     }
 
     virtual OUString makeExternalNameStr( sal_uInt16 nFileId, const OUString& /*rFile*/,
@@ -1513,7 +1513,7 @@ struct ConventionXL_OOX : public ConventionXL_A1
     }
 
     virtual void makeExternalRefStr(
-        const ScDocument* /*pDoc*/,
+        ScSheetLimits& ,
         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 nFileId, const OUString& /*rFileName*/,
         const std::vector<OUString>& rTabNames, const OUString& rTabName,
         const ScComplexRefData& rRef ) const override
@@ -1591,7 +1591,7 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
 {
     ConventionXL_R1C1() : ScCompiler::Convention( FormulaGrammar::CONV_XL_R1C1 ) { }
 
-    virtual void makeRefStr( const ScDocument* pDoc,
+    virtual void makeRefStr( ScSheetLimits& rLimits,
                      OUStringBuffer&   rBuf,
                      formula::FormulaGrammar::Grammar /*eGram*/,
                      const ScAddress& rPos,
@@ -1621,7 +1621,7 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
                 return;
             }
 
-            if (aAbsRef.aStart.Col() == 0 && aAbsRef.aEnd.Col() >= pDoc->MaxCol())
+            if (aAbsRef.aStart.Col() == 0 && aAbsRef.aEnd.Col() >= rLimits.mnMaxCol)
             {
                 r1c1_add_row(rBuf,  rRef.Ref1, aAbsRef.aStart);
                 if (aAbsRef.aStart.Row() != aAbsRef.aEnd.Row() ||
@@ -1634,7 +1634,7 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
 
             }
 
-            if (aAbsRef.aStart.Row() == 0 && aAbsRef.aEnd.Row() >= pDoc->MaxRow())
+            if (aAbsRef.aStart.Row() == 0 && aAbsRef.aEnd.Row() >= rLimits.mnMaxRow)
             {
                 r1c1_add_col(rBuf, rRef.Ref1, aAbsRef.aStart);
                 if (aAbsRef.aStart.Col() != aAbsRef.aEnd.Col() ||
@@ -1718,7 +1718,7 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
     }
 
     virtual void makeExternalRefStr(
-        const ScDocument* pDoc,
+        ScSheetLimits& rLimits,
         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
         const std::vector<OUString>& rTabNames, const OUString& rTabName,
         const ScComplexRefData& rRef ) const override
@@ -1735,7 +1735,7 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
             return;
         }
 
-        if (aAbsRef.aStart.Col() == 0 && aAbsRef.aEnd.Col() >= pDoc->MaxCol())
+        if (aAbsRef.aStart.Col() == 0 && aAbsRef.aEnd.Col() >= rLimits.mnMaxCol)
         {
             r1c1_add_row(rBuffer, rRef.Ref1, aAbsRef.aStart);
             if (aAbsRef.aStart.Row() != aAbsRef.aEnd.Row() || rRef.Ref1.IsRowRel() != rRef.Ref2.IsRowRel())
@@ -1746,7 +1746,7 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
             return;
         }
 
-        if (aAbsRef.aStart.Row() == 0 && aAbsRef.aEnd.Row() >= pDoc->MaxRow())
+        if (aAbsRef.aStart.Row() == 0 && aAbsRef.aEnd.Row() >= rLimits.mnMaxRow)
         {
             r1c1_add_col(rBuffer, rRef.Ref1, aAbsRef.aStart);
             if (aAbsRef.aStart.Col() != aAbsRef.aEnd.Col() || rRef.Ref1.IsColRel() != rRef.Ref2.IsColRel())
@@ -4658,7 +4658,7 @@ std::unique_ptr<ScTokenArray> ScCompiler::CompileString( const OUString& rFormul
                 ++pFunctionStack[ nFunction ].nSep;
             }
         }
-        FormulaToken* pNewToken = static_cast<ScTokenArray*>(pArr)->Add( maRawToken.CreateToken(pDoc));
+        FormulaToken* pNewToken = static_cast<ScTokenArray*>(pArr)->Add( maRawToken.CreateToken(pDoc->GetSheetLimits()));
         if (!pNewToken && eOp == ocArrayClose && pArr->OpCodeBefore( pArr->GetLen()) == ocArrayClose)
         {
             // Nested inline array or non-value/non-string in array. The
@@ -5026,7 +5026,7 @@ void ScCompiler::CreateStringFromExternal( OUStringBuffer& rBuffer, const Formul
                     *pFileName << "' '" << t->GetString().getString() << "'");
 
             pConv->makeExternalRefStr(
-                pDoc, rBuffer, GetPos(), nFileId, *pFileName, aTabNames, t->GetString().getString(),
+                pDoc->GetSheetLimits(), rBuffer, GetPos(), nFileId, *pFileName, aTabNames, t->GetString().getString(),
                 *t->GetDoubleRef());
         }
         break;
@@ -5128,7 +5128,7 @@ void ScCompiler::CreateStringFromSingleRef( OUStringBuffer& rBuffer, const Formu
         else
         {
             rBuffer.append(ScCompiler::GetNativeSymbol(ocErrName));
-            pConv->makeRefStr(pDoc, rBuffer, meGrammar, aPos, aErrRef,
+            pConv->makeRefStr(pDoc->GetSheetLimits(), rBuffer, meGrammar, aPos, aErrRef,
                               GetSetupTabNames(), aRef, true, (pArr && pArr->IsFromRangeName()));
         }
     }
@@ -5160,14 +5160,14 @@ void ScCompiler::CreateStringFromSingleRef( OUStringBuffer& rBuffer, const Formu
         rBuffer.append(aStr);
     }
     else
-        pConv->makeRefStr(pDoc, rBuffer, meGrammar, aPos, aErrRef,
+        pConv->makeRefStr(pDoc->GetSheetLimits(), rBuffer, meGrammar, aPos, aErrRef,
                           GetSetupTabNames(), aRef, true, (pArr && pArr->IsFromRangeName()));
 }
 
 void ScCompiler::CreateStringFromDoubleRef( OUStringBuffer& rBuffer, const FormulaToken* _pTokenP ) const
 {
     OUString aErrRef = GetCurrentOpCodeMap()->getSymbol(ocErrRef);
-    pConv->makeRefStr(pDoc, rBuffer, meGrammar, aPos, aErrRef, GetSetupTabNames(),
+    pConv->makeRefStr(pDoc->GetSheetLimits(), rBuffer, meGrammar, aPos, aErrRef, GetSetupTabNames(),
                       *_pTokenP->GetDoubleRef(), false, (pArr && pArr->IsFromRangeName()));
 }
 
@@ -5287,7 +5287,7 @@ sal_Unicode ScCompiler::GetNativeAddressSymbol( Convention::SpecialSymbolType eT
 
 FormulaTokenRef ScCompiler::ExtendRangeReference( FormulaToken & rTok1, FormulaToken & rTok2 )
 {
-    return extendRangeReference( pDoc, rTok1, rTok2, aPos, true/*bReuseDoubleRef*/ );
+    return extendRangeReference( pDoc->GetSheetLimits(), rTok1, rTok2, aPos, true/*bReuseDoubleRef*/ );
 }
 
 void ScCompiler::fillAddInToken(::std::vector< css::sheet::FormulaOpCodeMapEntry >& _rVec,bool _bIsEnglish) const
@@ -5519,7 +5519,7 @@ bool ScCompiler::HandleColRowName()
                     pNew->AddDoubleReference( aRefData );
                 else
                 {   // automagically
-                    pNew->Add( new ScDoubleRefToken( pDoc, aRefData, ocColRowNameAuto ) );
+                    pNew->Add( new ScDoubleRefToken( pDoc->GetSheetLimits(), aRefData, ocColRowNameAuto ) );
                 }
             }
             PushTokenArray( pNew, true );
@@ -5808,7 +5808,7 @@ bool ScCompiler::HandleTableRef()
                     if (nError != FormulaError::NONE)
                     {
                         aRefData.SetAddress( aRange.aStart, aRange.aStart);
-                        pTR->SetAreaRefRPN( new ScSingleRefToken(pDoc, aRefData));   // set reference at TableRef
+                        pTR->SetAreaRefRPN( new ScSingleRefToken(pDoc->GetSheetLimits(), aRefData));   // set reference at TableRef
                         pNew->Add( new FormulaErrorToken( nError));             // set error in RPN
                     }
                     else
@@ -5837,7 +5837,7 @@ bool ScCompiler::HandleTableRef()
                     if (nError != FormulaError::NONE)
                     {
                         aRefData.SetRange( aRange, aRange.aStart);
-                        pTR->SetAreaRefRPN( new ScDoubleRefToken(pDoc, aRefData));   // set reference at TableRef
+                        pTR->SetAreaRefRPN( new ScDoubleRefToken(pDoc->GetSheetLimits(), aRefData));   // set reference at TableRef
                         pNew->Add( new FormulaErrorToken( nError));             // set error in RPN
                     }
                     else
@@ -6095,7 +6095,7 @@ void ScCompiler::ReplaceDoubleRefII(FormulaToken** ppDoubleRefTok)
     aSingleRef.SetAddress(aAddr, aPos);
 
     // Replace the original doubleref token with computed singleref token
-    FormulaToken* pNewSingleRefTok = new ScSingleRefToken(pDoc, aSingleRef);
+    FormulaToken* pNewSingleRefTok = new ScSingleRefToken(pDoc->GetSheetLimits(), aSingleRef);
     (*ppDoubleRefTok)->DecRef();
     *ppDoubleRefTok = pNewSingleRefTok;
     pNewSingleRefTok->IncRef();
@@ -6226,7 +6226,7 @@ void ScCompiler::CorrectSumRange(const ScComplexRefData& rBaseRange,
         return;
 
     // Replace sum-range token
-    FormulaToken* pNewSumRangeTok = new ScDoubleRefToken(pDoc, rSumRange);
+    FormulaToken* pNewSumRangeTok = new ScDoubleRefToken(pDoc->GetSheetLimits(), rSumRange);
     (*ppSumRangeToken)->DecRef();
     *ppSumRangeToken = pNewSumRangeTok;
     pNewSumRangeTok->IncRef();
diff --git a/sc/source/core/tool/interpr2.cxx b/sc/source/core/tool/interpr2.cxx
index e20af82a4f4b..43bf4f75da07 100644
--- a/sc/source/core/tool/interpr2.cxx
+++ b/sc/source/core/tool/interpr2.cxx
@@ -2494,9 +2494,9 @@ void ScInterpreter::ScIntersect()
         {
             const ScComplexRefData& rRef = (*pRefList)[0];
             if (rRef.Ref1 == rRef.Ref2)
-                PushTempToken( new ScSingleRefToken(pDok, rRef.Ref1));
+                PushTempToken( new ScSingleRefToken(pDok->GetSheetLimits(), rRef.Ref1));
             else
-                PushTempToken( new ScDoubleRefToken(pDok, rRef));
+                PushTempToken( new ScDoubleRefToken(pDok->GetSheetLimits(), rRef));
         }
         else
             PushTokenRef( xRes);
@@ -2568,7 +2568,7 @@ void ScInterpreter::ScRangeFunc()
     // We explicitly tell extendRangeReference() to not reuse the token,
     // casting const away spares two clones.
     FormulaTokenRef xRes = extendRangeReference(
-            pDok, const_cast<FormulaToken&>(*x1), const_cast<FormulaToken&>(*x2), aPos, false);
+            pDok->GetSheetLimits(), const_cast<FormulaToken&>(*x1), const_cast<FormulaToken&>(*x2), aPos, false);
     if (!xRes)
         PushIllegalArgument();
     else
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
index 55d6b715c2f4..8a7143fb94ef 100644
--- a/sc/source/core/tool/interpr4.cxx
+++ b/sc/source/core/tool/interpr4.cxx
@@ -1367,7 +1367,7 @@ void ScInterpreter::PopRefListPushMatrixOrRef()
             if (nEntries == 1)
             {
                 --sp;
-                PushTempTokenWithoutError( new ScDoubleRefToken( pDok, (*pv)[0] ));
+                PushTempTokenWithoutError( new ScDoubleRefToken( pDok->GetSheetLimits(), (*pv)[0] ));
             }
             else if (bMatrixFormula)
             {
@@ -1813,7 +1813,7 @@ void ScInterpreter::PushSingleRef(SCCOL nCol, SCROW nRow, SCTAB nTab)
     {
         ScSingleRefData aRef;
         aRef.InitAddress(ScAddress(nCol,nRow,nTab));
-        PushTempTokenWithoutError( new ScSingleRefToken( pDok, aRef ) );
+        PushTempTokenWithoutError( new ScSingleRefToken( pDok->GetSheetLimits(), aRef ) );
     }
 }
 
@@ -1824,7 +1824,7 @@ void ScInterpreter::PushDoubleRef(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
     {
         ScComplexRefData aRef;
         aRef.InitRange(ScRange(nCol1,nRow1,nTab1,nCol2,nRow2,nTab2));
-        PushTempTokenWithoutError( new ScDoubleRefToken( pDok, aRef ) );
+        PushTempTokenWithoutError( new ScDoubleRefToken( pDok->GetSheetLimits(), aRef ) );
     }
 }
 
@@ -1859,7 +1859,7 @@ void ScInterpreter::PushSingleRef( const ScRefAddress& rRef )
     {
         ScSingleRefData aRef;
         aRef.InitFromRefAddress( rRef, aPos);
-        PushTempTokenWithoutError( new ScSingleRefToken( pDok, aRef ) );
+        PushTempTokenWithoutError( new ScSingleRefToken( pDok->GetSheetLimits(), aRef ) );
     }
 }
 
@@ -1869,7 +1869,7 @@ void ScInterpreter::PushDoubleRef( const ScRefAddress& rRef1, const ScRefAddress
     {
         ScComplexRefData aRef;
         aRef.InitFromRefAddresses( rRef1, rRef2, aPos);
-        PushTempTokenWithoutError( new ScDoubleRefToken( pDok, aRef ) );
+        PushTempTokenWithoutError( new ScDoubleRefToken( pDok->GetSheetLimits(), aRef ) );
     }
 }
 
@@ -3666,7 +3666,7 @@ void ScInterpreter::ScDBArea()
         pDBData->GetArea(aRange);
         aRange.aEnd.SetTab(aRange.aStart.Tab());
         aRefData.SetRange(aRange, aPos);
-        PushTempToken( new ScDoubleRefToken( pDok, aRefData ) );
+        PushTempToken( new ScDoubleRefToken( pDok->GetSheetLimits(), aRefData ) );
     }
     else
         PushError( FormulaError::NoName);
@@ -3750,7 +3750,7 @@ void ScInterpreter::ScColRowNameAuto()
         }
     }
     aRefData.SetRange(aAbs, aPos);
-    PushTempToken( new ScDoubleRefToken( pDok, aRefData ) );
+    PushTempToken( new ScDoubleRefToken( pDok->GetSheetLimits(), aRefData ) );
 }
 
 // --- internals ------------------------------------------------------------
diff --git a/sc/source/core/tool/reftokenhelper.cxx b/sc/source/core/tool/reftokenhelper.cxx
index 135b544fcdac..15341e92f930 100644
--- a/sc/source/core/tool/reftokenhelper.cxx
+++ b/sc/source/core/tool/reftokenhelper.cxx
@@ -176,7 +176,7 @@ void ScRefTokenHelper::getTokenFromRange(const ScDocument* pDoc, ScTokenRef& pTo
     // different sheets.
     aData.Ref2.SetFlag3D(rRange.aStart.Tab() != rRange.aEnd.Tab());
 
-    pToken.reset(new ScDoubleRefToken(pDoc, aData));
+    pToken.reset(new ScDoubleRefToken(pDoc->GetSheetLimits(), aData));
 }
 
 void ScRefTokenHelper::getTokensFromRangeList(const ScDocument* pDoc, vector<ScTokenRef>& pTokens, const ScRangeList& rRanges)
@@ -389,7 +389,7 @@ private:
                 if (bExternal)
                     pOldToken.reset(new ScExternalDoubleRefToken(nFileId, aTabName, aNewData));
                 else
-                    pOldToken.reset(new ScDoubleRefToken(pDoc, aNewData));
+                    pOldToken.reset(new ScDoubleRefToken(pDoc->GetSheetLimits(), aNewData));
 
                 bJoined = true;
                 break;
@@ -449,7 +449,7 @@ ScTokenRef ScRefTokenHelper::createRefToken(const ScDocument* pDoc, const ScAddr
 {
     ScSingleRefData aRefData;
     aRefData.InitAddress(rAddr);
-    ScTokenRef pRef(new ScSingleRefToken(pDoc, aRefData));
+    ScTokenRef pRef(new ScSingleRefToken(pDoc->GetSheetLimits(), aRefData));
     return pRef;
 }
 
@@ -457,7 +457,7 @@ ScTokenRef ScRefTokenHelper::createRefToken(const ScDocument* pDoc, const ScRang
 {
     ScComplexRefData aRefData;
     aRefData.InitRange(rRange);
-    ScTokenRef pRef(new ScDoubleRefToken(pDoc, aRefData));
+    ScTokenRef pRef(new ScDoubleRefToken(pDoc->GetSheetLimits(), aRefData));
     return pRef;
 }
 
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 332debee8d10..6fd70a6eaf23 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -350,7 +350,7 @@ bool ScRawToken::IsValidReference(const ScDocument* pDoc) const
     return false;
 }
 
-FormulaToken* ScRawToken::CreateToken(const ScDocument* pDoc) const
+FormulaToken* ScRawToken::CreateToken(ScSheetLimits& rLimits) const
 {
 #define IF_NOT_OPCODE_ERROR(o,c) SAL_WARN_IF((eOp!=o), "sc.core", #c "::ctor: OpCode " << static_cast<int>(eOp) << " lost, converted to " #o "; maybe inherit from FormulaToken instead!")
     switch ( GetType() )
@@ -370,14 +370,14 @@ FormulaToken* ScRawToken::CreateToken(const ScDocument* pDoc) const
         }
         case svSingleRef :
             if (eOp == ocPush)
-                return new ScSingleRefToken(pDoc, aRef.Ref1 );
+                return new ScSingleRefToken(rLimits, aRef.Ref1 );
             else
-                return new ScSingleRefToken(pDoc, aRef.Ref1, eOp );
+                return new ScSingleRefToken(rLimits, aRef.Ref1, eOp );
         case svDoubleRef :
             if (eOp == ocPush)
-                return new ScDoubleRefToken(pDoc, aRef );
+                return new ScDoubleRefToken(rLimits, aRef );
             else
-                return new ScDoubleRefToken(pDoc, aRef, eOp );
+                return new ScDoubleRefToken(rLimits, aRef, eOp );
         case svMatrix :
             IF_NOT_OPCODE_ERROR( ocPush, ScMatrixToken);
             return new ScMatrixToken( pMat );
@@ -499,7 +499,7 @@ void DumpToken(formula::FormulaToken const & rToken)
 }
 #endif
 
-FormulaTokenRef extendRangeReference( const ScDocument* pDoc, FormulaToken & rTok1, FormulaToken & rTok2,
+FormulaTokenRef extendRangeReference( ScSheetLimits& rLimits, FormulaToken & rTok1, FormulaToken & rTok2,
         const ScAddress & rPos, bool bReuseDoubleRef )
 {
 
@@ -549,7 +549,7 @@ FormulaTokenRef extendRangeReference( const ScDocument* pDoc, FormulaToken & rTo
         if (bExternal)
             xRes = new ScExternalDoubleRefToken( rTok1.GetIndex(), rTok1.GetString(), aRef);
         else
-            xRes = new ScDoubleRefToken(pDoc, aRef);
+            xRes = new ScDoubleRefToken(rLimits, aRef);
     }
     else
     {
@@ -575,7 +575,7 @@ FormulaTokenRef extendRangeReference( const ScDocument* pDoc, FormulaToken & rTo
                 return nullptr;
             if (bExternal)
                 return nullptr;    // external reference list not possible
-            xRes = new ScDoubleRefToken(pDoc, (*pRefList)[0] );
+            xRes = new ScDoubleRefToken(rLimits, (*pRefList)[0] );
         }
         if (!xRes)
             return nullptr;    // shouldn't happen...
@@ -1678,7 +1678,7 @@ void ScTokenArray::CheckToken( const FormulaToken& r )
     }
 }
 
-bool ScTokenArray::ImplGetReference( const ScDocument* pDoc, ScRange& rRange, const ScAddress& rPos, bool bValidOnly ) const
+bool ScTokenArray::ImplGetReference( ScRange& rRange, const ScAddress& rPos, bool bValidOnly ) const
 {
     bool bIs = false;
     if ( pCode && nLen == 1 )
@@ -1690,7 +1690,7 @@ bool ScTokenArray::ImplGetReference( const ScDocument* pDoc, ScRange& rRange, co
             {
                 const ScSingleRefData& rRef = *static_cast<const ScSingleRefToken*>(pToken)->GetSingleRef();
                 rRange.aStart = rRange.aEnd = rRef.toAbs(rPos);
-                bIs = !bValidOnly || pDoc->ValidAddress(rRange.aStart);
+                bIs = !bValidOnly || mxSheetLimits->ValidAddress(rRange.aStart);
             }
             else if ( pToken->GetType() == svDoubleRef )
             {
@@ -1699,7 +1699,7 @@ bool ScTokenArray::ImplGetReference( const ScDocument* pDoc, ScRange& rRange, co
                 const ScSingleRefData& rRef2 = rCompl.Ref2;
                 rRange.aStart = rRef1.toAbs(rPos);
                 rRange.aEnd   = rRef2.toAbs(rPos);
-                bIs = !bValidOnly || pDoc->ValidRange(rRange);
+                bIs = !bValidOnly || mxSheetLimits->ValidRange(rRange);
             }
         }
     }
@@ -1852,17 +1852,25 @@ bool ScTokenArray::IsInvariant() const
 
 bool ScTokenArray::IsReference( ScRange& rRange, const ScAddress& rPos ) const
 {
-    return ImplGetReference(mpDoc, rRange, rPos, false);
+    return ImplGetReference(rRange, rPos, false);
 }
 
 bool ScTokenArray::IsValidReference( ScRange& rRange, const ScAddress& rPos ) const
 {
-    return ImplGetReference(mpDoc, rRange, rPos, true);
+    return ImplGetReference(rRange, rPos, true);
 }
 
 ScTokenArray::ScTokenArray(const ScDocument* pDoc) :
     FormulaTokenArray(),
-    mpDoc(pDoc),
+    mxSheetLimits(&pDoc->GetSheetLimits()),
+    mnHashValue(0)
+{
+    ResetVectorState();
+}
+
+ScTokenArray::ScTokenArray(ScSheetLimits& rLimits) :
+    FormulaTokenArray(),
+    mxSheetLimits(&rLimits),
     mnHashValue(0)
 {
     ResetVectorState();
@@ -1909,7 +1917,7 @@ void ScTokenArray::Clear()
 
 std::unique_ptr<ScTokenArray> ScTokenArray::Clone() const
 {
-    std::unique_ptr<ScTokenArray> p(new ScTokenArray(mpDoc));
+    std::unique_ptr<ScTokenArray> p(new ScTokenArray(*mxSheetLimits));
     p->nLen = nLen;
     p->nRPN = nRPN;
     p->nMode = nMode;
@@ -1967,7 +1975,7 @@ std::unique_ptr<ScTokenArray> ScTokenArray::Clone() const
 
 FormulaToken* ScTokenArray::AddRawToken( const ScRawToken& r )
 {
-    return Add( r.CreateToken(mpDoc) );
+    return Add( r.CreateToken(*mxSheetLimits) );
 }
 
 // Utility function to ensure that there is strict alternation of values and
@@ -2165,7 +2173,7 @@ void ScTokenArray::MergeRangeReference( const ScAddress & rPos )
             (((p2 = PeekPrev(nIdx)) != nullptr) && p2->GetOpCode() == ocRange) &&
             ((p1 = PeekPrev(nIdx)) != nullptr))
     {
-        FormulaTokenRef p = extendRangeReference( mpDoc, *p1, *p3, rPos, true);
+        FormulaTokenRef p = extendRangeReference( *mxSheetLimits, *p1, *p3, rPos, true);
         if (p)
         {
             p->IncRef();
@@ -2187,17 +2195,17 @@ FormulaToken* ScTokenArray::AddOpCode( OpCode e )
 
 FormulaToken* ScTokenArray::AddSingleReference( const ScSingleRefData& rRef )
 {
-    return Add( new ScSingleRefToken(mpDoc, rRef ) );
+    return Add( new ScSingleRefToken( *mxSheetLimits, rRef ) );
 }
 
 FormulaToken* ScTokenArray::AddMatrixSingleReference( const ScSingleRefData& rRef )
 {
-    return Add( new ScSingleRefToken(mpDoc, rRef, ocMatRef ) );
+    return Add( new ScSingleRefToken(*mxSheetLimits, rRef, ocMatRef ) );
 }
 
 FormulaToken* ScTokenArray::AddDoubleReference( const ScComplexRefData& rRef )
 {
-    return Add( new ScDoubleRefToken(mpDoc, rRef ) );
+    return Add( new ScDoubleRefToken(*mxSheetLimits, rRef ) );
 }
 
 FormulaToken* ScTokenArray::AddMatrix( const ScMatrixRef& p )
@@ -2234,7 +2242,7 @@ FormulaToken* ScTokenArray::AddExternalDoubleReference( sal_uInt16 nFileId, cons
 
 FormulaToken* ScTokenArray::AddColRowName( const ScSingleRefData& rRef )
 {
-    return Add( new ScSingleRefToken(mpDoc, rRef, ocColRowName ) );
+    return Add( new ScSingleRefToken(*mxSheetLimits, rRef, ocColRowName ) );
 }
 
 void ScTokenArray::AssignXMLString( const OUString &rText, const OUString &rFormulaNmsp )
@@ -2258,13 +2266,13 @@ bool ScTokenArray::GetAdjacentExtendOfOuterFuncRefs( SCCOLROW& nExtend,
     switch ( eDir )
     {
         case DIR_BOTTOM :
-            if ( rPos.Row() < mpDoc->MaxRow() )
+            if ( rPos.Row() < mxSheetLimits->mnMaxRow )
                 nRow = (nExtend = rPos.Row()) + 1;
             else
                 return false;
         break;
         case DIR_RIGHT :
-            if ( rPos.Col() < mpDoc->MaxCol() )
+            if ( rPos.Col() < mxSheetLimits->mnMaxCol )
                 nCol = static_cast<SCCOL>(nExtend = rPos.Col()) + 1;
             else
                 return false;
@@ -4513,7 +4521,7 @@ void ScTokenArray::ClearTabDeleted( const ScAddress& rPos, SCTAB nStartTab, SCTA
 namespace {
 
 void checkBounds(
-    const ScDocument* pDoc,
+    ScSheetLimits& rLimits,
     const ScAddress& rPos, SCROW nGroupLen, const ScRange& rCheckRange,
     const ScSingleRefData& rRef, std::vector<SCROW>& rBounds, const ScRange* pDeletedRange )
 {
@@ -4549,7 +4557,7 @@ void checkBounds(
         SCROW nOffset = pDeletedRange->aStart.Row() - aAbs.aStart.Row();
         SCROW nRow = rPos.Row() + nOffset;
         // Unlike for rCheckRange, for pDeletedRange nRow can be anywhere>=0.
-        if (pDoc->ValidRow(nRow))
+        if (rLimits.ValidRow(nRow))
             rBounds.push_back(nRow);
     }
 
@@ -4574,7 +4582,7 @@ void checkBounds(
         SCROW nOffset = pDeletedRange->aEnd.Row() + 1 - aAbs.aStart.Row();
         SCROW nRow = rPos.Row() + nOffset;
         // Unlike for rCheckRange, for pDeletedRange nRow can be ~anywhere.
-        if (pDoc->ValidRow(nRow))
+        if (rLimits.ValidRow(nRow))
             rBounds.push_back(nRow);
     }
 }
@@ -4612,7 +4620,7 @@ void checkBounds(
         pDeletedRange = &aDeletedRange;
     }
 
-    checkBounds(&rCxt.mrDoc, rPos, nGroupLen, aCheckRange, rRef, rBounds, pDeletedRange);
+    checkBounds(rCxt.mrDoc.GetSheetLimits(), rPos, nGroupLen, aCheckRange, rRef, rBounds, pDeletedRange);
 }
 
 }
@@ -4671,14 +4679,14 @@ void ScTokenArray::CheckRelativeReferenceBounds(
                 case svSingleRef:
                     {
                         const ScSingleRefData& rRef = *p->GetSingleRef();
-                        checkBounds(mpDoc, rPos, nGroupLen, rRange, rRef, rBounds, nullptr);
+                        checkBounds(*mxSheetLimits, rPos, nGroupLen, rRange, rRef, rBounds, nullptr);
                     }
                     break;
                 case svDoubleRef:
                     {
                         const ScComplexRefData& rRef = *p->GetDoubleRef();
-                        checkBounds(mpDoc, rPos, nGroupLen, rRange, rRef.Ref1, rBounds, nullptr);
-                        checkBounds(mpDoc, rPos, nGroupLen, rRange, rRef.Ref2, rBounds, nullptr);
+                        checkBounds(*mxSheetLimits, rPos, nGroupLen, rRange, rRef.Ref1, rBounds, nullptr);
+                        checkBounds(*mxSheetLimits, rPos, nGroupLen, rRange, rRef.Ref2, rBounds, nullptr);
                     }
                     break;
                 default:
@@ -4814,7 +4822,7 @@ void appendString( OUStringBuffer& rBuf, const OUString& rStr )
     rBuf.append('"');
 }
 
-void appendTokenByType( const ScDocument* pDoc, sc::TokenStringContext& rCxt, OUStringBuffer& rBuf, const FormulaToken& rToken,
+void appendTokenByType( ScSheetLimits& rLimits, sc::TokenStringContext& rCxt, OUStringBuffer& rBuf, const FormulaToken& rToken,
         const ScAddress& rPos, bool bFromRangeName )
 {
     if (rToken.IsExternalRef())
@@ -4845,7 +4853,7 @@ void appendTokenByType( const ScDocument* pDoc, sc::TokenStringContext& rCxt, OU
                     return;
 
                 rCxt.mpRefConv->makeExternalRefStr(
-                        pDoc, rBuf, rPos, nFileId, aFileName, it->second, aTabName,
+                        rLimits, rBuf, rPos, nFileId, aFileName, it->second, aTabName,
                         *rToken.GetDoubleRef());
             }
             break;
@@ -4883,7 +4891,7 @@ void appendTokenByType( const ScDocument* pDoc, sc::TokenStringContext& rCxt, OU
                 ScComplexRefData aRef;
                 aRef.Ref1 = rRef;
                 aRef.Ref2 = rRef;
-                rCxt.mpRefConv->makeRefStr(pDoc, rBuf, rCxt.meGram, rPos, rCxt.maErrRef, rCxt.maTabNames, aRef, true,
+                rCxt.mpRefConv->makeRefStr(rLimits, rBuf, rCxt.meGram, rPos, rCxt.maErrRef, rCxt.maTabNames, aRef, true,
                         bFromRangeName);
             }
             else
@@ -4895,7 +4903,7 @@ void appendTokenByType( const ScDocument* pDoc, sc::TokenStringContext& rCxt, OU
             if (rCxt.mpRefConv)
             {
                 const ScComplexRefData& rRef = *rToken.GetDoubleRef();
-                rCxt.mpRefConv->makeRefStr(pDoc, rBuf, rCxt.meGram, rPos, rCxt.maErrRef, rCxt.maTabNames, rRef, false,
+                rCxt.mpRefConv->makeRefStr(rLimits, rBuf, rCxt.meGram, rPos, rCxt.maErrRef, rCxt.maTabNames, rRef, false,
                         bFromRangeName);
             }
             else
@@ -5115,7 +5123,7 @@ OUString ScTokenArray::CreateString( sc::TokenStringContext& rCxt, const ScAddre
         if (eOp < rCxt.mxOpCodeMap->getSymbolCount())
             aBuf.append(rCxt.mxOpCodeMap->getSymbol(eOp));
 
-        appendTokenByType(mpDoc, rCxt, aBuf, *pToken, rPos, IsFromRangeName());
+        appendTokenByType(*mxSheetLimits, rCxt, aBuf, *pToken, rPos, IsFromRangeName());
     }
 
     return aBuf.makeStringAndClear();
diff --git a/sc/source/ui/unoobj/chart2uno.cxx b/sc/source/ui/unoobj/chart2uno.cxx
index 658ad00c7b91..b7c11adfedba 100644
--- a/sc/source/ui/unoobj/chart2uno.cxx
+++ b/sc/source/ui/unoobj/chart2uno.cxx
@@ -762,7 +762,7 @@ void Chart2Positioner::createPositionMap()
                         if (bExternal)
                             rCol[ nInsRow ].reset(new ScExternalSingleRefToken(nFileId, aTabName, aCellData));
                         else
-                            rCol[ nInsRow ].reset(new ScSingleRefToken(mpDoc, aCellData));
+                            rCol[ nInsRow ].reset(new ScSingleRefToken(mpDoc->GetSheetLimits(), aCellData));
                     }
                 }
             }
@@ -921,12 +921,12 @@ private:
         if (bExternal)
             rStart.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref1));
         else
-            rStart.reset(new ScSingleRefToken(pDoc, aData.Ref1));
+            rStart.reset(new ScSingleRefToken(pDoc->GetSheetLimits(), aData.Ref1));
 
         if (bExternal)
             rEnd.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref2));
         else
-            rEnd.reset(new ScSingleRefToken(pDoc, aData.Ref2));
+            rEnd.reset(new ScSingleRefToken(pDoc->GetSheetLimits(), aData.Ref2));
         return true;
     }
 
@@ -1292,7 +1292,7 @@ bool lcl_addUpperLeftCornerIfMissing(const ScDocument* pDoc, vector<ScTokenRef>&
         }
         else
         {
-            ScTokenRef pCorner(new ScSingleRefToken(pDoc, aData));
+            ScTokenRef pCorner(new ScSingleRefToken(pDoc->GetSheetLimits(), aData));
             ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
         }
     }
@@ -1312,7 +1312,7 @@ bool lcl_addUpperLeftCornerIfMissing(const ScDocument* pDoc, vector<ScTokenRef>&
         }
         else
         {
-            ScTokenRef pCorner(new ScDoubleRefToken(pDoc, r));
+            ScTokenRef pCorner(new ScDoubleRefToken(pDoc->GetSheetLimits(), r));
             ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
         }
     }
commit 3b8e554b69de349a20d10ec90b27ab71a013b464
Author:     Deena Francis <deena.francis at gmail.com>
AuthorDate: Fri Dec 13 19:49:36 2019 +0530
Commit:     Noel Grandin <noel.grandin at collabora.co.uk>
CommitDate: Fri Dec 13 19:41:49 2019 +0100

    tdf#120948: row deltas should be stored as SCROW...
    
    instead of SCCOL, else it may cause overflows.
    Also included a unit test for protecting the fix.
    
    Change-Id: I8f735b23b7f95ecf34ccae86f00c76b82b0d668f
    Reviewed-on: https://gerrit.libreoffice.org/85118
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>

diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index d5b0bdf7ab28..777dc4a51389 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -562,6 +562,7 @@ public:
     void testProtectedSheetEditByColumn();
     void testFuncRowsHidden();
     void testInsertColCellStoreEventSwap();
+    void testFormulaAfterDeleteRows();
 
     CPPUNIT_TEST_SUITE(Test);
     CPPUNIT_TEST(testCollator);
@@ -862,6 +863,7 @@ public:
     CPPUNIT_TEST(testProtectedSheetEditByColumn);
     CPPUNIT_TEST(testFuncRowsHidden);
     CPPUNIT_TEST(testInsertColCellStoreEventSwap);
+    CPPUNIT_TEST(testFormulaAfterDeleteRows);
     CPPUNIT_TEST_SUITE_END();
 
 private:
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index b90db089d8ed..5c93d3083111 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -8996,4 +8996,24 @@ void Test::testInsertColCellStoreEventSwap()
     m_pDoc->DeleteTab(0);
 }
 
+void Test::testFormulaAfterDeleteRows()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
+    m_pDoc->InsertTab(0, "Test");
+
+    // Fill A1:A70000 with 1.0
+    std::vector<double> aVals(70000, 1.0);
+    m_pDoc->SetValues(ScAddress(0, 0, 0), aVals);
+    // Set A70001 with formula "=SUM(A1:A70000)"
+    m_pDoc->SetString(0, 70000, 0, "=SUM(A1:A70000)");
+
+    // Delete rows 2:69998
+    m_pDoc->DeleteRow(ScRange(0, 1, 0, m_pDoc->MaxCol(), 69997, 0));
+
+    const ScAddress aPos(0, 3, 0);  // A4
+    ASSERT_FORMULA_EQUAL(*m_pDoc, aPos, "SUM(A1:A3)", "Wrong formula in A4.");
+
+    ASSERT_DOUBLES_EQUAL_MESSAGE("Wrong value at A4", 3.0, m_pDoc->GetValue(aPos));
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index a70c68842273..332debee8d10 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2838,8 +2838,8 @@ ShrinkResult shrinkRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange,
             else
             {
                 // The reference range is truncated on the top.
-                SCCOL nOffset = rDeletedRange.aStart.Row() - rRefRange.aStart.Row();
-                SCCOL nDelta = rRefRange.aStart.Row() - rDeletedRange.aEnd.Row() - 1;
+                SCROW nOffset = rDeletedRange.aStart.Row() - rRefRange.aStart.Row();
+                SCROW nDelta = rRefRange.aStart.Row() - rDeletedRange.aEnd.Row() - 1;
                 rRefRange.IncEndRowSticky(&rCxt.mrDoc, nDelta+nOffset);
                 rRefRange.aStart.IncRow(nOffset);
             }
@@ -2852,7 +2852,7 @@ ShrinkResult shrinkRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange,
 
             // Reference is deleted in the middle. Move the last row
             // position upward.
-            SCCOL nDelta = rDeletedRange.aStart.Row() - rDeletedRange.aEnd.Row() - 1;
+            SCROW nDelta = rDeletedRange.aStart.Row() - rDeletedRange.aEnd.Row() - 1;
             rRefRange.IncEndRowSticky(&rCxt.mrDoc, nDelta);
         }
         else
@@ -2862,7 +2862,7 @@ ShrinkResult shrinkRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange,
                 return STICKY;
 
             // The reference range is truncated on the bottom.
-            SCCOL nDelta = rDeletedRange.aStart.Row() - rRefRange.aEnd.Row() - 1;
+            SCROW nDelta = rDeletedRange.aStart.Row() - rRefRange.aEnd.Row() - 1;
             rRefRange.IncEndRowSticky(&rCxt.mrDoc, nDelta);
         }
         return SHRUNK;


More information about the Libreoffice-commits mailing list