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