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