LibreOffice Module sc (master)  1
token.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <functional>
21 
22 #include <string.h>
23 #include <osl/diagnose.h>
24 #include <sal/log.hxx>
25 
26 #include <token.hxx>
27 #include <tokenarray.hxx>
28 #include <reftokenhelper.hxx>
29 #include <clipparam.hxx>
30 #include <compiler.hxx>
31 #include <interpre.hxx>
33 #include <formula/compiler.hxx>
34 #include <formula/opcode.hxx>
35 #include <jumpmatrix.hxx>
36 #include <rangeseq.hxx>
37 #include <externalrefmgr.hxx>
38 #include <document.hxx>
39 #include <refupdatecontext.hxx>
40 #include <tokenstringcontext.hxx>
41 #include <types.hxx>
42 #include <addincol.hxx>
43 #include <dbdata.hxx>
44 #include <reordermap.hxx>
45 #include <svl/sharedstring.hxx>
46 #include <scmatrix.hxx>
47 
48 using ::std::vector;
49 
50 #include <com/sun/star/sheet/ComplexReference.hpp>
51 #include <com/sun/star/sheet/ExternalReference.hpp>
52 #include <com/sun/star/sheet/FormulaToken.hpp>
53 #include <com/sun/star/sheet/ReferenceFlags.hpp>
54 #include <com/sun/star/sheet/NameToken.hpp>
55 #include <utility>
56 #include <o3tl/safeint.hxx>
57 #include <o3tl/sorted_vector.hxx>
58 
59 using namespace formula;
60 using namespace com::sun::star;
61 
62 namespace
63 {
64  void lcl_SingleRefToCalc( ScSingleRefData& rRef, const sheet::SingleReference& rAPI )
65  {
66  rRef.InitFlags();
67 
68  rRef.SetColRel( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_RELATIVE ) != 0 );
69  rRef.SetRowRel( ( rAPI.Flags & sheet::ReferenceFlags::ROW_RELATIVE ) != 0 );
70  rRef.SetTabRel( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_RELATIVE ) != 0 );
71  rRef.SetColDeleted( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_DELETED ) != 0 );
72  rRef.SetRowDeleted( ( rAPI.Flags & sheet::ReferenceFlags::ROW_DELETED ) != 0 );
73  rRef.SetTabDeleted( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_DELETED ) != 0 );
74  rRef.SetFlag3D( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_3D ) != 0 );
75  rRef.SetRelName( ( rAPI.Flags & sheet::ReferenceFlags::RELATIVE_NAME ) != 0 );
76 
77  if (rRef.IsColRel())
78  rRef.SetRelCol(static_cast<SCCOL>(rAPI.RelativeColumn));
79  else
80  rRef.SetAbsCol(static_cast<SCCOL>(rAPI.Column));
81 
82  if (rRef.IsRowRel())
83  rRef.SetRelRow(static_cast<SCROW>(rAPI.RelativeRow));
84  else
85  rRef.SetAbsRow(static_cast<SCROW>(rAPI.Row));
86 
87  if (rRef.IsTabRel())
88  rRef.SetRelTab(static_cast<SCTAB>(rAPI.RelativeSheet));
89  else
90  rRef.SetAbsTab(static_cast<SCTAB>(rAPI.Sheet));
91  }
92 
93  void lcl_ExternalRefToCalc( ScSingleRefData& rRef, const sheet::SingleReference& rAPI )
94  {
95  rRef.InitFlags();
96 
97  rRef.SetColRel( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_RELATIVE ) != 0 );
98  rRef.SetRowRel( ( rAPI.Flags & sheet::ReferenceFlags::ROW_RELATIVE ) != 0 );
99  rRef.SetColDeleted( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_DELETED ) != 0 );
100  rRef.SetRowDeleted( ( rAPI.Flags & sheet::ReferenceFlags::ROW_DELETED ) != 0 );
101  rRef.SetTabDeleted( false ); // sheet must not be deleted for external refs
102  rRef.SetFlag3D( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_3D ) != 0 );
103  rRef.SetRelName( false );
104 
105  if (rRef.IsColRel())
106  rRef.SetRelCol(static_cast<SCCOL>(rAPI.RelativeColumn));
107  else
108  rRef.SetAbsCol(static_cast<SCCOL>(rAPI.Column));
109 
110  if (rRef.IsRowRel())
111  rRef.SetRelRow(static_cast<SCROW>(rAPI.RelativeRow));
112  else
113  rRef.SetAbsRow(static_cast<SCROW>(rAPI.Row));
114 
115  // sheet index must be absolute for external refs
116  rRef.SetAbsTab(0);
117  }
118 
119  struct TokenPointerRange
120  {
122  FormulaToken** mpStop;
123 
124  TokenPointerRange() : mpStart(nullptr), mpStop(nullptr) {}
125  TokenPointerRange( FormulaToken** p, sal_uInt16 n ) :
126  mpStart(p), mpStop( p + static_cast<size_t>(n)) {}
127  };
128  struct TokenPointers
129  {
130  TokenPointerRange maPointerRange[2];
131  bool mbSkipRelName;
132 
133  TokenPointers( FormulaToken** pCode, sal_uInt16 nLen, FormulaToken** pRPN, sal_uInt16 nRPN,
134  bool bSkipRelName = true ) :
135  mbSkipRelName(bSkipRelName)
136  {
137  maPointerRange[0] = TokenPointerRange( pCode, nLen);
138  maPointerRange[1] = TokenPointerRange( pRPN, nRPN);
139  }
140 
141  bool skipToken( size_t i, const FormulaToken* const * pp )
142  {
143  // Handle all code tokens, and tokens in RPN only if they have a
144  // reference count of 1, which means they are not referenced in the
145  // code array. Doing it the other way would skip code tokens that
146  // are held by flat copied token arrays and thus are shared. For
147  // flat copy arrays the caller has to know what it does and should
148  // discard all RPN, update only one array and regenerate all RPN.
149  if (i == 1)
150  {
151  if ((*pp)->GetRef() > 1)
152  return true;
153 
154  if (mbSkipRelName)
155  {
156  // Skip (do not adjust) relative references resulting from
157  // named expressions. Resolved expressions are only in RPN.
158  switch ((*pp)->GetType())
159  {
160  case svSingleRef:
161  return (*pp)->GetSingleRef()->IsRelName();
162  case svDoubleRef:
163  {
164  const ScComplexRefData& rRef = *(*pp)->GetDoubleRef();
165  return rRef.Ref1.IsRelName() || rRef.Ref2.IsRelName();
166  }
167  default:
168  ; // nothing
169  }
170  }
171  }
172 
173  return false;
174  }
175 
176  FormulaToken* getHandledToken( size_t i, FormulaToken* const * pp )
177  {
178  if (skipToken( i, pp))
179  return nullptr;
180 
181  FormulaToken* p = *pp;
182  if (p->GetOpCode() == ocTableRef)
183  {
184  // Return the inner reference token if it is not in RPN.
185  ScTableRefToken* pTR = dynamic_cast<ScTableRefToken*>(p);
186  if (!pTR)
187  return p;
188  p = pTR->GetAreaRefRPN();
189  if (!p)
190  return pTR;
191  if (p->GetRef() > 1)
192  // Reference handled in RPN, but do not return nullptr so
193  // loops will process ocTableRef via pp instead of issuing
194  // a continue.
195  return pTR;
196  }
197  return p;
198  }
199  };
200 
201 } // namespace
202 
203 
204 // --- class ScRawToken -----------------------------------------------------
205 
207 {
208  eOp = e;
209  switch (eOp)
210  {
211  case ocIf:
212  eType = svJump;
213  nJump[ 0 ] = 3; // If, Else, Behind
214  break;
215  case ocIfError:
216  case ocIfNA:
217  eType = svJump;
218  nJump[ 0 ] = 2; // If, Behind
219  break;
220  case ocChoose:
221  eType = svJump;
222  nJump[ 0 ] = FORMULA_MAXJUMPCOUNT + 1;
223  break;
224  case ocMissing:
225  eType = svMissing;
226  break;
227  case ocSep:
228  case ocOpen:
229  case ocClose:
230  case ocArrayRowSep:
231  case ocArrayColSep:
232  case ocArrayOpen:
233  case ocArrayClose:
234  case ocTableRefOpen:
235  case ocTableRefClose:
236  eType = svSep;
237  break;
238  case ocWhitespace:
239  eType = svByte;
240  whitespace.nCount = 1;
241  whitespace.cChar = 0x20;
242  break;
243  default:
244  eType = svByte;
245  sbyte.cByte = 0;
246  sbyte.eInForceArray = ParamClass::Unknown;
247  }
248 }
249 
250 void ScRawToken::SetString( rtl_uString* pData, rtl_uString* pDataIgoreCase )
251 {
252  eOp = ocPush;
253  eType = svString;
254 
255  sharedstring.mpData = pData;
256  sharedstring.mpDataIgnoreCase = pDataIgoreCase;
257 }
258 
260 {
261  eOp = ocPush;
262  eType = svSingleRef;
263  aRef.Ref1 =
264  aRef.Ref2 = rRef;
265 }
266 
268 {
269  eOp = ocPush;
270  eType = svDoubleRef;
271  aRef = rRef;
272 }
273 
274 void ScRawToken::SetDouble(double rVal)
275 {
276  eOp = ocPush;
277  eType = svDouble;
278  nValue = rVal;
279 }
280 
282 {
283  eOp = ocPush;
284  eType = svError;
285  nError = nErr;
286 }
287 
288 void ScRawToken::SetName(sal_Int16 nSheet, sal_uInt16 nIndex)
289 {
290  eOp = ocName;
291  eType = svIndex;
292 
293  name.nSheet = nSheet;
294  name.nIndex = nIndex;
295 }
296 
297 void ScRawToken::SetExternalSingleRef( sal_uInt16 nFileId, const OUString& rTabName, const ScSingleRefData& rRef )
298 {
299  eOp = ocPush;
301 
302  extref.nFileId = nFileId;
303  extref.aRef.Ref1 =
304  extref.aRef.Ref2 = rRef;
305  maExternalName = rTabName;
306 }
307 
308 void ScRawToken::SetExternalDoubleRef( sal_uInt16 nFileId, const OUString& rTabName, const ScComplexRefData& rRef )
309 {
310  eOp = ocPush;
312 
313  extref.nFileId = nFileId;
314  extref.aRef = rRef;
315  maExternalName = rTabName;
316 }
317 
318 void ScRawToken::SetExternalName( sal_uInt16 nFileId, const OUString& rName )
319 {
320  eOp = ocPush;
322 
323  extname.nFileId = nFileId;
324  maExternalName = rName;
325 }
326 
327 void ScRawToken::SetExternal( const OUString& rStr )
328 {
329  eOp = ocExternal;
330  eType = svExternal;
331  maExternalName = rStr;
332 }
333 
335 {
336  switch (eType)
337  {
338  case svSingleRef:
339  return aRef.Ref1.Valid(rDoc);
340  case svDoubleRef:
341  return aRef.Valid(rDoc);
342  case svExternalSingleRef:
343  case svExternalDoubleRef:
344  return true;
345  default:
346  ; // nothing
347  }
348  return false;
349 }
350 
352 {
353 #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!")
354  switch ( GetType() )
355  {
356  case svByte :
357  if (eOp == ocWhitespace)
358  return new FormulaSpaceToken( whitespace.nCount, whitespace.cChar );
359  else
360  return new FormulaByteToken( eOp, sbyte.cByte, sbyte.eInForceArray );
361  case svDouble :
363  return new FormulaDoubleToken( nValue );
364  case svString :
365  {
366  svl::SharedString aSS(sharedstring.mpData, sharedstring.mpDataIgnoreCase);
367  if (eOp == ocPush)
368  return new FormulaStringToken(aSS);
369  else
370  return new FormulaStringOpToken(eOp, aSS);
371  }
372  case svSingleRef :
373  if (eOp == ocPush)
374  return new ScSingleRefToken(rLimits, aRef.Ref1 );
375  else
376  return new ScSingleRefToken(rLimits, aRef.Ref1, eOp );
377  case svDoubleRef :
378  if (eOp == ocPush)
379  return new ScDoubleRefToken(rLimits, aRef );
380  else
381  return new ScDoubleRefToken(rLimits, aRef, eOp );
382  case svMatrix :
384  return new ScMatrixToken( pMat );
385  case svIndex :
386  if (eOp == ocTableRef)
387  return new ScTableRefToken( table.nIndex, table.eItem);
388  else
389  return new FormulaIndexToken( eOp, name.nIndex, name.nSheet);
390  case svExternalSingleRef:
391  {
392  svl::SharedString aTabName(maExternalName); // string not interned
393  return new ScExternalSingleRefToken(extref.nFileId, aTabName, extref.aRef.Ref1);
394  }
395  case svExternalDoubleRef:
396  {
397  svl::SharedString aTabName(maExternalName); // string not interned
398  return new ScExternalDoubleRefToken(extref.nFileId, aTabName, extref.aRef);
399  }
400  case svExternalName:
401  {
402  svl::SharedString aName(maExternalName); // string not interned
403  return new ScExternalNameToken( extname.nFileId, aName );
404  }
405  case svJump :
406  return new FormulaJumpToken( eOp, nJump );
407  case svExternal :
408  return new FormulaExternalToken( eOp, sbyte.cByte, maExternalName );
409  case svFAP :
410  return new FormulaFAPToken( eOp, sbyte.cByte, nullptr );
411  case svMissing :
413  return new FormulaMissingToken;
414  case svSep :
415  return new FormulaToken( svSep,eOp );
416  case svError :
417  return new FormulaErrorToken( nError );
418  case svUnknown :
419  return new FormulaUnknownToken( eOp );
420  default:
421  {
422  SAL_WARN("sc.core", "unknown ScRawToken::CreateToken() type " << int(GetType()));
423  return new FormulaUnknownToken( ocBad );
424  }
425  }
426 #undef IF_NOT_OPCODE_ERROR
427 }
428 
429 namespace {
430 
431 // TextEqual: if same formula entered (for optimization in sort)
432 bool checkTextEqual( const ScSheetLimits& rLimits, const FormulaToken& _rToken1, const FormulaToken& _rToken2 )
433 {
434  assert(
435  (_rToken1.GetType() == svSingleRef || _rToken1.GetType() == svDoubleRef)
436  && _rToken1.FormulaToken::operator ==(_rToken2));
437 
438  // in relative Refs only compare relative parts
439 
440  ScComplexRefData aTemp1;
441  if ( _rToken1.GetType() == svSingleRef )
442  {
443  aTemp1.Ref1 = *_rToken1.GetSingleRef();
444  aTemp1.Ref2 = aTemp1.Ref1;
445  }
446  else
447  aTemp1 = *_rToken1.GetDoubleRef();
448 
449  ScComplexRefData aTemp2;
450  if ( _rToken2.GetType() == svSingleRef )
451  {
452  aTemp2.Ref1 = *_rToken2.GetSingleRef();
453  aTemp2.Ref2 = aTemp2.Ref1;
454  }
455  else
456  aTemp2 = *_rToken2.GetDoubleRef();
457 
458  ScAddress aPos;
459  ScRange aRange1 = aTemp1.toAbs(rLimits, aPos), aRange2 = aTemp2.toAbs(rLimits, aPos);
460 
461  // memcmp doesn't work because of the alignment byte after bFlags.
462  // After SmartRelAbs only absolute parts have to be compared.
463  return aRange1 == aRange2 && aTemp1.Ref1.FlagValue() == aTemp2.Ref1.FlagValue() && aTemp1.Ref2.FlagValue() == aTemp2.Ref2.FlagValue();
464 }
465 
466 }
467 
468 #if DEBUG_FORMULA_COMPILER
469 void DumpToken(formula::FormulaToken const & rToken)
470 {
471  switch (rToken.GetType()) {
472  case svSingleRef:
473  cout << "-- ScSingleRefToken" << endl;
474  rToken.GetSingleRef()->Dump(1);
475  break;
476  case svDoubleRef:
477  cout << "-- ScDoubleRefToken" << endl;
478  rToken.GetDoubleRef()->Dump(1);
479  break;
480  default:
481  cout << "-- FormulaToken" << endl;
482  cout << " opcode: " << int(rToken.GetOpCode()) << " " <<
483  formula::FormulaCompiler::GetNativeSymbol( rToken.GetOpCode()).toUtf8().getStr() << endl;
484  cout << " type: " << static_cast<int>(rToken.GetType()) << endl;
485  switch (rToken.GetType())
486  {
487  case svDouble:
488  cout << " value: " << rToken.GetDouble() << endl;
489  break;
490  case svString:
491  cout << " string: "
492  << OUStringToOString(rToken.GetString().getString(), RTL_TEXTENCODING_UTF8).getStr()
493  << endl;
494  break;
495  default:
496  ;
497  }
498  break;
499  }
500 }
501 #endif
502 
504  const ScAddress & rPos, bool bReuseDoubleRef )
505 {
506 
507  StackVar sv1 = rTok1.GetType();
508  // Doing a RangeOp with RefList is probably utter nonsense, but Xcl
509  // supports it, so do we.
510  if (sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList
511  && sv1 != svExternalSingleRef && sv1 != svExternalDoubleRef)
512  return nullptr;
513  StackVar sv2 = rTok2.GetType();
514  if (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList)
515  return nullptr;
516 
517  ScTokenRef xRes;
518  bool bExternal = (sv1 == svExternalSingleRef);
519  if ((sv1 == svSingleRef || bExternal) && sv2 == svSingleRef)
520  {
521  // Range references like Sheet1.A1:A2 are generalized and built by
522  // first creating a DoubleRef from the first SingleRef, effectively
523  // generating Sheet1.A1:A1, and then extending that with A2 as if
524  // Sheet1.A1:A1:A2 was encountered, so the mechanisms to adjust the
525  // references apply as well.
526 
527  /* Given the current structure of external references an external
528  * reference can only be extended if the second reference does not
529  * point to a different sheet. 'file'#Sheet1.A1:A2 is ok,
530  * 'file'#Sheet1.A1:Sheet2.A2 is not. Since we can't determine from a
531  * svSingleRef whether the sheet would be different from the one given
532  * in the external reference, we have to bail out if there is any sheet
533  * specified. NOTE: Xcl does handle external 3D references as in
534  * '[file]Sheet1:Sheet2'!A1:A2
535  *
536  * FIXME: For OOo syntax be smart and remember an external singleref
537  * encountered and if followed by ocRange and singleref, create an
538  * external singleref for the second singleref. Both could then be
539  * merged here. For Xcl syntax already parse an external range
540  * reference entirely, cumbersome. */
541 
542  const ScSingleRefData& rRef2 = *rTok2.GetSingleRef();
543  if (bExternal && rRef2.IsFlag3D())
544  return nullptr;
545 
546  ScComplexRefData aRef;
547  aRef.Ref1 = aRef.Ref2 = *rTok1.GetSingleRef();
548  aRef.Ref2.SetFlag3D( false);
549  aRef.Extend(rLimits, rRef2, rPos);
550  if (bExternal)
551  xRes = new ScExternalDoubleRefToken( rTok1.GetIndex(), rTok1.GetString(), aRef);
552  else
553  xRes = new ScDoubleRefToken(rLimits, aRef);
554  }
555  else
556  {
557  bExternal |= (sv1 == svExternalDoubleRef);
558  const ScRefList* pRefList = nullptr;
559  if (sv1 == svDoubleRef)
560  {
561  xRes = (bReuseDoubleRef && rTok1.GetRef() == 1 ? &rTok1 : rTok1.Clone());
562  sv1 = svUnknown; // mark as handled
563  }
564  else if (sv2 == svDoubleRef)
565  {
566  xRes = (bReuseDoubleRef && rTok2.GetRef() == 1 ? &rTok2 : rTok2.Clone());
567  sv2 = svUnknown; // mark as handled
568  }
569  else if (sv1 == svRefList)
570  pRefList = rTok1.GetRefList();
571  else if (sv2 == svRefList)
572  pRefList = rTok2.GetRefList();
573  if (pRefList)
574  {
575  if (pRefList->empty())
576  return nullptr;
577  if (bExternal)
578  return nullptr; // external reference list not possible
579  xRes = new ScDoubleRefToken(rLimits, (*pRefList)[0] );
580  }
581  if (!xRes)
582  return nullptr; // shouldn't happen...
583  StackVar sv[2] = { sv1, sv2 };
584  formula::FormulaToken* pt[2] = { &rTok1, &rTok2 };
585  ScComplexRefData& rRef = *xRes->GetDoubleRef();
586  for (size_t i=0; i<2; ++i)
587  {
588  switch (sv[i])
589  {
590  case svSingleRef:
591  rRef.Extend(rLimits, *pt[i]->GetSingleRef(), rPos);
592  break;
593  case svDoubleRef:
594  rRef.Extend(rLimits, *pt[i]->GetDoubleRef(), rPos);
595  break;
596  case svRefList:
597  {
598  const ScRefList* p = pt[i]->GetRefList();
599  if (p->empty())
600  return nullptr;
601  for (const auto& rRefData : *p)
602  {
603  rRef.Extend(rLimits, rRefData, rPos);
604  }
605  }
606  break;
607  case svExternalSingleRef:
608  if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D())
609  return nullptr; // no other sheets with external refs
610  else
611  rRef.Extend(rLimits, *pt[i]->GetSingleRef(), rPos);
612  break;
613  case svExternalDoubleRef:
614  if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D())
615  return nullptr; // no other sheets with external refs
616  else
617  rRef.Extend(rLimits, *pt[i]->GetDoubleRef(), rPos);
618  break;
619  default:
620  ; // nothing, prevent compiler warning
621  }
622  }
623  }
624  return FormulaTokenRef(xRes.get());
625 }
626 
627 // real implementations of virtual functions
628 
629 const ScSingleRefData* ScSingleRefToken::GetSingleRef() const { return &aSingleRef; }
631 bool ScSingleRefToken::TextEqual( const FormulaToken& _rToken ) const
632 {
633  return FormulaToken::operator ==(_rToken) && checkTextEqual(mrSheetLimits, *this, _rToken);
634 }
636 {
637  return FormulaToken::operator==( r ) && aSingleRef == *r.GetSingleRef();
638 }
639 
640 const ScSingleRefData* ScDoubleRefToken::GetSingleRef() const { return &aDoubleRef.Ref1; }
641 ScSingleRefData* ScDoubleRefToken::GetSingleRef() { return &aDoubleRef.Ref1; }
642 const ScComplexRefData* ScDoubleRefToken::GetDoubleRef() const { return &aDoubleRef; }
644 const ScSingleRefData* ScDoubleRefToken::GetSingleRef2() const { return &aDoubleRef.Ref2; }
645 ScSingleRefData* ScDoubleRefToken::GetSingleRef2() { return &aDoubleRef.Ref2; }
646 bool ScDoubleRefToken::TextEqual( const FormulaToken& _rToken ) const
647 {
648  return FormulaToken::operator ==(_rToken) && checkTextEqual(mrSheetLimits, *this, _rToken);
649 }
651 {
652  return FormulaToken::operator==( r ) && aDoubleRef == *r.GetDoubleRef();
653 }
654 
655 const ScRefList* ScRefListToken::GetRefList() const { return &aRefList; }
656  ScRefList* ScRefListToken::GetRefList() { return &aRefList; }
657  bool ScRefListToken::IsArrayResult() const { return mbArrayResult; }
659 {
660  if (!FormulaToken::operator==( r ) || &aRefList != r.GetRefList())
661  return false;
662  const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(&r);
663  return p && mbArrayResult == p->IsArrayResult();
664 }
665 
667  FormulaToken(formula::svMatrix), pMatrix(p) {}
668 
669 ScMatrixToken::ScMatrixToken( const ScMatrixToken& ) = default;
670 
671 const ScMatrix* ScMatrixToken::GetMatrix() const { return pMatrix.get(); }
674 {
675  return FormulaToken::operator==( r ) && pMatrix == r.GetMatrix();
676 }
677 
679  FormulaToken(formula::svMatrix), mpMatrix(rMat.mpMat)
680 {
681  maRef.InitRange(rMat.mnCol1, rMat.mnRow1, rMat.mnTab1, rMat.mnCol2, rMat.mnRow2, rMat.mnTab2);
682 }
683 
685 
687 {
688  return MATRIX_TOKEN_HAS_RANGE;
689 }
690 
692 {
693  return mpMatrix.get();
694 }
695 
697 {
698  return mpMatrix.get();
699 }
700 
702 {
703  return &maRef;
704 }
705 
707 {
708  return &maRef;
709 }
710 
712 {
713  return FormulaToken::operator==(r) && mpMatrix == r.GetMatrix();
714 }
715 
717 {
718  return new ScMatrixRangeToken(*this);
719 }
720 
723  mnFileId(nFileId),
724  maTabName(rTabName),
725  maSingleRef(r)
726 {
727 }
728 
730 {
731 }
732 
734 {
735  return mnFileId;
736 }
737 
739 {
740  return maTabName;
741 }
742 
744 {
745  return &maSingleRef;
746 }
747 
749 {
750  return &maSingleRef;
751 }
752 
754 {
755  if (!FormulaToken::operator==(r))
756  return false;
757 
758  if (mnFileId != r.GetIndex())
759  return false;
760 
761  if (maTabName != r.GetString())
762  return false;
763 
764  return maSingleRef == *r.GetSingleRef();
765 }
766 
769  mnFileId(nFileId),
770  maTabName(rTabName),
771  maDoubleRef(r)
772 {
773 }
774 
776 {
777 }
778 
780 {
781  return mnFileId;
782 }
783 
785 {
786  return maTabName;
787 }
788 
790 {
791  return &maDoubleRef.Ref1;
792 }
793 
795 {
796  return &maDoubleRef.Ref1;
797 }
798 
800 {
801  return &maDoubleRef.Ref2;
802 }
803 
805 {
806  return &maDoubleRef.Ref2;
807 }
808 
810 {
811  return &maDoubleRef;
812 }
813 
815 {
816  return &maDoubleRef;
817 }
818 
820 {
821  if (!FormulaToken::operator==(r))
822  return false;
823 
824  if (mnFileId != r.GetIndex())
825  return false;
826 
827  if (maTabName != r.GetString())
828  return false;
829 
830  return maDoubleRef == *r.GetDoubleRef();
831 }
832 
833 ScExternalNameToken::ScExternalNameToken( sal_uInt16 nFileId, const svl::SharedString& rName ) :
835  mnFileId(nFileId),
836  maName(rName)
837 {
838 }
839 
841 
843 {
844  return mnFileId;
845 }
846 
848 {
849  return maName;
850 }
851 
853 {
854  if ( !FormulaToken::operator==(r) )
855  return false;
856 
857  if (mnFileId != r.GetIndex())
858  return false;
859 
860  return maName.getData() == r.GetString().getData();
861 }
862 
865  mnIndex(nIndex),
866  meItem(eItem)
867 {
868 }
869 
871  FormulaToken(r),
872  mxAreaRefRPN( r.mxAreaRefRPN ? r.mxAreaRefRPN->Clone() : nullptr),
873  mnIndex(r.mnIndex),
874  meItem(r.meItem)
875 {
876 }
877 
879 
880 sal_uInt16 ScTableRefToken::GetIndex() const
881 {
882  return mnIndex;
883 }
884 
885 void ScTableRefToken::SetIndex( sal_uInt16 n )
886 {
887  mnIndex = n;
888 }
889 
890 sal_Int16 ScTableRefToken::GetSheet() const
891 {
892  // Code asking for this may have to be adapted as it might assume an
893  // svIndex token would always be ocName or ocDBArea.
894  SAL_WARN("sc.core","ScTableRefToken::GetSheet - maybe adapt caller to know about TableRef?");
895  // Database range is always global.
896  return -1;
897 }
898 
900 {
901  return meItem;
902 }
903 
905 {
906  meItem = static_cast<ScTableRefToken::Item>(meItem | eItem);
907 }
908 
910 {
911  mxAreaRefRPN = pToken;
912 }
913 
915 {
916  return mxAreaRefRPN.get();
917 }
918 
920 {
921  if ( !FormulaToken::operator==(r) )
922  return false;
923 
924  if (mnIndex != r.GetIndex())
925  return false;
926 
927  const ScTableRefToken* p = dynamic_cast<const ScTableRefToken*>(&r);
928  if (!p)
929  return false;
930 
931  if (meItem != p->GetItem())
932  return false;
933 
934  if (!mxAreaRefRPN && !p->mxAreaRefRPN)
935  ; // nothing
936  else if (!mxAreaRefRPN || !p->mxAreaRefRPN)
937  return false;
938  else if (!(*mxAreaRefRPN == *(p->mxAreaRefRPN)))
939  return false;
940 
941  return true;
942 }
943 
944 ScJumpMatrixToken::ScJumpMatrixToken(std::shared_ptr<ScJumpMatrix> p)
946  , mpJumpMatrix(std::move(p))
947 {}
948 
950 
952 {
953  return mpJumpMatrix.get();
954 }
955 
957 {
958  return FormulaToken::operator==( r ) && mpJumpMatrix.get() == r.GetJumpMatrix();
959 }
960 
962 {
963 }
964 
965 double ScEmptyCellToken::GetDouble() const { return 0.0; }
966 
968 {
970 }
971 
973 {
974  return FormulaToken::operator==( r ) &&
975  bInherited == static_cast< const ScEmptyCellToken & >(r).IsInherited() &&
976  bDisplayedAsString == static_cast< const ScEmptyCellToken & >(r).IsDisplayedAsString();
977 }
978 
980  FormulaToken(formula::svMatrixCell), xMatrix(pMat), xUpperLeft(pUL) {}
981 
983 
984 double ScMatrixCellResultToken::GetDouble() const { return xUpperLeft->GetDouble(); }
985 
987 
989 {
990  return xUpperLeft->GetString();
991 }
992 
993 const ScMatrix* ScMatrixCellResultToken::GetMatrix() const { return xMatrix.get(); }
994 // Non-const GetMatrix() is private and unused but must be implemented to
995 // satisfy vtable linkage.
997 {
998  return const_cast<ScMatrix*>(xMatrix.get());
999 }
1000 
1002 {
1003  return FormulaToken::operator==( r ) &&
1004  xUpperLeft == static_cast<const ScMatrixCellResultToken &>(r).xUpperLeft &&
1005  xMatrix == static_cast<const ScMatrixCellResultToken &>(r).xMatrix;
1006 }
1007 
1009 {
1010  return new ScMatrixCellResultToken(*this);
1011 }
1012 
1014 {
1015  xMatrix = r.xMatrix;
1016  xUpperLeft = r.xUpperLeft;
1017 }
1018 
1020  SCCOL nC, SCROW nR, const ScConstMatrixRef& pMat, const formula::FormulaToken* pUL ) :
1021  ScMatrixCellResultToken(pMat, pUL), nRows(nR), nCols(nC)
1022 {
1024 }
1025 
1027  ScMatrixCellResultToken(nullptr, nullptr), nRows(nR), nCols(nC) {}
1028 
1030  ScMatrixCellResultToken(r), nRows(r.nRows), nCols(r.nCols)
1031 {
1033 }
1034 
1036 
1038 {
1039  const ScMatrixFormulaCellToken* p = dynamic_cast<const ScMatrixFormulaCellToken*>(&r);
1040  return p && ScMatrixCellResultToken::operator==( r ) &&
1041  nCols == p->nCols && nRows == p->nRows;
1042 }
1043 
1045 {
1046  if (xUpperLeft && xUpperLeft->GetType() == svDouble)
1047  xUpperLeft = xUpperLeft->Clone();
1048 }
1049 
1051 {
1053 
1055 }
1056 
1058 {
1059  if (this == &r)
1060  return;
1061  const ScMatrixCellResultToken* p = dynamic_cast<const ScMatrixCellResultToken*>(&r);
1062  if (p)
1064  else
1065  {
1066  OSL_ENSURE( r.GetType() != svMatrix, "ScMatrixFormulaCellToken::operator=: assigning ScMatrixToken to ScMatrixFormulaCellToken is not proper, use ScMatrixCellResultToken instead");
1067  if (r.GetType() == svMatrix)
1068  {
1069  xUpperLeft = nullptr;
1070  xMatrix = r.GetMatrix();
1071  }
1072  else
1073  {
1074  xUpperLeft = &r;
1075  xMatrix = nullptr;
1077  }
1078  }
1079 }
1080 
1082 {
1083  switch (GetUpperLeftType())
1084  {
1085  case svDouble:
1086  const_cast<FormulaToken*>(xUpperLeft.get())->GetDoubleAsReference() = f;
1087  break;
1088  case svString:
1089  xUpperLeft = new FormulaDoubleToken( f);
1090  break;
1091  case svUnknown:
1092  if (!xUpperLeft)
1093  {
1094  xUpperLeft = new FormulaDoubleToken( f);
1095  break;
1096  }
1097  [[fallthrough]];
1098  default:
1099  {
1100  OSL_FAIL("ScMatrixFormulaCellToken::SetUpperLeftDouble: not modifying unhandled token type");
1101  }
1102  }
1103 }
1104 
1106 {
1107  xMatrix = nullptr;
1108  xUpperLeft = nullptr;
1109 }
1110 
1112  double f, const svl::SharedString & rStr, const OUString & rFormula, bool bEmptyDisplayedAsString ) :
1114  mfDouble( f ), maString( rStr ),
1115  maFormula( rFormula ),
1116  mbEmptyDisplayedAsString( bEmptyDisplayedAsString)
1117 {
1118  // caller, make up your mind...
1119  assert( !bEmptyDisplayedAsString || (f == 0.0 && rStr.getString().isEmpty()));
1120 }
1121 
1122 double ScHybridCellToken::GetDouble() const { return mfDouble; }
1123 
1125 {
1126  return maString;
1127 }
1128 
1130 {
1131  return FormulaToken::operator==( r ) &&
1132  mfDouble == r.GetDouble() && maString == r.GetString() &&
1133  maFormula == static_cast<const ScHybridCellToken &>(r).GetFormula();
1134 }
1135 
1137  const css::sheet::FormulaToken& rToken, svl::SharedStringPool& rSPool, formula::ExternalReferenceHelper* pExtRef)
1138 {
1139  bool bError = FormulaTokenArray::AddFormulaToken(rToken, rSPool, pExtRef);
1140  if ( bError )
1141  {
1142  bError = false;
1143  const OpCode eOpCode = static_cast<OpCode>(rToken.OpCode); // assuming equal values for the moment
1144 
1145  const uno::TypeClass eClass = rToken.Data.getValueTypeClass();
1146  switch ( eClass )
1147  {
1148  case uno::TypeClass_STRUCT:
1149  {
1150  uno::Type aType = rToken.Data.getValueType();
1151  if ( aType.equals( cppu::UnoType<sheet::SingleReference>::get() ) )
1152  {
1153  ScSingleRefData aSingleRef;
1154  sheet::SingleReference aApiRef;
1155  rToken.Data >>= aApiRef;
1156  lcl_SingleRefToCalc( aSingleRef, aApiRef );
1157  if ( eOpCode == ocPush )
1158  AddSingleReference( aSingleRef );
1159  else if ( eOpCode == ocColRowName )
1160  AddColRowName( aSingleRef );
1161  else
1162  bError = true;
1163  }
1164  else if ( aType.equals( cppu::UnoType<sheet::ComplexReference>::get() ) )
1165  {
1166  ScComplexRefData aComplRef;
1167  sheet::ComplexReference aApiRef;
1168  rToken.Data >>= aApiRef;
1169  lcl_SingleRefToCalc( aComplRef.Ref1, aApiRef.Reference1 );
1170  lcl_SingleRefToCalc( aComplRef.Ref2, aApiRef.Reference2 );
1171 
1172  if ( eOpCode == ocPush )
1173  AddDoubleReference( aComplRef );
1174  else
1175  bError = true;
1176  }
1177  else if ( aType.equals( cppu::UnoType<sheet::NameToken>::get() ) )
1178  {
1179  sheet::NameToken aTokenData;
1180  rToken.Data >>= aTokenData;
1181  if ( eOpCode == ocName )
1182  {
1183  SAL_WARN_IF( aTokenData.Sheet < -1 || std::numeric_limits<sal_Int16>::max() < aTokenData.Sheet,
1184  "sc.core",
1185  "ScTokenArray::AddFormulaToken - NameToken.Sheet out of limits: " << aTokenData.Sheet);
1186  sal_Int16 nSheet = static_cast<sal_Int16>(aTokenData.Sheet);
1187  AddRangeName(aTokenData.Index, nSheet);
1188  }
1189  else if (eOpCode == ocDBArea)
1190  AddDBRange(aTokenData.Index);
1191  else if (eOpCode == ocTableRef)
1192  bError = true; /* TODO: implementation */
1193  else
1194  bError = true;
1195  }
1196  else if ( aType.equals( cppu::UnoType<sheet::ExternalReference>::get() ) )
1197  {
1198  sheet::ExternalReference aApiExtRef;
1199  if( (eOpCode == ocPush) && (rToken.Data >>= aApiExtRef) && (0 <= aApiExtRef.Index) && (aApiExtRef.Index <= SAL_MAX_UINT16) )
1200  {
1201  sal_uInt16 nFileId = static_cast< sal_uInt16 >( aApiExtRef.Index );
1202  sheet::SingleReference aApiSRef;
1203  sheet::ComplexReference aApiCRef;
1204  OUString aName;
1205  if( aApiExtRef.Reference >>= aApiSRef )
1206  {
1207  // try to resolve cache index to sheet name
1208  size_t nCacheId = static_cast< size_t >( aApiSRef.Sheet );
1209  OUString aTabName = pExtRef->getCacheTableName( nFileId, nCacheId );
1210  if( !aTabName.isEmpty() )
1211  {
1212  ScSingleRefData aSingleRef;
1213  // convert column/row settings, set sheet index to absolute
1214  lcl_ExternalRefToCalc( aSingleRef, aApiSRef );
1215  AddExternalSingleReference( nFileId, rSPool.intern( aTabName), aSingleRef );
1216  }
1217  else
1218  bError = true;
1219  }
1220  else if( aApiExtRef.Reference >>= aApiCRef )
1221  {
1222  // try to resolve cache index to sheet name.
1223  size_t nCacheId = static_cast< size_t >( aApiCRef.Reference1.Sheet );
1224  OUString aTabName = pExtRef->getCacheTableName( nFileId, nCacheId );
1225  if( !aTabName.isEmpty() )
1226  {
1227  ScComplexRefData aComplRef;
1228  // convert column/row settings, set sheet index to absolute
1229  lcl_ExternalRefToCalc( aComplRef.Ref1, aApiCRef.Reference1 );
1230  lcl_ExternalRefToCalc( aComplRef.Ref2, aApiCRef.Reference2 );
1231  // NOTE: This assumes that cached sheets are in consecutive order!
1232  aComplRef.Ref2.SetAbsTab(
1233  aComplRef.Ref1.Tab() + static_cast<SCTAB>(aApiCRef.Reference2.Sheet - aApiCRef.Reference1.Sheet));
1234  AddExternalDoubleReference( nFileId, rSPool.intern( aTabName), aComplRef );
1235  }
1236  else
1237  bError = true;
1238  }
1239  else if( aApiExtRef.Reference >>= aName )
1240  {
1241  if( !aName.isEmpty() )
1242  AddExternalName( nFileId, rSPool.intern( aName) );
1243  else
1244  bError = true;
1245  }
1246  else
1247  bError = true;
1248  }
1249  else
1250  bError = true;
1251  }
1252  else
1253  bError = true; // unknown struct
1254  }
1255  break;
1256  case uno::TypeClass_SEQUENCE:
1257  {
1258  if ( eOpCode != ocPush )
1259  bError = true; // not an inline array
1260  else if (!rToken.Data.getValueType().equals( cppu::UnoType<
1261  uno::Sequence< uno::Sequence< uno::Any >>>::get()))
1262  bError = true; // unexpected sequence type
1263  else
1264  {
1266  if (xMat)
1267  AddMatrix( xMat);
1268  else
1269  bError = true;
1270  }
1271  }
1272  break;
1273  default:
1274  bError = true;
1275  }
1276  }
1277  return bError;
1278 }
1279 
1281 {
1282 #if HAVE_CPP_CONSTINIT_SORTED_VECTOR
1283  constinit
1284 #endif
1285  static const o3tl::sorted_vector<OpCode> aThreadedCalcDenyList({
1286  ocIndirect,
1287  ocMacro,
1288  ocOffset,
1289  ocTableOp,
1290  ocCell,
1291  ocMatch,
1292  ocInfo,
1293  ocStyle,
1294  ocDBAverage,
1295  ocDBCount,
1296  ocDBCount2,
1297  ocDBGet,
1298  ocDBMax,
1299  ocDBMin,
1300  ocDBProduct,
1301  ocDBStdDev,
1302  ocDBStdDevP,
1303  ocDBSum,
1304  ocDBVar,
1305  ocDBVarP,
1306  ocText,
1307  ocSheet,
1308  ocExternal,
1309  ocDde,
1310  ocWebservice,
1312  });
1313 
1314  // Don't enable threading once we decided to disable it.
1315  if (!mbThreadingEnabled)
1316  return;
1317 
1318  static const bool bThreadingProhibited = std::getenv("SC_NO_THREADED_CALCULATION");
1319 
1320  if (bThreadingProhibited)
1321  {
1322  mbThreadingEnabled = false;
1323  return;
1324  }
1325 
1326  OpCode eOp = r.GetOpCode();
1327 
1328  if (aThreadedCalcDenyList.find(eOp) != aThreadedCalcDenyList.end())
1329  {
1330  SAL_INFO("sc.core.formulagroup", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp)
1331  << "(" << int(eOp) << ") disables threaded calculation of formula group");
1332  mbThreadingEnabled = false;
1333  return;
1334  }
1335 
1336  if (eOp != ocPush)
1337  return;
1338 
1339  switch (r.GetType())
1340  {
1341  case svExternalDoubleRef:
1342  case svExternalSingleRef:
1343  case svExternalName:
1344  case svMatrix:
1345  SAL_INFO("sc.core.formulagroup", "opcode ocPush: variable type " << StackVarEnumToString(r.GetType())
1346  << " disables threaded calculation of formula group");
1347  mbThreadingEnabled = false;
1348  return;
1349  default:
1350  break;
1351  }
1352 }
1353 
1355 {
1356  if (mbThreadingEnabled)
1357  CheckForThreading(r);
1358 
1360  return; // It's already disabled. No more checking needed.
1361 
1362  OpCode eOp = r.GetOpCode();
1363 
1365  {
1366  if (ScInterpreter::GetGlobalConfig().mbOpenCLSubsetOnly &&
1367  ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes->find(eOp) == ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes->end())
1368  {
1369  SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp)
1370  << "(" << int(eOp) << ") disables vectorisation for formula group");
1372  mbOpenCLEnabled = false;
1373  return;
1374  }
1375 
1376  // We support vectorization for the following opcodes.
1377  switch (eOp)
1378  {
1379  case ocAverage:
1380  case ocMin:
1381  case ocMinA:
1382  case ocMax:
1383  case ocMaxA:
1384  case ocSum:
1385  case ocSumIfs:
1386  case ocSumProduct:
1387  case ocCount:
1388  case ocCount2:
1389  case ocVLookup:
1390  case ocSLN:
1391  case ocIRR:
1392  case ocMIRR:
1393  case ocPMT:
1394  case ocRate:
1395  case ocRRI:
1396  case ocPpmt:
1397  case ocFisher:
1398  case ocFisherInv:
1399  case ocGamma:
1400  case ocGammaLn:
1401  case ocNotAvail:
1402  case ocGauss:
1403  case ocGeoMean:
1404  case ocHarMean:
1405  case ocSYD:
1406  case ocCorrel:
1407  case ocNegBinomVert:
1408  case ocPearson:
1409  case ocRSQ:
1410  case ocCos:
1411  case ocCosecant:
1412  case ocCosecantHyp:
1413  case ocISPMT:
1414  case ocPDuration:
1415  case ocSinHyp:
1416  case ocAbs:
1417  case ocPV:
1418  case ocSin:
1419  case ocTan:
1420  case ocTanHyp:
1421  case ocStandard:
1422  case ocWeibull:
1423  case ocMedian:
1424  case ocDDB:
1425  case ocFV:
1426  case ocVBD:
1427  case ocKurt:
1428  case ocNper:
1429  case ocNormDist:
1430  case ocArcCos:
1431  case ocSqrt:
1432  case ocArcCosHyp:
1433  case ocNPV:
1434  case ocStdNormDist:
1435  case ocNormInv:
1436  case ocSNormInv:
1437  case ocPermut:
1438  case ocPermutationA:
1439  case ocPhi:
1440  case ocIpmt:
1441  case ocConfidence:
1442  case ocIntercept:
1443  case ocDB:
1444  case ocLogInv:
1445  case ocArcCot:
1446  case ocCosHyp:
1447  case ocCritBinom:
1448  case ocArcCotHyp:
1449  case ocArcSin:
1450  case ocArcSinHyp:
1451  case ocArcTan:
1452  case ocArcTanHyp:
1453  case ocBitAnd:
1454  case ocForecast:
1455  case ocLogNormDist:
1456  case ocGammaDist:
1457  case ocLn:
1458  case ocRound:
1459  case ocCot:
1460  case ocCotHyp:
1461  case ocFDist:
1462  case ocVar:
1463  case ocChiDist:
1464  case ocPower:
1465  case ocOdd:
1466  case ocChiSqDist:
1467  case ocChiSqInv:
1468  case ocGammaInv:
1469  case ocFloor:
1470  case ocFInv:
1471  case ocFTest:
1472  case ocB:
1473  case ocBetaDist:
1474  case ocExp:
1475  case ocLog10:
1476  case ocExpDist:
1477  case ocAverageIfs:
1478  case ocCountIfs:
1479  case ocCombinA:
1480  case ocEven:
1481  case ocLog:
1482  case ocMod:
1483  case ocTrunc:
1484  case ocSkew:
1485  case ocArcTan2:
1486  case ocBitOr:
1487  case ocBitLshift:
1488  case ocBitRshift:
1489  case ocBitXor:
1490  case ocChiInv:
1491  case ocPoissonDist:
1492  case ocSumSQ:
1493  case ocSkewp:
1494  case ocBinomDist:
1495  case ocVarP:
1496  case ocCeil:
1497  case ocCombin:
1498  case ocDevSq:
1499  case ocStDev:
1500  case ocSlope:
1501  case ocSTEYX:
1502  case ocZTest:
1503  case ocPi:
1504  case ocRandom:
1505  case ocProduct:
1506  case ocHypGeomDist:
1507  case ocSumX2MY2:
1508  case ocSumX2DY2:
1509  case ocBetaInv:
1510  case ocTTest:
1511  case ocTDist:
1512  case ocTInv:
1513  case ocSumXMY2:
1514  case ocStDevP:
1515  case ocCovar:
1516  case ocAnd:
1517  case ocOr:
1518  case ocNot:
1519  case ocXor:
1520  case ocDBMax:
1521  case ocDBMin:
1522  case ocDBProduct:
1523  case ocDBAverage:
1524  case ocDBStdDev:
1525  case ocDBStdDevP:
1526  case ocDBSum:
1527  case ocDBVar:
1528  case ocDBVarP:
1529  case ocAverageIf:
1530  case ocDBCount:
1531  case ocDBCount2:
1532  case ocDeg:
1533  case ocRoundUp:
1534  case ocRoundDown:
1535  case ocInt:
1536  case ocRad:
1537  case ocCountIf:
1538  case ocIsEven:
1539  case ocIsOdd:
1540  case ocFact:
1541  case ocAverageA:
1542  case ocVarA:
1543  case ocVarPA:
1544  case ocStDevA:
1545  case ocStDevPA:
1546  case ocSecant:
1547  case ocSecantHyp:
1548  case ocSumIf:
1549  case ocNegSub:
1550  case ocAveDev:
1551  // Don't change the state.
1552  break;
1553  default:
1554  SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp)
1555  << "(" << int(eOp) << ") disables vectorisation for formula group");
1557  mbOpenCLEnabled = false;
1558  return;
1559  }
1560  }
1561  else if (eOp == ocPush)
1562  {
1563  // This is a stack variable. See if this is a reference.
1564 
1565  switch (r.GetType())
1566  {
1567  case svByte:
1568  case svDouble:
1569  case svString:
1570  // Don't change the state.
1571  break;
1572  case svSingleRef:
1573  case svDoubleRef:
1574  // Depends on the reference state.
1576  break;
1577  case svError:
1578  case svEmptyCell:
1579  case svExternal:
1580  case svExternalDoubleRef:
1581  case svExternalName:
1582  case svExternalSingleRef:
1583  case svFAP:
1584  case svHybridCell:
1585  case svIndex:
1586  case svJump:
1587  case svJumpMatrix:
1588  case svMatrix:
1589  case svMatrixCell:
1590  case svMissing:
1591  case svRefList:
1592  case svSep:
1593  case svUnknown:
1594  // We don't support vectorization on these.
1595  SAL_INFO("sc.opencl", "opcode ocPush: variable type " << StackVarEnumToString(r.GetType()) << " disables vectorisation for formula group");
1597  mbOpenCLEnabled = false;
1598  return;
1599  default:
1600  ;
1601  }
1602  }
1603  else if (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP)
1604  {
1605  if (ScInterpreter::GetGlobalConfig().mbOpenCLSubsetOnly &&
1606  ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes->find(eOp) == ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes->end())
1607  {
1608  SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp)
1609  << "(" << int(eOp) << ") disables vectorisation for formula group");
1611  mbOpenCLEnabled = false;
1612  return;
1613  }
1614  }
1615  else
1616  {
1617  // All the rest, special commands, separators, error codes, ...
1618  switch (eOp)
1619  {
1620  default:
1621  // Default is off, no vectorization.
1622  // Mentioning some specific values below to indicate why.
1623 
1624  case ocName:
1625  // Named expression would need "recursive" handling of its
1626  // token array for vector state in
1627  // ScFormulaCell::InterpretFormulaGroup() and below.
1628 
1629  case ocDBArea:
1630  // Certainly not a vectorization of the entire area...
1631 
1632  case ocTableRef:
1633  // May result in a single cell or range reference, depending on
1634  // context.
1635 
1636  case ocColRowName:
1637  // The associated reference is the name cell with which to
1638  // create the implicit intersection.
1639 
1640  case ocColRowNameAuto:
1641  // Auto column/row names lead to references computed in
1642  // interpreter.
1643 
1644  SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp)
1645  << "(" << int(eOp) << ") disables vectorisation for formula group");
1647  mbOpenCLEnabled = false;
1648  return;
1649 
1650  // Known good, don't change state.
1651  case ocStop:
1652  case ocExternal:
1653  case ocOpen:
1654  case ocClose:
1655  case ocSep:
1656  case ocArrayOpen:
1657  case ocArrayRowSep:
1658  case ocArrayColSep:
1659  case ocArrayClose:
1660  case ocMissing:
1661  case ocBad:
1662  case ocSpaces:
1663  case ocWhitespace:
1664  case ocSkip:
1665  case ocPercentSign:
1666  case ocErrNull:
1667  case ocErrDivZero:
1668  case ocErrValue:
1669  case ocErrRef:
1670  case ocErrName:
1671  case ocErrNum:
1672  case ocErrNA:
1673  break;
1674  case ocIf:
1675  case ocIfError:
1676  case ocIfNA:
1677  case ocChoose:
1678  // Jump commands are now supported.
1679  break;
1680  }
1681  }
1682 }
1683 
1684 bool ScTokenArray::ImplGetReference( ScRange& rRange, const ScAddress& rPos, bool bValidOnly ) const
1685 {
1686  bool bIs = false;
1687  if ( pCode && nLen == 1 )
1688  {
1689  const FormulaToken* pToken = pCode[0];
1690  if ( pToken )
1691  {
1692  if ( pToken->GetType() == svSingleRef )
1693  {
1694  const ScSingleRefData& rRef = *static_cast<const ScSingleRefToken*>(pToken)->GetSingleRef();
1695  rRange.aStart = rRange.aEnd = rRef.toAbs(*mxSheetLimits, rPos);
1696  bIs = !bValidOnly || mxSheetLimits->ValidAddress(rRange.aStart);
1697  }
1698  else if ( pToken->GetType() == svDoubleRef )
1699  {
1700  const ScComplexRefData& rCompl = *static_cast<const ScDoubleRefToken*>(pToken)->GetDoubleRef();
1701  const ScSingleRefData& rRef1 = rCompl.Ref1;
1702  const ScSingleRefData& rRef2 = rCompl.Ref2;
1703  rRange.aStart = rRef1.toAbs(*mxSheetLimits, rPos);
1704  rRange.aEnd = rRef2.toAbs(*mxSheetLimits, rPos);
1705  bIs = !bValidOnly || mxSheetLimits->ValidRange(rRange);
1706  }
1707  }
1708  }
1709  return bIs;
1710 }
1711 
1712 namespace {
1713 
1714 // we want to compare for similar not identical formulae
1715 // so we can't use actual row & column indices.
1716 size_t HashSingleRef( const ScSingleRefData& rRef )
1717 {
1718  size_t nVal = 0;
1719 
1720  nVal += size_t(rRef.IsColRel());
1721  nVal += (size_t(rRef.IsRowRel()) << 1);
1722  nVal += (size_t(rRef.IsTabRel()) << 2);
1723 
1724  return nVal;
1725 }
1726 
1727 }
1728 
1730 {
1731  static const OUStringHash aHasher;
1732 
1733  size_t nHash = 1;
1734  OpCode eOp;
1735  StackVar eType;
1736  const formula::FormulaToken* p;
1737  sal_uInt16 n = std::min<sal_uInt16>(nLen, 20);
1738  for (sal_uInt16 i = 0; i < n; ++i)
1739  {
1740  p = pCode[i];
1741  eOp = p->GetOpCode();
1742  if (eOp == ocPush)
1743  {
1744  // This is stack variable. Do additional differentiation.
1745  eType = p->GetType();
1746  switch (eType)
1747  {
1748  case svByte:
1749  {
1750  // Constant value.
1751  sal_uInt8 nVal = p->GetByte();
1752  nHash += static_cast<size_t>(nVal);
1753  }
1754  break;
1755  case svDouble:
1756  {
1757  // Constant value.
1758  double fVal = p->GetDouble();
1759  nHash += std::hash<double>()(fVal);
1760  }
1761  break;
1762  case svString:
1763  {
1764  // Constant string.
1765  OUString aStr = p->GetString().getString();
1766  nHash += aHasher(aStr);
1767  }
1768  break;
1769  case svSingleRef:
1770  {
1771  size_t nVal = HashSingleRef(*p->GetSingleRef());
1772  nHash += nVal;
1773  }
1774  break;
1775  case svDoubleRef:
1776  {
1777  const ScComplexRefData& rRef = *p->GetDoubleRef();
1778  size_t nVal1 = HashSingleRef(rRef.Ref1);
1779  size_t nVal2 = HashSingleRef(rRef.Ref2);
1780  nHash += nVal1;
1781  nHash += nVal2;
1782  }
1783  break;
1784  default:
1785  // Use the opcode value in all the other cases.
1786  nHash += static_cast<size_t>(eOp);
1787  }
1788  }
1789  else
1790  // Use the opcode value in all the other cases.
1791  nHash += static_cast<size_t>(eOp);
1792 
1793  nHash = (nHash << 4) - nHash;
1794  }
1795 
1796  mnHashValue = nHash;
1797 }
1798 
1800 {
1804 }
1805 
1807 {
1808  switch (meVectorState)
1809  {
1810  case FormulaVectorDisabled:
1814  return true;
1815  default:
1816  ;
1817  }
1818 
1819  return false;
1820 }
1821 
1823 {
1824  FormulaToken** p = pCode.get();
1825  FormulaToken** pEnd = p + static_cast<size_t>(nLen);
1826  for (; p != pEnd; ++p)
1827  {
1828  switch ((*p)->GetType())
1829  {
1830  case svSingleRef:
1831  case svExternalSingleRef:
1832  {
1833  const ScSingleRefData& rRef = *(*p)->GetSingleRef();
1834  if (rRef.IsRowRel())
1835  return false;
1836  }
1837  break;
1838  case svDoubleRef:
1839  case svExternalDoubleRef:
1840  {
1841  const ScComplexRefData& rRef = *(*p)->GetDoubleRef();
1842  if (rRef.Ref1.IsRowRel() || rRef.Ref2.IsRowRel())
1843  return false;
1844  }
1845  break;
1846  case svIndex:
1847  return false;
1848  default:
1849  ;
1850  }
1851  }
1852 
1853  return true;
1854 }
1855 
1856 bool ScTokenArray::IsReference( ScRange& rRange, const ScAddress& rPos ) const
1857 {
1858  return ImplGetReference(rRange, rPos, false);
1859 }
1860 
1861 bool ScTokenArray::IsValidReference( ScRange& rRange, const ScAddress& rPos ) const
1862 {
1863  return ImplGetReference(rRange, rPos, true);
1864 }
1865 
1867  mxSheetLimits(&rDoc.GetSheetLimits()),
1868  mnHashValue(0)
1869 {
1870  ResetVectorState();
1871 }
1872 
1874  mxSheetLimits(&rLimits),
1875  mnHashValue(0)
1876 {
1877  ResetVectorState();
1878 }
1879 
1881 {
1882 }
1883 
1885 {
1886  Clear();
1887  Assign( rArr );
1888  mnHashValue = rArr.mnHashValue;
1892  return *this;
1893 }
1894 
1896 {
1897  mxSheetLimits = std::move(rArr.mxSheetLimits);
1898  mnHashValue = rArr.mnHashValue;
1899  meVectorState = rArr.meVectorState;
1900  mbOpenCLEnabled = rArr.mbOpenCLEnabled;
1901  mbThreadingEnabled = rArr.mbThreadingEnabled;
1902  Move(std::move(rArr));
1903  return *this;
1904 }
1905 
1906 bool ScTokenArray::EqualTokens( const ScTokenArray* pArr2) const
1907 {
1908  // We only compare the non-RPN array
1909  if ( pArr2->nLen != nLen )
1910  return false;
1911 
1912  FormulaToken** ppToken1 = GetArray();
1913  FormulaToken** ppToken2 = pArr2->GetArray();
1914  for (sal_uInt16 i=0; i<nLen; i++)
1915  {
1916  if ( ppToken1[i] != ppToken2[i] &&
1917  !(*ppToken1[i] == *ppToken2[i]) )
1918  return false; // Difference
1919  }
1920  return true; // All entries are the same
1921 }
1922 
1924 {
1925  mnHashValue = 0;
1926  ResetVectorState();
1927  FormulaTokenArray::Clear();
1928 }
1929 
1930 std::unique_ptr<ScTokenArray> ScTokenArray::Clone() const
1931 {
1932  std::unique_ptr<ScTokenArray> p(new ScTokenArray(*mxSheetLimits));
1933  p->nLen = nLen;
1934  p->nRPN = nRPN;
1935  p->nMode = nMode;
1936  p->nError = nError;
1937  p->bHyperLink = bHyperLink;
1938  p->mnHashValue = mnHashValue;
1939  p->meVectorState = meVectorState;
1940  p->mbOpenCLEnabled = mbOpenCLEnabled;
1941  p->mbThreadingEnabled = mbThreadingEnabled;
1942  p->mbFromRangeName = mbFromRangeName;
1943  p->mbShareable = mbShareable;
1944 
1945  FormulaToken** pp;
1946  if( nLen )
1947  {
1948  p->pCode.reset(new FormulaToken*[ nLen ]);
1949  pp = p->pCode.get();
1950  memcpy( pp, pCode.get(), nLen * sizeof( formula::FormulaToken* ) );
1951  for( sal_uInt16 i = 0; i < nLen; i++, pp++ )
1952  {
1953  *pp = (*pp)->Clone();
1954  (*pp)->IncRef();
1955  }
1956  }
1957  if( nRPN )
1958  {
1959  pp = p->pRPN = new FormulaToken*[ nRPN ];
1960  memcpy( pp, pRPN, nRPN * sizeof( formula::FormulaToken* ) );
1961  for( sal_uInt16 i = 0; i < nRPN; i++, pp++ )
1962  {
1963  FormulaToken* t = *pp;
1964  if( t->GetRef() > 1 )
1965  {
1966  FormulaToken** p2 = pCode.get();
1967  sal_uInt16 nIdx = 0xFFFF;
1968  for( sal_uInt16 j = 0; j < nLen; j++, p2++ )
1969  {
1970  if( *p2 == t )
1971  {
1972  nIdx = j; break;
1973  }
1974  }
1975  if( nIdx == 0xFFFF )
1976  *pp = t->Clone();
1977  else
1978  *pp = p->pCode[ nIdx ];
1979  }
1980  else
1981  *pp = t->Clone();
1982  (*pp)->IncRef();
1983  }
1984  }
1985  return p;
1986 }
1987 
1989 {
1990  ScTokenArray aNew(*mxSheetLimits);
1991  aNew.nLen = nLen;
1992  aNew.nRPN = nRPN;
1993  aNew.nMode = nMode;
1994  aNew.nError = nError;
1995  aNew.bHyperLink = bHyperLink;
1996  aNew.mnHashValue = mnHashValue;
2001  aNew.mbShareable = mbShareable;
2002 
2003  FormulaToken** pp;
2004  if( nLen )
2005  {
2006  aNew.pCode.reset(new FormulaToken*[ nLen ]);
2007  pp = aNew.pCode.get();
2008  memcpy( pp, pCode.get(), nLen * sizeof( formula::FormulaToken* ) );
2009  for( sal_uInt16 i = 0; i < nLen; i++, pp++ )
2010  {
2011  *pp = (*pp)->Clone();
2012  (*pp)->IncRef();
2013  }
2014  }
2015  if( nRPN )
2016  {
2017  pp = aNew.pRPN = new FormulaToken*[ nRPN ];
2018  memcpy( pp, pRPN, nRPN * sizeof( formula::FormulaToken* ) );
2019  for( sal_uInt16 i = 0; i < nRPN; i++, pp++ )
2020  {
2021  FormulaToken* t = *pp;
2022  if( t->GetRef() > 1 )
2023  {
2024  FormulaToken** p2 = pCode.get();
2025  sal_uInt16 nIdx = 0xFFFF;
2026  for( sal_uInt16 j = 0; j < nLen; j++, p2++ )
2027  {
2028  if( *p2 == t )
2029  {
2030  nIdx = j; break;
2031  }
2032  }
2033  if( nIdx == 0xFFFF )
2034  *pp = t->Clone();
2035  else
2036  *pp = aNew.pCode[ nIdx ];
2037  }
2038  else
2039  *pp = t->Clone();
2040  (*pp)->IncRef();
2041  }
2042  }
2043  return aNew;
2044 }
2045 
2047 {
2048  return Add( r.CreateToken(*mxSheetLimits) );
2049 }
2050 
2051 // Utility function to ensure that there is strict alternation of values and
2052 // separators.
2053 static bool
2054 checkArraySep( bool & bPrevWasSep, bool bNewVal )
2055 {
2056  bool bResult = (bPrevWasSep == bNewVal);
2057  bPrevWasSep = bNewVal;
2058  return bResult;
2059 }
2060 
2062 {
2063  int nCol = -1, nRow = 0;
2064  int i, nPrevRowSep = -1, nStart = 0;
2065  bool bPrevWasSep = false; // top of stack is ocArrayClose
2066  FormulaToken* t;
2067  bool bNumeric = false; // numeric value encountered in current element
2068 
2069  // (1) Iterate from the end to the start to find matrix dims
2070  // and do basic validation.
2071  for ( i = nLen ; i-- > nStart ; )
2072  {
2073  t = pCode[i];
2074  switch ( t->GetOpCode() )
2075  {
2076  case ocPush :
2077  if( checkArraySep( bPrevWasSep, false ) )
2078  {
2079  return nullptr;
2080  }
2081 
2082  // no references or nested arrays
2083  if ( t->GetType() != svDouble && t->GetType() != svString )
2084  {
2085  return nullptr;
2086  }
2087  bNumeric = (t->GetType() == svDouble);
2088  break;
2089 
2090  case ocMissing :
2091  case ocTrue :
2092  case ocFalse :
2093  if( checkArraySep( bPrevWasSep, false ) )
2094  {
2095  return nullptr;
2096  }
2097  bNumeric = false;
2098  break;
2099 
2100  case ocArrayColSep :
2101  case ocSep :
2102  if( checkArraySep( bPrevWasSep, true ) )
2103  {
2104  return nullptr;
2105  }
2106  bNumeric = false;
2107  break;
2108 
2109  case ocArrayClose :
2110  // not possible with the , but check just in case
2111  // something changes in the future
2112  if( i != (nLen-1))
2113  {
2114  return nullptr;
2115  }
2116 
2117  if( checkArraySep( bPrevWasSep, true ) )
2118  {
2119  return nullptr;
2120  }
2121 
2122  nPrevRowSep = i;
2123  bNumeric = false;
2124  break;
2125 
2126  case ocArrayOpen :
2127  nStart = i; // stop iteration
2128  [[fallthrough]]; // to ArrayRowSep
2129 
2130  case ocArrayRowSep :
2131  if( checkArraySep( bPrevWasSep, true ) )
2132  {
2133  return nullptr;
2134  }
2135 
2136  if( nPrevRowSep < 0 || // missing ocArrayClose
2137  ((nPrevRowSep - i) % 2) == 1) // no complex elements
2138  {
2139  return nullptr;
2140  }
2141 
2142  if( nCol < 0 )
2143  {
2144  nCol = (nPrevRowSep - i) / 2;
2145  }
2146  else if( (nPrevRowSep - i)/2 != nCol) // irregular array
2147  {
2148  return nullptr;
2149  }
2150 
2151  nPrevRowSep = i;
2152  nRow++;
2153  bNumeric = false;
2154  break;
2155 
2156  case ocNegSub :
2157  case ocAdd :
2158  // negation or unary plus must precede numeric value
2159  if( !bNumeric )
2160  {
2161  return nullptr;
2162  }
2163  --nPrevRowSep; // shorten this row by 1
2164  bNumeric = false; // one level only, no --42
2165  break;
2166 
2167  case ocSpaces :
2168  case ocWhitespace :
2169  // ignore spaces
2170  --nPrevRowSep; // shorten this row by 1
2171  break;
2172 
2173  default :
2174  // no functions or operators
2175  return nullptr;
2176  }
2177  }
2178  if( nCol <= 0 || nRow <= 0 )
2179  return nullptr;
2180 
2181  int nSign = 1;
2182  ScMatrix* pArray = new ScMatrix(nCol, nRow, 0.0);
2183  for ( i = nStart, nCol = 0, nRow = 0 ; i < nLen ; i++ )
2184  {
2185  t = pCode[i];
2186 
2187  switch ( t->GetOpCode() )
2188  {
2189  case ocPush :
2190  if ( t->GetType() == svDouble )
2191  {
2192  pArray->PutDouble( t->GetDouble() * nSign, nCol, nRow );
2193  nSign = 1;
2194  }
2195  else if ( t->GetType() == svString )
2196  {
2197  pArray->PutString(t->GetString(), nCol, nRow);
2198  }
2199  break;
2200 
2201  case ocMissing :
2202  pArray->PutEmpty( nCol, nRow );
2203  break;
2204 
2205  case ocTrue :
2206  pArray->PutBoolean( true, nCol, nRow );
2207  break;
2208 
2209  case ocFalse :
2210  pArray->PutBoolean( false, nCol, nRow );
2211  break;
2212 
2213  case ocArrayColSep :
2214  case ocSep :
2215  nCol++;
2216  break;
2217 
2218  case ocArrayRowSep :
2219  nRow++; nCol = 0;
2220  break;
2221 
2222  case ocNegSub :
2223  nSign = -nSign;
2224  break;
2225 
2226  default :
2227  break;
2228  }
2229  pCode[i] = nullptr;
2230  t->DecRef();
2231  }
2232  nLen = sal_uInt16( nStart );
2233  return AddMatrix( pArray );
2234 }
2235 
2237 {
2238  if (!pCode || !nLen)
2239  return;
2240  sal_uInt16 nIdx = nLen;
2241 
2242  // The actual types are checked in extendRangeReference().
2243  FormulaToken *p3 = PeekPrev(nIdx); // ref
2244  if (!p3)
2245  return;
2246  FormulaToken *p2 = PeekPrev(nIdx); // ocRange
2247  if (!p2 || p2->GetOpCode() != ocRange)
2248  return;
2249  FormulaToken *p1 = PeekPrev(nIdx); // ref
2250  if (!p1)
2251  return;
2252  FormulaTokenRef p = extendRangeReference( *mxSheetLimits, *p1, *p3, rPos, true);
2253  if (p)
2254  {
2255  p->IncRef();
2256  p1->DecRef();
2257  p2->DecRef();
2258  p3->DecRef();
2259  nLen -= 2;
2260  pCode[ nLen-1 ] = p.get();
2261  }
2262 }
2263 
2265 {
2266  ScRawToken t;
2267  t.SetOpCode( e );
2268  return AddRawToken( t );
2269 }
2270 
2272 {
2273  return Add( new ScSingleRefToken( *mxSheetLimits, rRef ) );
2274 }
2275 
2277 {
2278  return Add( new ScSingleRefToken(*mxSheetLimits, rRef, ocMatRef ) );
2279 }
2280 
2282 {
2283  return Add( new ScDoubleRefToken(*mxSheetLimits, rRef ) );
2284 }
2285 
2287 {
2288  return Add( new ScMatrixToken( p ) );
2289 }
2290 
2291 void ScTokenArray::AddRangeName( sal_uInt16 n, sal_Int16 nSheet )
2292 {
2293  Add( new FormulaIndexToken( ocName, n, nSheet));
2294 }
2295 
2297 {
2298  return Add( new FormulaIndexToken( ocDBArea, n));
2299 }
2300 
2302 {
2303  return Add( new ScExternalNameToken(nFileId, rName) );
2304 }
2305 
2306 void ScTokenArray::AddExternalSingleReference( sal_uInt16 nFileId, const svl::SharedString& rTabName,
2307  const ScSingleRefData& rRef )
2308 {
2309  Add( new ScExternalSingleRefToken(nFileId, rTabName, rRef) );
2310 }
2311 
2313  const ScComplexRefData& rRef )
2314 {
2315  return Add( new ScExternalDoubleRefToken(nFileId, rTabName, rRef) );
2316 }
2317 
2319 {
2320  return Add( new ScSingleRefToken(*mxSheetLimits, rRef, ocColRowName ) );
2321 }
2322 
2323 void ScTokenArray::AssignXMLString( const OUString &rText, const OUString &rFormulaNmsp )
2324 {
2325  sal_uInt16 nTokens = 1;
2326  FormulaToken *aTokens[2];
2327 
2328  aTokens[0] = new FormulaStringOpToken( ocStringXML, svl::SharedString( rText) ); // string not interned
2329  if( !rFormulaNmsp.isEmpty() )
2330  aTokens[ nTokens++ ] = new FormulaStringOpToken( ocStringXML,
2331  svl::SharedString( rFormulaNmsp) ); // string not interned
2332 
2333  Assign( nTokens, aTokens );
2334 }
2335 
2337  const ScAddress& rPos, ScDirection eDir )
2338 {
2339  SCCOL nCol = 0;
2340  SCROW nRow = 0;
2341  switch ( eDir )
2342  {
2343  case DIR_BOTTOM :
2344  if ( rPos.Row() >= mxSheetLimits->mnMaxRow )
2345  return false;
2346  nExtend = rPos.Row();
2347  nRow = nExtend + 1;
2348  break;
2349  case DIR_RIGHT :
2350  if ( rPos.Col() >= mxSheetLimits->mnMaxCol )
2351  return false;
2352  nExtend = rPos.Col();
2353  nCol = static_cast<SCCOL>(nExtend) + 1;
2354  break;
2355  case DIR_TOP :
2356  if ( rPos.Row() <= 0 )
2357  return false;
2358  nExtend = rPos.Row();
2359  nRow = nExtend - 1;
2360  break;
2361  case DIR_LEFT :
2362  if ( rPos.Col() <= 0 )
2363  return false;
2364  nExtend = rPos.Col();
2365  nCol = static_cast<SCCOL>(nExtend) - 1;
2366  break;
2367  default:
2368  OSL_FAIL( "unknown Direction" );
2369  return false;
2370  }
2371  if ( pRPN && nRPN )
2372  {
2373  FormulaToken* t = pRPN[nRPN-1];
2374  if ( t->GetType() == svByte )
2375  {
2376  sal_uInt8 nParamCount = t->GetByte();
2377  if ( nParamCount && nRPN > nParamCount )
2378  {
2379  bool bRet = false;
2380  sal_uInt16 nParam = nRPN - nParamCount - 1;
2381  for ( ; nParam < nRPN-1; nParam++ )
2382  {
2383  FormulaToken* p = pRPN[nParam];
2384  switch ( p->GetType() )
2385  {
2386  case svSingleRef :
2387  {
2388  ScSingleRefData& rRef = *p->GetSingleRef();
2389  ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rPos);
2390  switch ( eDir )
2391  {
2392  case DIR_BOTTOM :
2393  if (aAbs.Row() == nRow && aAbs.Row() > nExtend)
2394  {
2395  nExtend = aAbs.Row();
2396  bRet = true;
2397  }
2398  break;
2399  case DIR_RIGHT :
2400  if (aAbs.Col() == nCol && static_cast<SCCOLROW>(aAbs.Col()) > nExtend)
2401  {
2402  nExtend = aAbs.Col();
2403  bRet = true;
2404  }
2405  break;
2406  case DIR_TOP :
2407  if (aAbs.Row() == nRow && aAbs.Row() < nExtend)
2408  {
2409  nExtend = aAbs.Row();
2410  bRet = true;
2411  }
2412  break;
2413  case DIR_LEFT :
2414  if (aAbs.Col() == nCol && static_cast<SCCOLROW>(aAbs.Col()) < nExtend)
2415  {
2416  nExtend = aAbs.Col();
2417  bRet = true;
2418  }
2419  break;
2420  }
2421  }
2422  break;
2423  case svDoubleRef :
2424  {
2425  ScComplexRefData& rRef = *p->GetDoubleRef();
2426  ScRange aAbs = rRef.toAbs(*mxSheetLimits, rPos);
2427  switch ( eDir )
2428  {
2429  case DIR_BOTTOM :
2430  if (aAbs.aStart.Row() == nRow && aAbs.aEnd.Row() > nExtend)
2431  {
2432  nExtend = aAbs.aEnd.Row();
2433  bRet = true;
2434  }
2435  break;
2436  case DIR_RIGHT :
2437  if (aAbs.aStart.Col() == nCol && static_cast<SCCOLROW>(aAbs.aEnd.Col()) > nExtend)
2438  {
2439  nExtend = aAbs.aEnd.Col();
2440  bRet = true;
2441  }
2442  break;
2443  case DIR_TOP :
2444  if (aAbs.aEnd.Row() == nRow && aAbs.aStart.Row() < nExtend)
2445  {
2446  nExtend = aAbs.aStart.Row();
2447  bRet = true;
2448  }
2449  break;
2450  case DIR_LEFT :
2451  if (aAbs.aEnd.Col() == nCol && static_cast<SCCOLROW>(aAbs.aStart.Col()) < nExtend)
2452  {
2453  nExtend = aAbs.aStart.Col();
2454  bRet = true;
2455  }
2456  break;
2457  }
2458  }
2459  break;
2460  default:
2461  {
2462  // added to avoid warnings
2463  }
2464  } // switch
2465  } // for
2466  return bRet;
2467  }
2468  }
2469  }
2470  return false;
2471 }
2472 
2473 namespace {
2474 
2475 void GetExternalTableData(const ScDocument* pOldDoc, const ScDocument* pNewDoc, const SCTAB nTab, OUString& rTabName, sal_uInt16& rFileId)
2476 {
2477  const OUString& aFileName = pOldDoc->GetFileURL();
2478  rFileId = pNewDoc->GetExternalRefManager()->getExternalFileId(aFileName);
2479  rTabName = pOldDoc->GetCopyTabName(nTab);
2480  if (rTabName.isEmpty())
2481  pOldDoc->GetName(nTab, rTabName);
2482 }
2483 
2484 bool IsInCopyRange( const ScRange& rRange, const ScDocument* pClipDoc )
2485 {
2486  ScClipParam& rClipParam = const_cast<ScDocument*>(pClipDoc)->GetClipParam();
2487  return rClipParam.maRanges.In(rRange);
2488 }
2489 
2490 bool SkipReference(formula::FormulaToken* pToken, const ScAddress& rPos, const ScDocument& rOldDoc, bool bRangeName, bool bCheckCopyArea)
2491 {
2492  ScRange aRange;
2493 
2494  if (!ScRefTokenHelper::getRangeFromToken(&rOldDoc, aRange, pToken, rPos))
2495  return true;
2496 
2497  if (bRangeName && aRange.aStart.Tab() == rPos.Tab())
2498  {
2499  switch (pToken->GetType())
2500  {
2501  case svDoubleRef:
2502  {
2503  ScSingleRefData& rRef = *pToken->GetSingleRef2();
2504  if (rRef.IsColRel() || rRef.IsRowRel())
2505  return true;
2506  }
2507  [[fallthrough]];
2508  case svSingleRef:
2509  {
2510  ScSingleRefData& rRef = *pToken->GetSingleRef();
2511  if (rRef.IsColRel() || rRef.IsRowRel())
2512  return true;
2513  }
2514  break;
2515  default:
2516  break;
2517  }
2518  }
2519 
2520  if (bCheckCopyArea && IsInCopyRange(aRange, &rOldDoc))
2521  return true;
2522 
2523  return false;
2524 }
2525 
2526 void AdjustSingleRefData( ScSingleRefData& rRef, const ScAddress& rOldPos, const ScAddress& rNewPos)
2527 {
2528  SCCOL nCols = rNewPos.Col() - rOldPos.Col();
2529  SCROW nRows = rNewPos.Row() - rOldPos.Row();
2530  SCTAB nTabs = rNewPos.Tab() - rOldPos.Tab();
2531 
2532  if (!rRef.IsColRel())
2533  rRef.IncCol(nCols);
2534 
2535  if (!rRef.IsRowRel())
2536  rRef.IncRow(nRows);
2537 
2538  if (!rRef.IsTabRel())
2539  rRef.IncTab(nTabs);
2540 }
2541 
2542 }
2543 
2544 void ScTokenArray::ReadjustAbsolute3DReferences( const ScDocument& rOldDoc, ScDocument& rNewDoc, const ScAddress& rPos, bool bRangeName )
2545 {
2546  for ( sal_uInt16 j=0; j<nLen; ++j )
2547  {
2548  switch ( pCode[j]->GetType() )
2549  {
2550  case svDoubleRef :
2551  {
2552  if (SkipReference(pCode[j], rPos, rOldDoc, bRangeName, true))
2553  continue;
2554 
2555  ScComplexRefData& rRef = *pCode[j]->GetDoubleRef();
2556  ScSingleRefData& rRef2 = rRef.Ref2;
2557  ScSingleRefData& rRef1 = rRef.Ref1;
2558 
2559  if ( (rRef2.IsFlag3D() && !rRef2.IsTabRel()) || (rRef1.IsFlag3D() && !rRef1.IsTabRel()) )
2560  {
2561  OUString aTabName;
2562  sal_uInt16 nFileId;
2563  GetExternalTableData(&rOldDoc, &rNewDoc, rRef1.Tab(), aTabName, nFileId);
2564  ReplaceToken( j, new ScExternalDoubleRefToken( nFileId,
2565  rNewDoc.GetSharedStringPool().intern( aTabName), rRef), CODE_AND_RPN);
2566  // ATTENTION: rRef can't be used after this point
2567  }
2568  }
2569  break;
2570  case svSingleRef :
2571  {
2572  if (SkipReference(pCode[j], rPos, rOldDoc, bRangeName, true))
2573  continue;
2574 
2575  ScSingleRefData& rRef = *pCode[j]->GetSingleRef();
2576 
2577  if ( rRef.IsFlag3D() && !rRef.IsTabRel() )
2578  {
2579  OUString aTabName;
2580  sal_uInt16 nFileId;
2581  GetExternalTableData(&rOldDoc, &rNewDoc, rRef.Tab(), aTabName, nFileId);
2582  ReplaceToken( j, new ScExternalSingleRefToken( nFileId,
2583  rNewDoc.GetSharedStringPool().intern( aTabName), rRef), CODE_AND_RPN);
2584  // ATTENTION: rRef can't be used after this point
2585  }
2586  }
2587  break;
2588  default:
2589  {
2590  // added to avoid warnings
2591  }
2592  }
2593  }
2594 }
2595 
2596 void ScTokenArray::AdjustAbsoluteRefs( const ScDocument& rOldDoc, const ScAddress& rOldPos, const ScAddress& rNewPos,
2597  bool bCheckCopyRange)
2598 {
2599  TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN, true);
2600  for (size_t j=0; j<2; ++j)
2601  {
2602  FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
2603  FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
2604  for (; pp != pEnd; ++pp)
2605  {
2606  FormulaToken* p = aPtrs.getHandledToken(j,pp);
2607  if (!p)
2608  continue;
2609 
2610  switch ( p->GetType() )
2611  {
2612  case svDoubleRef :
2613  {
2614  if (!SkipReference(p, rOldPos, rOldDoc, false, bCheckCopyRange))
2615  continue;
2616 
2617  ScComplexRefData& rRef = *p->GetDoubleRef();
2618  ScSingleRefData& rRef2 = rRef.Ref2;
2619  ScSingleRefData& rRef1 = rRef.Ref1;
2620 
2621  AdjustSingleRefData( rRef1, rOldPos, rNewPos );
2622  AdjustSingleRefData( rRef2, rOldPos, rNewPos );
2623  }
2624  break;
2625  case svSingleRef :
2626  {
2627  if (!SkipReference(p, rOldPos, rOldDoc, false, bCheckCopyRange))
2628  continue;
2629 
2630  ScSingleRefData& rRef = *p->GetSingleRef();
2631 
2632  AdjustSingleRefData( rRef, rOldPos, rNewPos );
2633  }
2634  break;
2635  default:
2636  {
2637  // added to avoid warnings
2638  }
2639  }
2640  }
2641  }
2642 }
2643 
2645 {
2646  TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN, false);
2647  for (size_t j=0; j<2; ++j)
2648  {
2649  FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
2650  FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
2651  for (; pp != pEnd; ++pp)
2652  {
2653  FormulaToken* p = aPtrs.getHandledToken(j,pp);
2654  if (!p)
2655  continue;
2656 
2657  switch ( p->GetType() )
2658  {
2659  case svDoubleRef :
2660  {
2661  ScComplexRefData& rRef = *p->GetDoubleRef();
2662  ScSingleRefData& rRef2 = rRef.Ref2;
2663  ScSingleRefData& rRef1 = rRef.Ref1;
2664 
2665  if (!rRef1.IsTabRel() && rRef1.Tab() == nOldTab)
2666  rRef1.SetAbsTab( nNewTab);
2667  if (!rRef2.IsTabRel() && rRef2.Tab() == nOldTab)
2668  rRef2.SetAbsTab( nNewTab);
2669  if (!rRef1.IsTabRel() && !rRef2.IsTabRel() && rRef1.Tab() > rRef2.Tab())
2670  {
2671  SCTAB nTab = rRef1.Tab();
2672  rRef1.SetAbsTab( rRef2.Tab());
2673  rRef2.SetAbsTab( nTab);
2674  }
2675  }
2676  break;
2677  case svSingleRef :
2678  {
2679  ScSingleRefData& rRef = *p->GetSingleRef();
2680 
2681  if (!rRef.IsTabRel() && rRef.Tab() == nOldTab)
2682  rRef.SetAbsTab( nNewTab);
2683  }
2684  break;
2685  default:
2686  ;
2687  }
2688  }
2689  }
2690 }
2691 
2692 bool ScTokenArray::ReferencesSheet( SCTAB nTab, SCTAB nPosTab ) const
2693 {
2694  TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN, false);
2695  for (size_t j=0; j<2; ++j)
2696  {
2697  FormulaToken* const * pp = aPtrs.maPointerRange[j].mpStart;
2698  FormulaToken* const * const pEnd = aPtrs.maPointerRange[j].mpStop;
2699  for (; pp != pEnd; ++pp)
2700  {
2701  const FormulaToken* p = aPtrs.getHandledToken(j,pp);
2702  if (!p)
2703  continue;
2704 
2705  switch ( p->GetType() )
2706  {
2707  case svDoubleRef :
2708  {
2709  const ScComplexRefData& rRef = *p->GetDoubleRef();
2710  const ScSingleRefData& rRef2 = rRef.Ref2;
2711  const ScSingleRefData& rRef1 = rRef.Ref1;
2712 
2713  SCTAB nTab1 = (rRef1.IsTabRel() ? rRef1.Tab() + nPosTab : rRef1.Tab());
2714  SCTAB nTab2 = (rRef2.IsTabRel() ? rRef2.Tab() + nPosTab : rRef2.Tab());
2715  if (nTab1 <= nTab && nTab <= nTab2)
2716  return true;
2717  }
2718  break;
2719  case svSingleRef :
2720  {
2721  const ScSingleRefData& rRef = *p->GetSingleRef();
2722  if (rRef.IsTabRel())
2723  {
2724  if (rRef.Tab() + nPosTab == nTab)
2725  return true;
2726  }
2727  else
2728  {
2729  if (rRef.Tab() == nTab)
2730  return true;
2731  }
2732  }
2733  break;
2734  default:
2735  ;
2736  }
2737  }
2738  }
2739  return false;
2740 }
2741 
2742 namespace {
2743 
2744 ScRange getSelectedRange( const sc::RefUpdateContext& rCxt )
2745 {
2746  ScRange aSelectedRange(ScAddress::INITIALIZE_INVALID);
2747  if (rCxt.mnColDelta < 0)
2748  {
2749  // Delete and shift to left.
2750  aSelectedRange.aStart = ScAddress(rCxt.maRange.aStart.Col()+rCxt.mnColDelta, rCxt.maRange.aStart.Row(), rCxt.maRange.aStart.Tab());
2751  aSelectedRange.aEnd = ScAddress(rCxt.maRange.aStart.Col()-1, rCxt.maRange.aEnd.Row(), rCxt.maRange.aEnd.Tab());
2752  }
2753  else if (rCxt.mnRowDelta < 0)
2754  {
2755  // Delete and shift up.
2756  aSelectedRange.aStart = ScAddress(rCxt.maRange.aStart.Col(), rCxt.maRange.aStart.Row()+rCxt.mnRowDelta, rCxt.maRange.aStart.Tab());
2757  aSelectedRange.aEnd = ScAddress(rCxt.maRange.aEnd.Col(), rCxt.maRange.aStart.Row()-1, rCxt.maRange.aEnd.Tab());
2758  }
2759  else if (rCxt.mnTabDelta < 0)
2760  {
2761  // Deleting sheets.
2762  // TODO : Figure out what to do here.
2763  }
2764  else if (rCxt.mnColDelta > 0)
2765  {
2766  // Insert and shift to the right.
2767  aSelectedRange.aStart = rCxt.maRange.aStart;
2768  aSelectedRange.aEnd = ScAddress(rCxt.maRange.aStart.Col()+rCxt.mnColDelta-1, rCxt.maRange.aEnd.Row(), rCxt.maRange.aEnd.Tab());
2769  }
2770  else if (rCxt.mnRowDelta > 0)
2771  {
2772  // Insert and shift down.
2773  aSelectedRange.aStart = rCxt.maRange.aStart;
2774  aSelectedRange.aEnd = ScAddress(rCxt.maRange.aEnd.Col(), rCxt.maRange.aStart.Row()+rCxt.mnRowDelta-1, rCxt.maRange.aEnd.Tab());
2775  }
2776  else if (rCxt.mnTabDelta > 0)
2777  {
2778  // Inserting sheets.
2779  // TODO : Figure out what to do here.
2780  }
2781 
2782  return aSelectedRange;
2783 }
2784 
2785 void setRefDeleted( ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt )
2786 {
2787  if (rCxt.mnColDelta < 0)
2788  rRef.SetColDeleted(true);
2789  else if (rCxt.mnRowDelta < 0)
2790  rRef.SetRowDeleted(true);
2791  else if (rCxt.mnTabDelta < 0)
2792  rRef.SetTabDeleted(true);
2793 }
2794 
2795 void restoreDeletedRef( ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt )
2796 {
2797  if (rCxt.mnColDelta)
2798  {
2799  if (rRef.IsColDeleted())
2800  rRef.SetColDeleted(false);
2801  }
2802  else if (rCxt.mnRowDelta)
2803  {
2804  if (rRef.IsRowDeleted())
2805  rRef.SetRowDeleted(false);
2806  }
2807  else if (rCxt.mnTabDelta)
2808  {
2809  if (rRef.IsTabDeleted())
2810  rRef.SetTabDeleted(false);
2811  }
2812 }
2813 
2814 void setRefDeleted( ScComplexRefData& rRef, const sc::RefUpdateContext& rCxt )
2815 {
2816  if (rCxt.mnColDelta < 0)
2817  {
2818  rRef.Ref1.SetColDeleted(true);
2819  rRef.Ref2.SetColDeleted(true);
2820  }
2821  else if (rCxt.mnRowDelta < 0)
2822  {
2823  rRef.Ref1.SetRowDeleted(true);
2824  rRef.Ref2.SetRowDeleted(true);
2825  }
2826  else if (rCxt.mnTabDelta < 0)
2827  {
2828  rRef.Ref1.SetTabDeleted(true);
2829  rRef.Ref2.SetTabDeleted(true);
2830  }
2831 }
2832 
2833 void restoreDeletedRef( ScComplexRefData& rRef, const sc::RefUpdateContext& rCxt )
2834 {
2835  restoreDeletedRef(rRef.Ref1, rCxt);
2836  restoreDeletedRef(rRef.Ref2, rCxt);
2837 }
2838 
2840 {
2841  UNMODIFIED,
2842  SHRUNK,
2843  STICKY
2844 };
2845 
2846 ShrinkResult shrinkRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const ScRange& rDeletedRange,
2847  const ScComplexRefData& rRef )
2848 {
2849  if (!rDeletedRange.Intersects(rRefRange))
2850  return UNMODIFIED;
2851 
2852  if (rCxt.mnColDelta < 0)
2853  {
2854  if (rRef.IsEntireRow())
2855  // Entire rows are not affected, columns are anchored.
2856  return STICKY;
2857 
2858  // Shifting left.
2859  if (rRefRange.aStart.Row() < rDeletedRange.aStart.Row() || rDeletedRange.aEnd.Row() < rRefRange.aEnd.Row())
2860  // Deleted range is only partially overlapping in vertical direction. Bail out.
2861  return UNMODIFIED;
2862 
2863  if (rDeletedRange.aStart.Col() <= rRefRange.aStart.Col())
2864  {
2865  if (rRefRange.aEnd.Col() <= rDeletedRange.aEnd.Col())
2866  {
2867  // Reference is entirely deleted.
2868  rRefRange.SetInvalid();
2869  }
2870  else
2871  {
2872  // The reference range is truncated on the left.
2873  SCCOL nOffset = rDeletedRange.aStart.Col() - rRefRange.aStart.Col();
2874  SCCOL nDelta = rRefRange.aStart.Col() - rDeletedRange.aEnd.Col() - 1;
2875  rRefRange.IncEndColSticky(rCxt.mrDoc, nDelta+nOffset);
2876  rRefRange.aStart.IncCol(nOffset);
2877  }
2878  }
2879  else if (rDeletedRange.aEnd.Col() < rRefRange.aEnd.Col())
2880  {
2881  if (rRefRange.IsEndColSticky())
2882  // Sticky end not affected.
2883  return STICKY;
2884 
2885  // Reference is deleted in the middle. Move the last column
2886  // position to the left.
2887  SCCOL nDelta = rDeletedRange.aStart.Col() - rDeletedRange.aEnd.Col() - 1;
2888  rRefRange.IncEndColSticky(rCxt.mrDoc, nDelta);
2889  }
2890  else
2891  {
2892  if (rRefRange.IsEndColSticky())
2893  // Sticky end not affected.
2894  return STICKY;
2895 
2896  // The reference range is truncated on the right.
2897  SCCOL nDelta = rDeletedRange.aStart.Col() - rRefRange.aEnd.Col() - 1;
2898  rRefRange.IncEndColSticky(rCxt.mrDoc, nDelta);
2899  }
2900  return SHRUNK;
2901  }
2902  else if (rCxt.mnRowDelta < 0)
2903  {
2904  if (rRef.IsEntireCol())
2905  // Entire columns are not affected, rows are anchored.
2906  return STICKY;
2907 
2908  // Shifting up.
2909 
2910  if (rRefRange.aStart.Col() < rDeletedRange.aStart.Col() || rDeletedRange.aEnd.Col() < rRefRange.aEnd.Col())
2911  // Deleted range is only partially overlapping in horizontal direction. Bail out.
2912  return UNMODIFIED;
2913 
2914  if (rDeletedRange.aStart.Row() <= rRefRange.aStart.Row())
2915  {
2916  if (rRefRange.aEnd.Row() <= rDeletedRange.aEnd.Row())
2917  {
2918  // Reference is entirely deleted.
2919  rRefRange.SetInvalid();
2920  }
2921  else
2922  {
2923  // The reference range is truncated on the top.
2924  SCROW nOffset = rDeletedRange.aStart.Row() - rRefRange.aStart.Row();
2925  SCROW nDelta = rRefRange.aStart.Row() - rDeletedRange.aEnd.Row() - 1;
2926  rRefRange.IncEndRowSticky(rCxt.mrDoc, nDelta+nOffset);
2927  rRefRange.aStart.IncRow(nOffset);
2928  }
2929  }
2930  else if (rDeletedRange.aEnd.Row() < rRefRange.aEnd.Row())
2931  {
2932  if (rRefRange.IsEndRowSticky())
2933  // Sticky end not affected.
2934  return STICKY;
2935 
2936  // Reference is deleted in the middle. Move the last row
2937  // position upward.
2938  SCROW nDelta = rDeletedRange.aStart.Row() - rDeletedRange.aEnd.Row() - 1;
2939  rRefRange.IncEndRowSticky(rCxt.mrDoc, nDelta);
2940  }
2941  else
2942  {
2943  if (rRefRange.IsEndRowSticky())
2944  // Sticky end not affected.
2945  return STICKY;
2946 
2947  // The reference range is truncated on the bottom.
2948  SCROW nDelta = rDeletedRange.aStart.Row() - rRefRange.aEnd.Row() - 1;
2949  rRefRange.IncEndRowSticky(rCxt.mrDoc, nDelta);
2950  }
2951  return SHRUNK;
2952  }
2953 
2954  return UNMODIFIED;
2955 }
2956 
2957 bool expandRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const ScRange& rSelectedRange,
2958  const ScComplexRefData& rRef )
2959 {
2960  if (!rSelectedRange.Intersects(rRefRange))
2961  return false;
2962 
2963  if (rCxt.mnColDelta > 0)
2964  {
2965  if (rRef.IsEntireRow())
2966  // Entire rows are not affected, columns are anchored.
2967  return false;
2968 
2969  // Insert and shifting right.
2970  if (rRefRange.aStart.Row() < rSelectedRange.aStart.Row() || rSelectedRange.aEnd.Row() < rRefRange.aEnd.Row())
2971  // Selected range is only partially overlapping in vertical direction. Bail out.
2972  return false;
2973 
2974  if (rCxt.mrDoc.IsExpandRefs())
2975  {
2976  if (rRefRange.aEnd.Col() - rRefRange.aStart.Col() < 1)
2977  // Reference must be at least two columns wide.
2978  return false;
2979  }
2980  else
2981  {
2982  if (rSelectedRange.aStart.Col() <= rRefRange.aStart.Col())
2983  // Selected range is at the left end and the edge expansion is turned off. No expansion.
2984  return false;
2985  }
2986 
2987  if (rRefRange.IsEndColSticky())
2988  // Sticky end not affected.
2989  return false;
2990 
2991  // Move the last column position to the right.
2992  SCCOL nDelta = rSelectedRange.aEnd.Col() - rSelectedRange.aStart.Col() + 1;
2993  rRefRange.IncEndColSticky(rCxt.mrDoc, nDelta);
2994  return true;
2995  }
2996  else if (rCxt.mnRowDelta > 0)
2997  {
2998  if (rRef.IsEntireCol())
2999  // Entire columns are not affected, rows are anchored.
3000  return false;
3001 
3002  // Insert and shifting down.
3003  if (rRefRange.aStart.Col() < rSelectedRange.aStart.Col() || rSelectedRange.aEnd.Col() < rRefRange.aEnd.Col())
3004  // Selected range is only partially overlapping in horizontal direction. Bail out.
3005  return false;
3006 
3007  if (rCxt.mrDoc.IsExpandRefs())
3008  {
3009  if (rRefRange.aEnd.Row() - rRefRange.aStart.Row() < 1)
3010  // Reference must be at least two rows tall.
3011  return false;
3012  }
3013  else
3014  {
3015  if (rSelectedRange.aStart.Row() <= rRefRange.aStart.Row())
3016  // Selected range is at the top end and the edge expansion is turned off. No expansion.
3017  return false;
3018  }
3019 
3020  if (rRefRange.IsEndRowSticky())
3021  // Sticky end not affected.
3022  return false;
3023 
3024  // Move the last row position down.
3025  SCROW nDelta = rSelectedRange.aEnd.Row() - rSelectedRange.aStart.Row() + 1;
3026  rRefRange.IncEndRowSticky(rCxt.mrDoc, nDelta);
3027  return true;
3028  }
3029  return false;
3030 }
3031 
3036 bool expandRangeByEdge( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const ScRange& rSelectedRange,
3037  const ScComplexRefData& rRef )
3038 {
3039  if (!rCxt.mrDoc.IsExpandRefs())
3040  // Edge-expansion is turned off.
3041  return false;
3042 
3043  if (rSelectedRange.aStart.Tab() > rRefRange.aStart.Tab() || rRefRange.aEnd.Tab() > rSelectedRange.aEnd.Tab())
3044  // Sheet references not within selected range.
3045  return false;
3046 
3047  if (rCxt.mnColDelta > 0)
3048  {
3049  if (rRef.IsEntireRow())
3050  // Entire rows are not affected, columns are anchored.
3051  return false;
3052 
3053  // Insert and shift right.
3054 
3055  if (rRefRange.aEnd.Col() - rRefRange.aStart.Col() < 1)
3056  // Reference must be at least two columns wide.
3057  return false;
3058 
3059  if (rRefRange.aStart.Row() < rSelectedRange.aStart.Row() || rSelectedRange.aEnd.Row() < rRefRange.aEnd.Row())
3060  // Selected range is only partially overlapping in vertical direction. Bail out.
3061  return false;
3062 
3063  if (rSelectedRange.aStart.Col() - rRefRange.aEnd.Col() != 1)
3064  // Selected range is not immediately adjacent. Bail out.
3065  return false;
3066 
3067  if (rRefRange.IsEndColSticky())
3068  // Sticky end not affected.
3069  return false;
3070 
3071  // Move the last column position to the right.
3072  SCCOL nDelta = rSelectedRange.aEnd.Col() - rSelectedRange.aStart.Col() + 1;
3073  rRefRange.IncEndColSticky(rCxt.mrDoc, nDelta);
3074  return true;
3075  }
3076  else if (rCxt.mnRowDelta > 0)
3077  {
3078  if (rRef.IsEntireCol())
3079  // Entire columns are not affected, rows are anchored.
3080  return false;
3081 
3082  if (rRefRange.aEnd.Row() - rRefRange.aStart.Row() < 1)
3083  // Reference must be at least two rows tall.
3084  return false;
3085 
3086  if (rRefRange.aStart.Col() < rSelectedRange.aStart.Col() || rSelectedRange.aEnd.Col() < rRefRange.aEnd.Col())
3087  // Selected range is only partially overlapping in horizontal direction. Bail out.
3088  return false;
3089 
3090  if (rSelectedRange.aStart.Row() - rRefRange.aEnd.Row() != 1)
3091  // Selected range is not immediately adjacent. Bail out.
3092  return false;
3093 
3094  if (rRefRange.IsEndRowSticky())
3095  // Sticky end not affected.
3096  return false;
3097 
3098  // Move the last row position down.
3099  SCROW nDelta = rSelectedRange.aEnd.Row() - rSelectedRange.aStart.Row() + 1;
3100  rRefRange.IncEndRowSticky(rCxt.mrDoc, nDelta);
3101  return true;
3102  }
3103 
3104  return false;
3105 }
3106 
3107 bool isNameModified( const sc::UpdatedRangeNames& rUpdatedNames, SCTAB nOldTab, const formula::FormulaToken& rToken )
3108 {
3109  SCTAB nTab = -1;
3110  if (rToken.GetSheet() >= 0)
3111  nTab = nOldTab;
3112 
3113  // Check if this named expression has been modified.
3114  return rUpdatedNames.isNameUpdated(nTab, rToken.GetIndex());
3115 }
3116 
3117 bool isDBDataModified( const ScDocument& rDoc, const formula::FormulaToken& rToken )
3118 {
3119  // Check if this DBData has been modified.
3120  const ScDBData* pDBData = rDoc.GetDBCollection()->getNamedDBs().findByIndex( rToken.GetIndex());
3121  if (!pDBData)
3122  return true;
3123 
3124  return pDBData->IsModified();
3125 }
3126 
3127 }
3128 
3130 {
3131  ScRange aSelectedRange = getSelectedRange(rCxt);
3132 
3133  sc::RefUpdateResult aRes;
3134  ScAddress aNewPos = rOldPos;
3135  bool bCellShifted = rCxt.maRange.In(rOldPos);
3136  if (bCellShifted)
3137  {
3138  ScAddress aErrorPos( ScAddress::UNINITIALIZED );
3139  if (!aNewPos.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos))
3140  {
3141  assert(!"can't move");
3142  }
3143  }
3144 
3145  TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
3146  for (size_t j=0; j<2; ++j)
3147  {
3148  FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
3149  FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
3150  for (; pp != pEnd; ++pp)
3151  {
3152  FormulaToken* p = aPtrs.getHandledToken(j,pp);
3153  if (!p)
3154  continue;
3155 
3156  switch (p->GetType())
3157  {
3158  case svSingleRef:
3159  {
3160  ScSingleRefData& rRef = *p->GetSingleRef();
3161  ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3162 
3163  if (rCxt.isDeleted() && aSelectedRange.In(aAbs))
3164  {
3165  // This reference is in the deleted region.
3166  setRefDeleted(rRef, rCxt);
3167  aRes.mbValueChanged = true;
3168  break;
3169  }
3170 
3171  if (!rCxt.isDeleted() && rRef.IsDeleted())
3172  {
3173  // Check if the token has reference to previously deleted region.
3174  ScAddress aCheckPos = rRef.toAbs(*mxSheetLimits, aNewPos);
3175  if (rCxt.maRange.In(aCheckPos))
3176  {
3177  restoreDeletedRef(rRef, rCxt);
3178  aRes.mbValueChanged = true;
3179  break;
3180  }
3181  }
3182 
3183  if (rCxt.maRange.In(aAbs))
3184  {
3185  ScAddress aErrorPos( ScAddress::UNINITIALIZED );
3186  if (!aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos))
3187  aAbs = aErrorPos;
3188  aRes.mbReferenceModified = true;
3189  }
3190 
3191  rRef.SetAddress(*mxSheetLimits, aAbs, aNewPos);
3192  }
3193  break;
3194  case svDoubleRef:
3195  {
3196  ScComplexRefData& rRef = *p->GetDoubleRef();
3197  ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3198 
3199  if (rCxt.isDeleted())
3200  {
3201  if (aSelectedRange.In(aAbs))
3202  {
3203  // This reference is in the deleted region.
3204  setRefDeleted(rRef, rCxt);
3205  aRes.mbValueChanged = true;
3206  break;
3207  }
3208  else if (aSelectedRange.Intersects(aAbs))
3209  {
3210  const ShrinkResult eSR = shrinkRange(rCxt, aAbs, aSelectedRange, rRef);
3211  if (eSR == SHRUNK)
3212  {
3213  // The reference range has been shrunk.
3214  rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
3215  aRes.mbValueChanged = true;
3216  aRes.mbReferenceModified = true;
3217  break;
3218  }
3219  else if (eSR == STICKY)
3220  {
3221  // The reference range stays the same but a
3222  // new (empty) cell range is shifted in and
3223  // may change the calculation result.
3224  aRes.mbValueChanged = true;
3225  // Sticky when intersecting the selected
3226  // range means also that the other
3227  // conditions below are not met,
3228  // specifically not the
3229  // if (rCxt.maRange.In(aAbs))
3230  // that is able to update the reference,
3231  // but aSelectedRange does not intersect
3232  // with rCxt.maRange so that can't happen
3233  // and we can bail out early without
3234  // updating the reference.
3235  break;
3236  }
3237  }
3238  }
3239 
3240  if (!rCxt.isDeleted() && rRef.IsDeleted())
3241  {
3242  // Check if the token has reference to previously deleted region.
3243  ScRange aCheckRange = rRef.toAbs(*mxSheetLimits, aNewPos);
3244  if (aSelectedRange.In(aCheckRange))
3245  {
3246  // This reference was previously in the deleted region. Restore it.
3247  restoreDeletedRef(rRef, rCxt);
3248  aRes.mbValueChanged = true;
3249  break;
3250  }
3251  }
3252 
3253  if (rCxt.isInserted())
3254  {
3255  if (expandRange(rCxt, aAbs, aSelectedRange, rRef))
3256  {
3257  // The reference range has been expanded.
3258  rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
3259  aRes.mbValueChanged = true;
3260  aRes.mbReferenceModified = true;
3261  break;
3262  }
3263 
3264  if (expandRangeByEdge(rCxt, aAbs, aSelectedRange, rRef))
3265  {
3266  // The reference range has been expanded on the edge.
3267  rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
3268  aRes.mbValueChanged = true;
3269  aRes.mbReferenceModified = true;
3270  break;
3271  }
3272  }
3273 
3274  if (rCxt.maRange.In(aAbs))
3275  {
3276  // We shift either by column or by row, not both,
3277  // so moving the reference has only to be done in
3278  // the non-sticky case.
3279  if ((rCxt.mnRowDelta && rRef.IsEntireCol()) || (rCxt.mnColDelta && rRef.IsEntireRow()))
3280  {
3281  // In entire col/row, values are shifted within
3282  // the reference, which affects all positional
3283  // results like in MATCH or matrix positions.
3284  aRes.mbValueChanged = true;
3285  }
3286  else
3287  {
3288  ScRange aErrorRange( ScAddress::UNINITIALIZED );
3289  if (!aAbs.MoveSticky(rCxt.mrDoc, rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorRange))
3290  aAbs = aErrorRange;
3291  aRes.mbReferenceModified = true;
3292  }
3293  }
3294  else if (rCxt.maRange.Intersects(aAbs))
3295  {
3296  // Part of the referenced range is being shifted. This
3297  // will change the values of the range.
3298  aRes.mbValueChanged = true;
3299  }
3300 
3301  rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
3302  }
3303  break;
3304  case svExternalSingleRef:
3305  {
3306  // For external reference, just reset the reference with
3307  // respect to the new cell position.
3308  ScSingleRefData& rRef = *p->GetSingleRef();
3309  ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3310  rRef.SetAddress(*mxSheetLimits, aAbs, aNewPos);
3311  }
3312  break;
3313  case svExternalDoubleRef:
3314  {
3315  // Same as above.
3316  ScComplexRefData& rRef = *p->GetDoubleRef();
3317  ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3318  rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
3319  }
3320  break;
3321  default:
3322  ;
3323  }
3324 
3325  // For ocTableRef p is the inner token of *pp, so have a separate
3326  // condition here.
3327  if ((*pp)->GetType() == svIndex)
3328  {
3329  switch ((*pp)->GetOpCode())
3330  {
3331  case ocName:
3332  {
3333  SCTAB nOldTab = (*pp)->GetSheet();
3334  if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
3335  aRes.mbNameModified = true;
3336  if (rCxt.mnTabDelta &&
3337  rCxt.maRange.aStart.Tab() <= nOldTab && nOldTab <= rCxt.maRange.aEnd.Tab())
3338  {
3339  aRes.mbNameModified = true;
3340  (*pp)->SetSheet( nOldTab + rCxt.mnTabDelta);
3341  }
3342  }
3343  break;
3344  case ocDBArea:
3345  case ocTableRef:
3346  if (isDBDataModified(rCxt.mrDoc, **pp))
3347  aRes.mbNameModified = true;
3348  break;
3349  default:
3350  ; // nothing
3351  }
3352  }
3353  }
3354  }
3355 
3356  return aRes;
3357 }
3358 
3360  const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos, const ScAddress& rNewPos )
3361 {
3362  sc::RefUpdateResult aRes;
3363 
3364  if (!rCxt.mnColDelta && !rCxt.mnRowDelta && !rCxt.mnTabDelta)
3365  // The cell hasn't moved at all.
3366  return aRes;
3367 
3368  // When moving, the range in the context is the destination range. We need
3369  // to use the old range prior to the move for hit analysis.
3370  ScRange aOldRange = rCxt.maRange;
3371  ScRange aErrorMoveRange( ScAddress::UNINITIALIZED );
3372  if (!aOldRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta, aErrorMoveRange))
3373  {
3374  assert(!"can't move");
3375  }
3376 
3377  TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
3378  for (size_t j=0; j<2; ++j)
3379  {
3380  FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
3381  FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
3382  for (; pp != pEnd; ++pp)
3383  {
3384  FormulaToken* p = aPtrs.getHandledToken(j,pp);
3385  if (!p)
3386  continue;
3387 
3388  switch (p->GetType())
3389  {
3390  case svSingleRef:
3391  {
3392  ScSingleRefData& rRef = *p->GetSingleRef();
3393  ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3394 
3395  // Do not update the reference in transposed case (cut paste transposed).
3396  // The reference will be updated in UpdateTranspose().
3397  // Additionally, do not update the references from cells within the moved
3398  // range as they lead to #REF! errors here. These #REF! cannot by fixed
3399  // later in UpdateTranspose().
3400  if (rCxt.mbTransposed && (aOldRange.In(rOldPos) || aOldRange.In(aAbs)))
3401  break;
3402 
3403  if (aOldRange.In(aAbs))
3404  {
3405  ScAddress aErrorPos( ScAddress::UNINITIALIZED );
3406  if (!aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos))
3407  aAbs = aErrorPos;
3408  aRes.mbReferenceModified = true;
3409  }
3410  else if (rCxt.maRange.In(aAbs))
3411  {
3412  // Referenced cell has been overwritten.
3413  aRes.mbValueChanged = true;
3414  }
3415 
3416  rRef.SetAddress(*mxSheetLimits, aAbs, rNewPos);
3417  rRef.SetFlag3D(aAbs.Tab() != rNewPos.Tab() || !rRef.IsTabRel());
3418  }
3419  break;
3420  case svDoubleRef:
3421  {
3422  ScComplexRefData& rRef = *p->GetDoubleRef();
3423  ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3424 
3425  // Do not update the reference in transposed case (cut paste transposed).
3426  // The reference will be updated in UpdateTranspose().
3427  // Additionally, do not update the references from cells within the moved
3428  // range as they lead to #REF! errors here. These #REF! cannot by fixed
3429  // later in UpdateTranspose().
3430  if (rCxt.mbTransposed && (aOldRange.In(rOldPos) || aOldRange.In(aAbs)))
3431  break;
3432 
3433  if (aOldRange.In(aAbs))
3434  {
3435  ScRange aErrorRange( ScAddress::UNINITIALIZED );
3436  if (!aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorRange))
3437  aAbs = aErrorRange;
3438  aRes.mbReferenceModified = true;
3439  }
3440  else if (rCxt.maRange.In(aAbs))
3441  {
3442  // Referenced range has been entirely overwritten.
3443  aRes.mbValueChanged = true;
3444  }
3445 
3446  rRef.SetRange(*mxSheetLimits, aAbs, rNewPos);
3447  // Absolute sheet reference => set 3D flag.
3448  // More than one sheet referenced => has to have both 3D flags.
3449  // If end part has 3D flag => start part must have it too.
3450  rRef.Ref2.SetFlag3D(aAbs.aStart.Tab() != aAbs.aEnd.Tab() || !rRef.Ref2.IsTabRel());
3451  rRef.Ref1.SetFlag3D(aAbs.aStart.Tab() != rNewPos.Tab() || !rRef.Ref1.IsTabRel() ||
3452  rRef.Ref2.IsFlag3D());
3453  }
3454  break;
3455  case svExternalSingleRef:
3456  {
3457  ScSingleRefData& rRef = *p->GetSingleRef();
3458  ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3459  rRef.SetAddress(*mxSheetLimits, aAbs, rNewPos);
3460  }
3461  break;
3462  case svExternalDoubleRef:
3463  {
3464  ScComplexRefData& rRef = *p->GetDoubleRef();
3465  ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3466  rRef.SetRange(*mxSheetLimits, aAbs, rNewPos);
3467  }
3468  break;
3469  default:
3470  ;
3471  }
3472 
3473  // For ocTableRef p is the inner token of *pp, so have a separate
3474  // condition here.
3475  if ((*pp)->GetType() == svIndex)
3476  {
3477  switch ((*pp)->GetOpCode())
3478  {
3479  case ocName:
3480  {
3481  SCTAB nOldTab = (*pp)->GetSheet();
3482  if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
3483  aRes.mbNameModified = true;
3484  }
3485  break;
3486  case ocDBArea:
3487  case ocTableRef:
3488  if (isDBDataModified(rCxt.mrDoc, **pp))
3489  aRes.mbNameModified = true;
3490  break;
3491  default:
3492  ; // nothing
3493  }
3494  }
3495  }
3496  }
3497 
3498  return aRes;
3499 }
3500 
3502  const ScAddress& rPos, SCTAB nTab, SCROW nRow1, SCROW nRow2, const sc::ColRowReorderMapType& rColMap )
3503 {
3504  FormulaToken** p = pCode.get();
3505  FormulaToken** pEnd = p + static_cast<size_t>(nLen);
3506  for (; p != pEnd; ++p)
3507  {
3508  switch ((*p)->GetType())
3509  {
3510  case svSingleRef:
3511  {
3512  formula::FormulaToken* pToken = *p;
3513  ScSingleRefData& rRef = *pToken->GetSingleRef();
3514  ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rPos);
3515 
3516  if (aAbs.Tab() == nTab && nRow1 <= aAbs.Row() && aAbs.Row() <= nRow2)
3517  {
3518  // Inside reordered row range.
3519  sc::ColRowReorderMapType::const_iterator it = rColMap.find(aAbs.Col());
3520  if (it != rColMap.end())
3521  {
3522  // This column is reordered.
3523  SCCOL nNewCol = it->second;
3524  aAbs.SetCol(nNewCol);
3525  rRef.SetAddress(*mxSheetLimits, aAbs, rPos);
3526  }
3527  }
3528  }
3529  break;
3530  case svDoubleRef:
3531  {
3532  formula::FormulaToken* pToken = *p;
3533  ScComplexRefData& rRef = *pToken->GetDoubleRef();
3534  ScRange aAbs = rRef.toAbs(*mxSheetLimits, rPos);
3535 
3536  if (aAbs.aStart.Tab() != aAbs.aEnd.Tab())
3537  // Must be a single-sheet reference.
3538  break;
3539 
3540  if (aAbs.aStart.Col() != aAbs.aEnd.Col())
3541  // Whole range must fit in a single column.
3542  break;
3543 
3544  if (aAbs.aStart.Tab() == nTab && nRow1 <= aAbs.aStart.Row() && aAbs.aEnd.Row() <= nRow2)
3545  {
3546  // Inside reordered row range.
3548  if (it != rColMap.end())
3549  {
3550  // This column is reordered.
3551  SCCOL nNewCol = it->second;
3552  aAbs.aStart.SetCol(nNewCol);
3553  aAbs.aEnd.SetCol(nNewCol);
3554  rRef.SetRange(*mxSheetLimits, aAbs, rPos);
3555  }
3556  }
3557  }
3558  break;
3559  default:
3560  ;
3561  }
3562  }
3563 }
3564 
3565 void ScTokenArray::MoveReferenceRowReorder( const ScAddress& rPos, SCTAB nTab, SCCOL nCol1, SCCOL nCol2, const sc::ColRowReorderMapType& rRowMap )
3566 {
3567  FormulaToken** p = pCode.get();
3568  FormulaToken** pEnd = p + static_cast<size_t>(nLen);
3569  for (; p != pEnd; ++p)
3570  {
3571  switch ((*p)->GetType())
3572  {
3573  case svSingleRef:
3574  {
3575  formula::FormulaToken* pToken = *p;
3576  ScSingleRefData& rRef = *pToken->GetSingleRef();
3577  ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rPos);
3578 
3579  if (aAbs.Tab() == nTab && nCol1 <= aAbs.Col() && aAbs.Col() <= nCol2)
3580  {
3581  // Inside reordered column range.
3582  sc::ColRowReorderMapType::const_iterator it = rRowMap.find(aAbs.Row());
3583  if (it != rRowMap.end())
3584  {
3585  // This column is reordered.
3586  SCROW nNewRow = it->second;
3587  aAbs.SetRow(nNewRow);
3588  rRef.SetAddress(*mxSheetLimits, aAbs, rPos);
3589  }
3590  }
3591  }
3592  break;
3593  case svDoubleRef:
3594  {
3595  formula::FormulaToken* pToken = *p;
3596  ScComplexRefData& rRef = *pToken->GetDoubleRef();
3597  ScRange aAbs = rRef.toAbs(*mxSheetLimits, rPos);
3598 
3599  if (aAbs.aStart.Tab() != aAbs.aEnd.Tab())
3600  // Must be a single-sheet reference.
3601  break;
3602 
3603  if (aAbs.aStart.Row() != aAbs.aEnd.Row())
3604  // Whole range must fit in a single row.
3605  break;
3606 
3607  if (aAbs.aStart.Tab() == nTab && nCol1 <= aAbs.aStart.Col() && aAbs.aEnd.Col() <= nCol2)
3608  {
3609  // Inside reordered column range.
3611  if (it != rRowMap.end())
3612  {
3613  // This row is reordered.
3614  SCROW nNewRow = it->second;
3615  aAbs.aStart.SetRow(nNewRow);
3616  aAbs.aEnd.SetRow(nNewRow);
3617  rRef.SetRange(*mxSheetLimits, aAbs, rPos);
3618  }
3619  }
3620  }
3621  break;
3622  default:
3623  ;
3624  }
3625  }
3626 }
3627 
3628 namespace {
3629 
3630 bool adjustSingleRefInName(
3631  ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt, const ScAddress& rPos,
3632  ScComplexRefData* pEndOfComplex )
3633 {
3634  ScAddress aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3635 
3636  if (aAbs.Tab() < rCxt.maRange.aStart.Tab() || rCxt.maRange.aEnd.Tab() < aAbs.Tab())
3637  {
3638  // This references a sheet that has not shifted. Don't change it.
3639  return false;
3640  }
3641 
3642  if (!rCxt.maRange.In(rRef.toAbs(rCxt.mrDoc, rPos)))
3643  return false;
3644 
3645  bool bChanged = false;
3646 
3647  if (rCxt.mnColDelta && !rRef.IsColRel())
3648  {
3649  // Adjust absolute column reference.
3650  if (rCxt.maRange.aStart.Col() <= rRef.Col() && rRef.Col() <= rCxt.maRange.aEnd.Col())
3651  {
3652  if (pEndOfComplex)
3653  {
3654  if (pEndOfComplex->IncEndColSticky(rCxt.mrDoc, rCxt.mnColDelta, rPos))
3655  bChanged = true;
3656  }
3657  else
3658  {
3659  rRef.IncCol(rCxt.mnColDelta);
3660  bChanged = true;
3661  }
3662  }
3663  }
3664 
3665  if (rCxt.mnRowDelta && !rRef.IsRowRel())
3666  {
3667  // Adjust absolute row reference.
3668  if (rCxt.maRange.aStart.Row() <= rRef.Row() && rRef.Row() <= rCxt.maRange.aEnd.Row())
3669  {
3670  if (pEndOfComplex)
3671  {
3672  if (pEndOfComplex->IncEndRowSticky(rCxt.mrDoc, rCxt.mnRowDelta, rPos))
3673  bChanged = true;
3674  }
3675  else
3676  {
3677  rRef.IncRow(rCxt.mnRowDelta);
3678  bChanged = true;
3679  }
3680  }
3681  }
3682 
3683  if (!rRef.IsTabRel() && rCxt.mnTabDelta)
3684  {
3685  // Sheet range has already been checked above.
3686  rRef.IncTab(rCxt.mnTabDelta);
3687  bChanged = true;
3688  }
3689 
3690  return bChanged;
3691 }
3692 
3693 bool adjustDoubleRefInName(
3694  ScComplexRefData& rRef, const sc::RefUpdateContext& rCxt, const ScAddress& rPos )
3695 {
3696  bool bRefChanged = false;
3697  if (rCxt.mrDoc.IsExpandRefs())
3698  {
3699  if (rCxt.mnRowDelta > 0 && !rRef.Ref1.IsRowRel() && !rRef.Ref2.IsRowRel())
3700  {
3701  ScRange aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3702  // Expand only if at least two rows tall.
3703  if (aAbs.aStart.Row() < aAbs.aEnd.Row())
3704  {
3705  // Check and see if we should expand the range at the top.
3706  ScRange aSelectedRange = getSelectedRange(rCxt);
3707  if (aSelectedRange.Intersects(aAbs))
3708  {
3709  // Selection intersects the referenced range. Only expand the
3710  // bottom position.
3711  rRef.IncEndRowSticky(rCxt.mrDoc, rCxt.mnRowDelta, rPos);
3712  return true;
3713  }
3714  }
3715  }
3716  if (rCxt.mnColDelta > 0 && !rRef.Ref1.IsColRel() && !rRef.Ref2.IsColRel())
3717  {
3718  ScRange aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3719  // Expand only if at least two columns wide.
3720  if (aAbs.aStart.Col() < aAbs.aEnd.Col())
3721  {
3722  // Check and see if we should expand the range at the left.
3723  ScRange aSelectedRange = getSelectedRange(rCxt);
3724  if (aSelectedRange.Intersects(aAbs))
3725  {
3726  // Selection intersects the referenced range. Only expand the
3727  // right position.
3728  rRef.IncEndColSticky(rCxt.mrDoc, rCxt.mnColDelta, rPos);
3729  return true;
3730  }
3731  }
3732  }
3733  }
3734 
3735  if ((rCxt.mnRowDelta && rRef.IsEntireCol()) || (rCxt.mnColDelta && rRef.IsEntireRow()))
3736  {
3737  sc::RefUpdateContext aCxt( rCxt.mrDoc);
3738  // We only need a few parameters of RefUpdateContext.
3739  aCxt.maRange = rCxt.maRange;
3740  aCxt.mnColDelta = rCxt.mnColDelta;
3741  aCxt.mnRowDelta = rCxt.mnRowDelta;
3742  aCxt.mnTabDelta = rCxt.mnTabDelta;
3743 
3744  // References to entire col/row are not to be adjusted in the other axis.
3745  if (aCxt.mnRowDelta && rRef.IsEntireCol())
3746  aCxt.mnRowDelta = 0;
3747  if (aCxt.mnColDelta && rRef.IsEntireRow())
3748  aCxt.mnColDelta = 0;
3749  if (!aCxt.mnColDelta && !aCxt.mnRowDelta && !aCxt.mnTabDelta)
3750  // early bailout
3751  return bRefChanged;
3752 
3753  // Ref2 before Ref1 for sticky ends.
3754  if (adjustSingleRefInName(rRef.Ref2, aCxt, rPos, &rRef))
3755  bRefChanged = true;
3756 
3757  if (adjustSingleRefInName(rRef.Ref1, aCxt, rPos, nullptr))
3758  bRefChanged = true;
3759  }
3760  else
3761  {
3762  // Ref2 before Ref1 for sticky ends.
3763  if (adjustSingleRefInName(rRef.Ref2, rCxt, rPos, &rRef))
3764  bRefChanged = true;
3765 
3766  if (adjustSingleRefInName(rRef.Ref1, rCxt, rPos, nullptr))
3767  bRefChanged = true;
3768  }
3769 
3770  return bRefChanged;
3771 }
3772 
3773 }
3774 
3776  const sc::RefUpdateContext& rCxt, const ScAddress& rPos )
3777 {
3778  if (rCxt.meMode == URM_MOVE)
3779  return AdjustReferenceInMovedName(rCxt, rPos);
3780 
3781  sc::RefUpdateResult aRes;
3782 
3783  if (rCxt.meMode == URM_COPY)
3784  // Copying cells does not modify named expressions.
3785  return aRes;
3786 
3787  TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
3788  for (size_t j=0; j<2; ++j)
3789  {
3790  FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
3791  FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
3792  for (; pp != pEnd; ++pp)
3793  {
3794  FormulaToken* p = aPtrs.getHandledToken(j,pp);
3795  if (!p)
3796  continue;
3797 
3798  switch (p->GetType())
3799  {
3800  case svSingleRef:
3801  {
3802  ScSingleRefData& rRef = *p->GetSingleRef();
3803  if (rCxt.mnRowDelta < 0)
3804  {
3805  // row(s) deleted.
3806 
3807  if (rRef.IsRowRel())
3808  // Don't modify relative references in names.
3809  break;
3810 
3811  ScAddress aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3812 
3813  if (aAbs.Col() < rCxt.maRange.aStart.Col() || rCxt.maRange.aEnd.Col() < aAbs.Col())
3814  // column of the reference is not in the deleted column range.
3815  break;
3816 
3817  if (aAbs.Tab() > rCxt.maRange.aEnd.Tab() || aAbs.Tab() < rCxt.maRange.aStart.Tab())
3818  // wrong tables
3819  break;
3820 
3821  const SCROW nDelStartRow = rCxt.maRange.aStart.Row() + rCxt.mnRowDelta;
3822  const SCROW nDelEndRow = nDelStartRow - rCxt.mnRowDelta - 1;
3823 
3824  if (nDelStartRow <= aAbs.Row() && aAbs.Row() <= nDelEndRow)
3825  {
3826  // This reference is deleted.
3827  rRef.SetRowDeleted(true);
3828  aRes.mbReferenceModified = true;
3829  break;
3830  }
3831  }
3832  else if (rCxt.mnColDelta < 0)
3833  {
3834  // column(s) deleted.
3835 
3836  if (rRef.IsColRel())
3837  // Don't modify relative references in names.
3838  break;
3839 
3840  ScAddress aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3841 
3842  if (aAbs.Row() < rCxt.maRange.aStart.Row() || rCxt.maRange.aEnd.Row() < aAbs.Row())
3843  // row of the reference is not in the deleted row range.
3844  break;
3845 
3846  if (aAbs.Tab() > rCxt.maRange.aEnd.Tab() || aAbs.Tab() < rCxt.maRange.aStart.Tab())
3847  // wrong tables
3848  break;
3849 
3850  const SCCOL nDelStartCol = rCxt.maRange.aStart.Col() + rCxt.mnColDelta;
3851  const SCCOL nDelEndCol = nDelStartCol - rCxt.mnColDelta - 1;
3852 
3853  if (nDelStartCol <= aAbs.Col() && aAbs.Col() <= nDelEndCol)
3854  {
3855  // This reference is deleted.
3856  rRef.SetColDeleted(true);
3857  aRes.mbReferenceModified = true;
3858  break;
3859  }
3860  }
3861 
3862  if (adjustSingleRefInName(rRef, rCxt, rPos, nullptr))
3863  aRes.mbReferenceModified = true;
3864  }
3865  break;
3866  case svDoubleRef:
3867  {
3868  ScComplexRefData& rRef = *p->GetDoubleRef();
3869  ScRange aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3870 
3871  if (aAbs.aStart.Tab() > rCxt.maRange.aEnd.Tab() || aAbs.aEnd.Tab() < rCxt.maRange.aStart.Tab())
3872  // Sheet references not affected.
3873  break;
3874 
3875  if (rCxt.maRange.In(aAbs))
3876  {
3877  // This range is entirely within the shifted region.
3878  if (adjustDoubleRefInName(rRef, rCxt, rPos))
3879  aRes.mbReferenceModified = true;
3880  }
3881  else if (rCxt.mnRowDelta < 0)
3882  {
3883  // row(s) deleted.
3884 
3885  if (rRef.IsEntireCol())
3886  // Rows of entire columns are not affected.
3887  break;
3888 
3889  if (rRef.Ref1.IsRowRel() || rRef.Ref2.IsRowRel())
3890  // Don't modify relative references in names.
3891  break;
3892 
3893  if (aAbs.aStart.Col() < rCxt.maRange.aStart.Col() || rCxt.maRange.aEnd.Col() < aAbs.aEnd.Col())
3894  // column range of the reference is not entirely in the deleted column range.
3895  break;
3896 
3897  ScRange aDeleted = rCxt.maRange;
3898  aDeleted.aStart.IncRow(rCxt.mnRowDelta);
3899  aDeleted.aEnd.SetRow(aDeleted.aStart.Row()-rCxt.mnRowDelta-1);
3900 
3901  if (aAbs.aEnd.Row() < aDeleted.aStart.Row() || aDeleted.aEnd.Row() < aAbs.aStart.Row())
3902  // reference range doesn't intersect with the deleted range.
3903  break;
3904 
3905  if (aDeleted.aStart.Row() <= aAbs.aStart.Row() && aAbs.aEnd.Row() <= aDeleted.aEnd.Row())
3906  {
3907  // This reference is entirely deleted.
3908  rRef.Ref1.SetRowDeleted(true);
3909  rRef.Ref2.SetRowDeleted(true);
3910  aRes.mbReferenceModified = true;
3911  break;
3912  }
3913 
3914  if (aAbs.aStart.Row() < aDeleted.aStart.Row())
3915  {
3916  if (!aAbs.IsEndRowSticky())
3917  {
3918  if (aDeleted.aEnd.Row() < aAbs.aEnd.Row())
3919  // Deleted in the middle. Make the reference shorter.
3920  rRef.Ref2.IncRow(rCxt.mnRowDelta);
3921  else
3922  // Deleted at tail end. Cut off the lower part.
3923  rRef.Ref2.SetAbsRow(aDeleted.aStart.Row()-1);
3924  }
3925  }
3926  else
3927  {
3928  // Deleted at the top. Cut the top off and shift up.
3929  rRef.Ref1.SetAbsRow(aDeleted.aEnd.Row()+1);
3930  rRef.Ref1.IncRow(rCxt.mnRowDelta);
3931  if (!aAbs.IsEndRowSticky())
3932  rRef.Ref2.IncRow(rCxt.mnRowDelta);
3933  }
3934 
3935  aRes.mbReferenceModified = true;
3936  }
3937  else if (rCxt.mnColDelta < 0)
3938  {
3939  // column(s) deleted.
3940 
3941  if (rRef.IsEntireRow())
3942  // Rows of entire rows are not affected.
3943  break;
3944 
3945  if (rRef.Ref1.IsColRel() || rRef.Ref2.IsColRel())
3946  // Don't modify relative references in names.
3947  break;
3948 
3949  if (aAbs.aStart.Row() < rCxt.maRange.aStart.Row() || rCxt.maRange.aEnd.Row() < aAbs.aEnd.Row())
3950  // row range of the reference is not entirely in the deleted row range.
3951  break;
3952 
3953  ScRange aDeleted = rCxt.maRange;
3954  aDeleted.aStart.IncCol(rCxt.mnColDelta);
3955  aDeleted.aEnd.SetCol(aDeleted.aStart.Col()-rCxt.mnColDelta-1);
3956 
3957  if (aAbs.aEnd.Col() < aDeleted.aStart.Col() || aDeleted.aEnd.Col() < aAbs.aStart.Col())
3958  // reference range doesn't intersect with the deleted range.
3959  break;
3960 
3961  if (aDeleted.aStart.Col() <= aAbs.aStart.Col() && aAbs.aEnd.Col() <= aDeleted.aEnd.Col())
3962  {
3963  // This reference is entirely deleted.
3964  rRef.Ref1.SetColDeleted(true);
3965  rRef.Ref2.SetColDeleted(true);
3966  aRes.mbReferenceModified = true;
3967  break;
3968  }
3969 
3970  if (aAbs.aStart.Col() < aDeleted.aStart.Col())
3971  {
3972  if (!aAbs.IsEndColSticky())
3973  {
3974  if (aDeleted.aEnd.Col() < aAbs.aEnd.Col())
3975  // Deleted in the middle. Make the reference shorter.
3976  rRef.Ref2.IncCol(rCxt.mnColDelta);
3977  else
3978  // Deleted at tail end. Cut off the right part.
3979  rRef.Ref2.SetAbsCol(aDeleted.aStart.Col()-1);
3980  }
3981  }
3982  else
3983  {
3984  // Deleted at the left. Cut the left off and shift left.
3985  rRef.Ref1.SetAbsCol(aDeleted.aEnd.Col()+1);
3986  rRef.Ref1.IncCol(rCxt.mnColDelta);
3987  if (!aAbs.IsEndColSticky())
3988  rRef.Ref2.IncCol(rCxt.mnColDelta);
3989  }
3990 
3991  aRes.mbReferenceModified = true;
3992  }
3993  else if (rCxt.maRange.Intersects(aAbs))
3994  {
3995  if (rCxt.mnColDelta && rCxt.maRange.aStart.Row() <= aAbs.aStart.Row() && aAbs.aEnd.Row() <= rCxt.maRange.aEnd.Row())
3996  {
3997  if (adjustDoubleRefInName(rRef, rCxt, rPos))
3998  aRes.mbReferenceModified = true;
3999  }
4000  if (rCxt.mnRowDelta && rCxt.maRange.aStart.Col() <= aAbs.aStart.Col() && aAbs.aEnd.Col() <= rCxt.maRange.aEnd.Col())
4001  {
4002  if (adjustDoubleRefInName(rRef, rCxt, rPos))
4003  aRes.mbReferenceModified = true;
4004  }
4005  }
4006  else if (rCxt.mnRowDelta > 0 && rCxt.mrDoc.IsExpandRefs())
4007  {
4008  // Check if we could expand range reference by the bottom
4009  // edge. For named expressions, we only expand absolute
4010  // references. Reference must be at least two rows
4011  // tall.
4012  if (!rRef.Ref1.IsRowRel() && !rRef.Ref2.IsRowRel() &&
4013  aAbs.aStart.Row() < aAbs.aEnd.Row() &&
4014  aAbs.aEnd.Row()+1 == rCxt.maRange.aStart.Row())
4015  {
4016  // Expand by the bottom edge.
4017  rRef.Ref2.IncRow(rCxt.mnRowDelta);
4018  aRes.mbReferenceModified = true;
4019  }
4020  }
4021  else if (rCxt.mnColDelta > 0 && rCxt.mrDoc.IsExpandRefs())
4022  {
4023  // Check if we could expand range reference by the right
4024  // edge. For named expressions, we only expand absolute
4025  // references. Reference must be at least two
4026  // columns wide.
4027  if (!rRef.Ref1.IsColRel() && !rRef.Ref2.IsColRel() &&
4028  aAbs.aStart.Col() < aAbs.aEnd.Col() &&
4029  aAbs.aEnd.Col()+1 == rCxt.maRange.aStart.Col())
4030  {
4031  // Expand by the right edge.
4032  rRef.Ref2.IncCol(rCxt.mnColDelta);
4033  aRes.mbReferenceModified = true;
4034  }
4035  }
4036  }
4037  break;
4038  default:
4039  ;
4040  }
4041  }
4042  }
4043 
4044  return aRes;
4045 }
4046 
4048 {
4049  // When moving, the range is the destination range.
4050  ScRange aOldRange = rCxt.maRange;
4051  ScRange aErrorMoveRange( ScAddress::UNINITIALIZED );
4052  if (!aOldRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta, aErrorMoveRange))
4053  {
4054  assert(!"can't move");
4055  }
4056 
4057  // In a named expression, we'll move the reference only when the reference
4058  // is entirely absolute.
4059 
4060  sc::RefUpdateResult aRes;
4061 
4062  TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4063  for (size_t j=0; j<2; ++j)
4064  {
4065  FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4066  FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4067  for (; pp != pEnd; ++pp)
4068  {
4069  FormulaToken* p = aPtrs.getHandledToken(j,pp);
4070  if (!p)
4071  continue;
4072 
4073  switch (p->GetType())
4074  {
4075  case svSingleRef:
4076  {
4077  ScSingleRefData& rRef = *p->GetSingleRef();
4078  if (rRef.IsColRel() || rRef.IsRowRel() || rRef.IsTabRel())
4079  continue;
4080 
4081  ScAddress aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
4082 
4083  // Do not update the reference in transposed case (cut paste transposed).
4084  // The reference will be updated in UpdateTranspose().
4085  if (rCxt.mbTransposed && aOldRange.In(aAbs))
4086  break;
4087 
4088  if (aOldRange.In(aAbs))
4089  {
4090  ScAddress aErrorPos( ScAddress::UNINITIALIZED );
4091  if (!aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos))
4092  aAbs = aErrorPos;
4093  aRes.mbReferenceModified = true;
4094  }
4095 
4096  rRef.SetAddress(rCxt.mrDoc.GetSheetLimits(), aAbs, rPos);
4097  }
4098  break;
4099  case svDoubleRef:
4100  {
4101  ScComplexRefData& rRef = *p->GetDoubleRef();
4102  if (rRef.Ref1.IsColRel() || rRef.Ref1.IsRowRel() || rRef.Ref1.IsTabRel() ||
4103  rRef.Ref2.IsColRel() || rRef.Ref2.IsRowRel() || rRef.Ref2.IsTabRel())
4104  continue;
4105 
4106  ScRange aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
4107 
4108  // Do not update the reference in transposed case (cut paste transposed).
4109  // The reference will be updated in UpdateTranspose().
4110  if (rCxt.mbTransposed && aOldRange.In(aAbs))
4111  break;
4112 
4113  if (aOldRange.In(aAbs))
4114  {
4115  ScRange aErrorRange( ScAddress::UNINITIALIZED );
4116  if (!aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorRange))
4117  aAbs = aErrorRange;
4118  aRes.mbReferenceModified = true;
4119  }
4120 
4121  rRef.SetRange(rCxt.mrDoc.GetSheetLimits(), aAbs, rPos);
4122  }
4123  break;
4124  default:
4125  ;
4126  }
4127  }
4128  }
4129 
4130  return aRes;
4131 }
4132 
4133 namespace {
4134 
4135 bool adjustSingleRefOnDeletedTab( const ScSheetLimits& rLimits, ScSingleRefData& rRef, SCTAB nDelPos, SCTAB nSheets, const ScAddress& rOldPos, const ScAddress& rNewPos )
4136 {
4137  ScAddress aAbs = rRef.toAbs(rLimits, rOldPos);
4138  if (nDelPos <= aAbs.Tab() && aAbs.Tab() < nDelPos + nSheets)
4139  {
4140  rRef.SetTabDeleted(true);
4141  return true;
4142  }
4143 
4144  if (nDelPos < aAbs.Tab())
4145  {
4146  // Reference sheet needs to be adjusted.
4147  aAbs.IncTab(-1*nSheets);
4148  rRef.SetAddress(rLimits, aAbs, rNewPos);
4149  return true;
4150  }
4151  else if (rOldPos.Tab() != rNewPos.Tab())
4152  {
4153  // Cell itself has moved.
4154  rRef.SetAddress(rLimits, aAbs, rNewPos);
4155  return true;
4156  }
4157 
4158  return false;
4159 }
4160 
4161 bool adjustSingleRefOnInsertedTab( const ScSheetLimits& rLimits, ScSingleRefData& rRef, SCTAB nInsPos, SCTAB nSheets, const ScAddress& rOldPos, const ScAddress& rNewPos )
4162 {
4163  ScAddress aAbs = rRef.toAbs(rLimits, rOldPos);
4164  if (nInsPos <= aAbs.Tab())
4165  {
4166  // Reference sheet needs to be adjusted.
4167  aAbs.IncTab(nSheets);
4168  rRef.SetAddress(rLimits, aAbs, rNewPos);
4169  return true;
4170  }
4171  else if (rOldPos.Tab() != rNewPos.Tab())
4172  {
4173  // Cell itself has moved.
4174  rRef.SetAddress(rLimits, aAbs, rNewPos);
4175  return true;
4176  }
4177 
4178  return false;
4179 }
4180 
4181 bool adjustDoubleRefOnDeleteTab(const ScSheetLimits& rLimits, ScComplexRefData& rRef, SCTAB nDelPos, SCTAB nSheets, const ScAddress& rOldPos, const ScAddress& rNewPos)
4182 {
4183  ScSingleRefData& rRef1 = rRef.Ref1;
4184  ScSingleRefData& rRef2 = rRef.Ref2;
4185  ScAddress aStartPos = rRef1.toAbs(rLimits, rOldPos);
4186  ScAddress aEndPos = rRef2.toAbs(rLimits, rOldPos);
4187  bool bMoreThanOneTab = aStartPos.Tab() != aEndPos.Tab();
4188  bool bModified = false;
4189  if (bMoreThanOneTab && aStartPos.Tab() == nDelPos && nDelPos + nSheets <= aEndPos.Tab())
4190  {
4191  if (rRef1.IsTabRel() && aStartPos.Tab() < rOldPos.Tab())
4192  {
4193  rRef1.IncTab(nSheets);
4194  bModified = true;
4195  }
4196  }
4197  else
4198  {
4199  bModified = adjustSingleRefOnDeletedTab(rLimits, rRef1, nDelPos, nSheets, rOldPos, rNewPos);
4200  }
4201 
4202  if (bMoreThanOneTab && aEndPos.Tab() == nDelPos && aStartPos.Tab() <= nDelPos - nSheets)
4203  {
4204  if (!rRef2.IsTabRel() || rOldPos.Tab() < aEndPos.Tab())
4205  {
4206  rRef2.IncTab(-nSheets);
4207  bModified = true;
4208  }
4209  }
4210  else
4211  {
4212  bModified |= adjustSingleRefOnDeletedTab(rLimits, rRef2, nDelPos, nSheets, rOldPos, rNewPos);
4213  }
4214  return bModified;
4215 }
4216 
4217 }
4218 
4220 {
4221  sc::RefUpdateResult aRes;
4222  ScAddress aNewPos = rOldPos;
4223  if (rCxt.mnDeletePos < rOldPos.Tab())
4224  aNewPos.IncTab(-1*rCxt.mnSheets);
4225 
4226  TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4227  for (size_t j=0; j<2; ++j)
4228  {
4229  FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4230  FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4231  for (; pp != pEnd; ++pp)
4232  {
4233  FormulaToken* p = aPtrs.getHandledToken(j,pp);
4234  if (!p)
4235  continue;
4236 
4237  switch (p->GetType())
4238  {
4239  case svSingleRef:
4240  {
4241  ScSingleRefData& rRef = *p->GetSingleRef();
4242  if (adjustSingleRefOnDeletedTab(*mxSheetLimits, rRef, rCxt.mnDeletePos, rCxt.mnSheets, rOldPos, aNewPos))
4243  aRes.mbReferenceModified = true;
4244  }
4245  break;
4246  case svDoubleRef:
4247  {
4248  ScComplexRefData& rRef = *p->GetDoubleRef();
4249  aRes.mbReferenceModified |= adjustDoubleRefOnDeleteTab(*mxSheetLimits, rRef, rCxt.mnDeletePos, rCxt.mnSheets, rOldPos, aNewPos);
4250  }
4251  break;
4252  default:
4253  ;
4254  }
4255 
4256  // For ocTableRef p is the inner token of *pp, so have a separate
4257  // condition here.
4258  if ((*pp)->GetType() == svIndex)
4259  {
4260  switch ((*pp)->GetOpCode())
4261  {
4262  case ocName:
4263  {
4264  SCTAB nOldTab = (*pp)->GetSheet();
4265  if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
4266  aRes.mbNameModified = true;
4267  if (rCxt.mnDeletePos <= nOldTab)
4268  {
4269  aRes.mbNameModified = true;
4270  if (rCxt.mnDeletePos + rCxt.mnSheets <= nOldTab)
4271  (*pp)->SetSheet( nOldTab - rCxt.mnSheets);
4272  else
4273  // Would point to a deleted sheet. Invalidate.
4274  (*pp)->SetSheet( SCTAB_MAX);
4275  }
4276  }
4277  break;
4278  case ocDBArea:
4279  case ocTableRef:
4280  if (isDBDataModified(rCxt.mrDoc, **pp))
4281  aRes.mbNameModified = true;
4282  break;
4283  default:
4284  ; // nothing
4285  }
4286  }
4287  }
4288  }
4289  return aRes;
4290 }
4291 
4293 {
4294  sc::RefUpdateResult aRes;
4295  ScAddress aNewPos = rOldPos;
4296  if (rCxt.mnInsertPos <= rOldPos.Tab())
4297  aNewPos.IncTab(rCxt.mnSheets);
4298 
4299  TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4300  for (size_t j=0; j<2; ++j)
4301  {
4302  FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4303  FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4304  for (; pp != pEnd; ++pp)
4305  {
4306  FormulaToken* p = aPtrs.getHandledToken(j,pp);
4307  if (!p)
4308  continue;
4309 
4310  switch (p->GetType())
4311  {
4312  case svSingleRef:
4313  {
4314  ScSingleRefData& rRef = *p->GetSingleRef();
4315  if (adjustSingleRefOnInsertedTab(*mxSheetLimits, rRef, rCxt.mnInsertPos, rCxt.mnSheets, rOldPos, aNewPos))
4316  aRes.mbReferenceModified = true;
4317  }
4318  break;
4319  case svDoubleRef:
4320  {
4321  ScComplexRefData& rRef = *p->GetDoubleRef();
4322  if (adjustSingleRefOnInsertedTab(*mxSheetLimits, rRef.Ref1, rCxt.mnInsertPos, rCxt.mnSheets, rOldPos, aNewPos))
4323  aRes.mbReferenceModified = true;
4324  if (adjustSingleRefOnInsertedTab(*mxSheetLimits, rRef.Ref2, rCxt.mnInsertPos, rCxt.mnSheets, rOldPos, aNewPos))
4325  aRes.mbReferenceModified = true;
4326  }
4327  break;
4328  default:
4329  ;
4330  }
4331 
4332  // For ocTableRef p is the inner token of *pp, so have a separate
4333  // condition here.
4334  if ((*pp)->GetType() == svIndex)
4335  {
4336  switch ((*pp)->GetOpCode())
4337  {
4338  case ocName:
4339  {
4340  SCTAB nOldTab = (*pp)->GetSheet();
4341  if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
4342  aRes.mbNameModified = true;
4343  if (rCxt.mnInsertPos <= nOldTab)
4344  {
4345  aRes.mbNameModified = true;
4346  (*pp)->SetSheet( nOldTab + rCxt.mnSheets);
4347  }
4348  }
4349  break;
4350  case ocDBArea:
4351  case ocTableRef:
4352  if (isDBDataModified(rCxt.mrDoc, **pp))
4353  aRes.mbNameModified = true;
4354  break;
4355  default:
4356  ; // nothing
4357  }
4358  }
4359  }
4360  }
4361  return aRes;
4362 }
4363 
4364 namespace {
4365 
4366 bool adjustTabOnMove( ScAddress& rPos, const sc::RefUpdateMoveTabContext& rCxt )
4367 {
4368  SCTAB nNewTab = rCxt.getNewTab(rPos.Tab());
4369  if (nNewTab == rPos.Tab())
4370  return false;
4371 
4372  rPos.SetTab(nNewTab);
4373  return true;
4374 }
4375 
4376 }
4377 
4379 {
4380  sc::RefUpdateResult aRes;
4381  if (rCxt.mnOldPos == rCxt.mnNewPos)
4382  return aRes;
4383 
4384  ScAddress aNewPos = rOldPos;
4385  if (adjustTabOnMove(aNewPos, rCxt))
4386  aRes.mbReferenceModified = true;
4387 
4388  TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4389  for (size_t j=0; j<2; ++j)
4390  {
4391  FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4392  FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4393  for (; pp != pEnd; ++pp)
4394  {
4395  FormulaToken* p = aPtrs.getHandledToken(j,pp);
4396  if (!p)
4397  continue;
4398 
4399  switch (p->GetType())
4400  {
4401  case svSingleRef:
4402  {
4403  ScSingleRefData& rRef = *p->GetSingleRef();
4404  ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
4405  if (adjustTabOnMove(aAbs, rCxt))
4406  aRes.mbReferenceModified = true;
4407  rRef.SetAddress(*mxSheetLimits, aAbs, aNewPos);
4408  }
4409  break;
4410  case svDoubleRef:
4411  {
4412  ScComplexRefData& rRef = *p->GetDoubleRef();
4413  ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
4414  if (adjustTabOnMove(aAbs.aStart,