summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2020-10-13 18:16:24 +0200
committerEike Rathke <erack@redhat.com>2020-10-13 21:36:31 +0200
commit3a33828b8de7554e497051738c722b1764960a86 (patch)
tree8265298e3ccc6a1f52e8db3d9f51d68397b0b6ef
parentf558d810de845ad1dd52632ca0a2cae4733ed6e6 (diff)
Resolves: tdf#133260 Propagate ForceArrayReturn from inline arrays
... and functions returning array/matrix. Same as for TRANSPOSE() and FREQUENCY() but not mentioned in ECMA-376-1:2016 OOXML. Change-Id: I1e9f1151b2bc0b7de892f4f3d9f91b9a6b86b67f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/104249 Reviewed-by: Eike Rathke <erack@redhat.com> Tested-by: Jenkins
-rw-r--r--formula/source/core/api/FormulaCompiler.cxx54
1 files changed, 45 insertions, 9 deletions
diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx
index e969ecba4344..3829ffe562df 100644
--- a/formula/source/core/api/FormulaCompiler.cxx
+++ b/formula/source/core/api/FormulaCompiler.cxx
@@ -2714,9 +2714,41 @@ void FormulaCompiler::ForceArrayOperator( FormulaTokenRef const & rCurr )
// CheckSetForceArrayParameter() and later PutCode().
return;
- if (!(rCurr->GetOpCode() != ocPush && (rCurr->GetType() == svByte || rCurr->GetType() == svJump)))
+ const OpCode eOp = rCurr->GetOpCode();
+ const StackVar eType = rCurr->GetType();
+ bool bInlineArray = false;
+ if (!(eOp != ocPush && (eType == svByte || eType == svJump))
+ && !(bInlineArray = (eOp == ocPush && eType == svMatrix)))
return;
+ // Return class for inline arrays and functions returning array/matrix.
+ // It's somewhat unclear what Excel actually does there and in
+ // ECMA-376-1:2016 OOXML mentions "call to ... shall be an array formula"
+ // only for FREQUENCY() and TRANSPOSE() but not for any other function
+ // returning array/matrix or inline arrays, though for the latter has one
+ // example in 18.17.2 Syntax:
+ // "SUM(SQRT({1,2,3,4})) returns 6.14 when entered normally". However,
+ // these need to be treated similar but not as ParamClass::ForceArray
+ // (which would contradict the example in
+ // https://bugs.documentfoundation.org/show_bug.cgi?id=122301#c19 and A6 of
+ // https://bugs.documentfoundation.org/show_bug.cgi?id=133260#c10 ).
+ // See also
+ // commit d0ded163d8e93dc5b10d7a7c9bdab1d0a6a50bac
+ // commit 5413c8871dec08eff19f514f5f391b946a45c86c
+ constexpr ParamClass eArrayReturn = ParamClass::ForceArrayReturn;
+
+ if (bInlineArray)
+ {
+ // rCurr->SetInForceArray() can not be used with ocPush.
+ if (pCurrentFactorToken && pCurrentFactorToken->GetInForceArray() == ParamClass::Unknown)
+ {
+ // Propagate to caller as if a function returning an array/matrix
+ // was called (see also below).
+ pCurrentFactorToken->SetInForceArray( eArrayReturn);
+ }
+ return;
+ }
+
if (!pCurrentFactorToken || (pCurrentFactorToken.get() == rCurr.get()))
{
if (!pCurrentFactorToken && mbMatrixFlag)
@@ -2760,14 +2792,14 @@ void FormulaCompiler::ForceArrayOperator( FormulaTokenRef const & rCurr )
return;
// Actual current parameter's class.
- const formula::ParamClass eType = GetForceArrayParameter(
+ const formula::ParamClass eParamType = GetForceArrayParameter(
pCurrentFactorToken.get(), static_cast<sal_uInt16>(nCurrentFactorParam - 1));
- if (eType == ParamClass::ForceArray)
- rCurr->SetInForceArray( eType);
- else if (eType == ParamClass::ReferenceOrForceArray)
+ if (eParamType == ParamClass::ForceArray)
+ rCurr->SetInForceArray( eParamType);
+ else if (eParamType == ParamClass::ReferenceOrForceArray)
{
if (GetForceArrayParameter( rCurr.get(), SAL_MAX_UINT16) != ParamClass::Reference)
- rCurr->SetInForceArray( eType);
+ rCurr->SetInForceArray( eParamType);
else
rCurr->SetInForceArray( formula::ParamClass::SuppressedReferenceOrForceArray);
}
@@ -2775,9 +2807,13 @@ void FormulaCompiler::ForceArrayOperator( FormulaTokenRef const & rCurr )
// Propagate a ForceArrayReturn to caller if the called function
// returns one and the caller so far does not have a stronger array
// mode set.
- if (pCurrentFactorToken->GetInForceArray() == ParamClass::Unknown
- && GetForceArrayParameter( rCurr.get(), SAL_MAX_UINT16) == ParamClass::ForceArrayReturn)
- pCurrentFactorToken->SetInForceArray( ParamClass::ForceArrayReturn);
+ if (pCurrentFactorToken->GetInForceArray() == ParamClass::Unknown)
+ {
+ if (IsMatrixFunction( eOp))
+ pCurrentFactorToken->SetInForceArray( eArrayReturn);
+ else if (GetForceArrayParameter( rCurr.get(), SAL_MAX_UINT16) == ParamClass::ForceArrayReturn)
+ pCurrentFactorToken->SetInForceArray( ParamClass::ForceArrayReturn);
+ }
}
void FormulaCompiler::CheckSetForceArrayParameter( FormulaTokenRef const & rCurr, sal_uInt8 nParam )