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