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