summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2018-11-09 12:39:40 +0100
committerEike Rathke <erack@redhat.com>2018-11-09 19:14:09 +0100
commit6ce84da750abcec3139bf12bc212fb2f03460add (patch)
treec8c333458a924bd1c33ed1c233f88888e7a7d43a
parentcustom widgets: Fix various warnings. (diff)
downloadcore-6ce84da750abcec3139bf12bc212fb2f03460add.tar.gz
core-6ce84da750abcec3139bf12bc212fb2f03460add.zip
Resolves: tdf#120895 new ParamClass::ReferenceOrRefArray, tdf#58874 related
Too many side conditions are possible with implicit array of references in array mode. Propagate new ReferenceOrRefArray parameter class to indicate the preferred return type for arguments to functions whose parameters explicitly handle array of references. Change-Id: I1f01266495c2ef1941ffe0cb7c2e0a5ae0bb7e69 Reviewed-on: https://gerrit.libreoffice.org/63201 Reviewed-by: Eike Rathke <erack@redhat.com> Tested-by: Jenkins
-rw-r--r--formula/source/core/api/FormulaCompiler.cxx33
-rw-r--r--formula/source/core/api/token.cxx3
-rw-r--r--formula/source/ui/dlg/formula.cxx1
-rw-r--r--include/formula/paramclass.hxx8
-rw-r--r--sc/source/core/tool/compiler.cxx3
-rw-r--r--sc/source/core/tool/interpr1.cxx6
-rw-r--r--sc/source/core/tool/interpr4.cxx2
-rw-r--r--sc/source/core/tool/parclass.cxx56
8 files changed, 76 insertions, 36 deletions
diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx
index b0938aa630be..ccf4562fec9d 100644
--- a/formula/source/core/api/FormulaCompiler.cxx
+++ b/formula/source/core/api/FormulaCompiler.cxx
@@ -2693,6 +2693,13 @@ formula::ParamClass FormulaCompiler::GetForceArrayParameter( const FormulaToken*
void FormulaCompiler::ForceArrayOperator( FormulaTokenRef const & rCurr )
{
+ if (rCurr->GetInForceArray() != ParamClass::Unknown)
+ // Already set, unnecessary to evaluate again. This happens by calls to
+ // CurrentFactor::operator=() while descending through Factor() and
+ // then ascending back (and down and up, ...),
+ // CheckSetForceArrayParameter() and later PutCode().
+ return;
+
if (!pCurrentFactorToken || (pCurrentFactorToken.get() == rCurr.get()))
return;
@@ -2700,27 +2707,37 @@ void FormulaCompiler::ForceArrayOperator( FormulaTokenRef const & rCurr )
return;
// Inherited parameter class.
- formula::ParamClass eType = pCurrentFactorToken->GetInForceArray();
- if (eType == formula::ParamClass::ForceArray)
- {
- rCurr->SetInForceArray( eType);
+ const formula::ParamClass eForceType = pCurrentFactorToken->GetInForceArray();
+ if (eForceType == ParamClass::ForceArray || eForceType == ParamClass::ReferenceOrRefArray)
+ {
+ // ReferenceOrRefArray was set only if in ForceArray context already,
+ // it is valid for the one function only to indicate the preferred
+ // return type. Propagate as ForceArray if not another parameter
+ // handling ReferenceOrRefArray.
+ if (nCurrentFactorParam > 0
+ && (GetForceArrayParameter( pCurrentFactorToken.get(), static_cast<sal_uInt16>(nCurrentFactorParam - 1))
+ == ParamClass::ReferenceOrRefArray))
+ rCurr->SetInForceArray( ParamClass::ReferenceOrRefArray);
+ else
+ rCurr->SetInForceArray( ParamClass::ForceArray);
return;
}
- else if (eType == formula::ParamClass::ReferenceOrForceArray)
+ else if (eForceType == ParamClass::ReferenceOrForceArray)
{
// Inherit further only if the return class of the nested function is
// not Reference. Else flag as suppressed.
if (GetForceArrayParameter( rCurr.get(), SAL_MAX_UINT16) != ParamClass::Reference)
- rCurr->SetInForceArray( eType);
+ rCurr->SetInForceArray( eForceType);
else
- rCurr->SetInForceArray( formula::ParamClass::SuppressedReferenceOrForceArray);
+ rCurr->SetInForceArray( ParamClass::SuppressedReferenceOrForceArray);
return;
}
if (nCurrentFactorParam > 0)
{
// Actual current parameter's class.
- eType = GetForceArrayParameter( pCurrentFactorToken.get(), static_cast<sal_uInt16>(nCurrentFactorParam - 1));
+ const formula::ParamClass eType = GetForceArrayParameter(
+ pCurrentFactorToken.get(), static_cast<sal_uInt16>(nCurrentFactorParam - 1));
if (eType == ParamClass::ForceArray)
rCurr->SetInForceArray( eType);
else if (eType == ParamClass::ReferenceOrForceArray)
diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx
index cefab324fd53..aa3dbec8c8ef 100644
--- a/formula/source/core/api/token.cxx
+++ b/formula/source/core/api/token.cxx
@@ -150,7 +150,8 @@ bool FormulaToken::IsRef() const
bool FormulaToken::IsInForceArray() const
{
ParamClass eParam = GetInForceArray();
- return eParam == ParamClass::ForceArray || eParam == ParamClass::ReferenceOrForceArray;
+ return eParam == ParamClass::ForceArray || eParam == ParamClass::ReferenceOrForceArray
+ || eParam == ParamClass::ReferenceOrRefArray;
}
bool FormulaToken::operator==( const FormulaToken& rToken ) const
diff --git a/formula/source/ui/dlg/formula.cxx b/formula/source/ui/dlg/formula.cxx
index c324be63a943..55135ebc11cf 100644
--- a/formula/source/ui/dlg/formula.cxx
+++ b/formula/source/ui/dlg/formula.cxx
@@ -753,6 +753,7 @@ void FormulaDlg_Impl::MakeTree( StructPage* _pTree, SvTreeListEntry* pParent, co
aUnforcedResult.clear();
break;
case ParamClass::Reference:
+ case ParamClass::ReferenceOrRefArray:
case ParamClass::Array:
case ParamClass::ForceArray:
case ParamClass::ReferenceOrForceArray:
diff --git a/include/formula/paramclass.hxx b/include/formula/paramclass.hxx
index a22854fc890c..a1e564819457 100644
--- a/include/formula/paramclass.hxx
+++ b/include/formula/paramclass.hxx
@@ -36,6 +36,14 @@ namespace formula
PopDoubleRefOrSingleRef() should not have this. */
Reference,
+ /** Like Reference but the function accepts also a list of references
+ (ocUnion svRefList) as one argument AND handles the special case of
+ an array of references in array mode. Then the resulting argument
+ for a parameter in JumpMatrix context may be an array of references
+ which then is to be preferred over a result matrix. This final
+ behaviour is the opposite of SuppressedReferenceOrForceArray. */
+ ReferenceOrRefArray,
+
/** In array formula: convert area reference to array. Function will be
called only once if no Value type is involved. Functions able to
handle a svMatrix parameter but not a formula::svDoubleRef parameter as area
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index 3c86ad2f5591..556cd49b39c3 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -5809,7 +5809,8 @@ bool ScCompiler::SkipImplicitIntersectionOptimization(const FormulaToken* token)
formula::ParamClass paramClass = token->GetInForceArray();
if (paramClass == formula::ForceArray
|| paramClass == formula::ReferenceOrForceArray
- || paramClass == formula::SuppressedReferenceOrForceArray)
+ || paramClass == formula::SuppressedReferenceOrForceArray
+ || paramClass == formula::ReferenceOrRefArray)
{
return true;
}
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 38e56deb52f7..b83406223a17 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -835,8 +835,10 @@ bool ScInterpreter::JumpMatrix( short nStackLevel )
{ // We're done with it, throw away jump matrix, keep result.
// For an intermediate result of Reference use the array of references
// if there are more than one reference and the current ForceArray
- // context is not ForceArray or related, suppressed, ...,
- // else (also for a final result of Reference) use the matrix.
+ // context is not ForceArray or suppressed. Note that also
+ // ReferenceOrRefArray forces the array of references as result if
+ // there is more than one reference.
+ // Else (also for a final result of Reference) use the matrix.
// Treat the result of a jump command as final and use the matrix (see
// tdf#115493 for why).
ParamClass eParamClass;
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
index a1eb180683db..3bb3cf83c350 100644
--- a/sc/source/core/tool/interpr4.cxx
+++ b/sc/source/core/tool/interpr4.cxx
@@ -1490,6 +1490,7 @@ bool ScInterpreter::ConvertMatrixParameters()
{
formula::ParamClass eType = ScParameterClassification::GetParameterType( pCur, nParams - i);
if ( eType != formula::ParamClass::Reference &&
+ eType != formula::ParamClass::ReferenceOrRefArray &&
eType != formula::ParamClass::ReferenceOrForceArray &&
// For scalar Value: convert to Array/JumpMatrix
// only if in array formula context, else (function
@@ -1554,6 +1555,7 @@ bool ScInterpreter::ConvertMatrixParameters()
{
formula::ParamClass eType = ScParameterClassification::GetParameterType( pCur, nParams - i);
if ( eType != formula::ParamClass::Reference &&
+ eType != formula::ParamClass::ReferenceOrRefArray &&
eType != formula::ParamClass::ReferenceOrForceArray &&
eType != formula::ParamClass::ForceArray)
{
diff --git a/sc/source/core/tool/parclass.cxx b/sc/source/core/tool/parclass.cxx
index 9f79da716a40..46179fe552f8 100644
--- a/sc/source/core/tool/parclass.cxx
+++ b/sc/source/core/tool/parclass.cxx
@@ -99,25 +99,25 @@ const ScParameterClassification::RawData ScParameterClassification::pRawData[] =
{ ocTableOp, {{ Value, Value, Value, Value, Value }, 0, Value }},
// Operators and functions.
{ ocAdd, {{ Array, Array }, 0, Value }},
- { ocAggregate, {{ Value, Value, Reference }, 1, Value }},
+ { ocAggregate, {{ Value, Value, ReferenceOrRefArray }, 1, Value }},
{ ocAmpersand, {{ Array, Array }, 0, Value }},
{ ocAnd, {{ Reference }, 1, Value }},
{ ocAreas, {{ Reference }, 0, Value }},
{ ocAveDev, {{ Reference }, 1, Value }},
- { ocAverage, {{ Reference }, 1, Value }},
- { ocAverageA, {{ Reference }, 1, Value }},
- { ocAverageIf, {{ Reference, Value, Reference }, 0, Value }},
- { ocAverageIfs, {{ Reference, Reference, Value }, 2, Value }},
+ { ocAverage, {{ ReferenceOrRefArray }, 1, Value }},
+ { ocAverageA, {{ ReferenceOrRefArray }, 1, Value }},
+ { ocAverageIf, {{ ReferenceOrRefArray, Value, Reference }, 0, Value }},
+ { ocAverageIfs, {{ ReferenceOrRefArray, ReferenceOrRefArray, Value }, 2, Value }},
{ ocCell, {{ Value, Reference }, 0, Value }},
{ ocColumn, {{ Reference }, 0, Value }},
{ ocColumns, {{ Reference }, 1, Value }},
{ ocConcat_MS, {{ Reference }, 1, Value }},
{ ocCorrel, {{ ForceArray, ForceArray }, 0, Value }},
- { ocCount, {{ Reference }, 1, Value }},
- { ocCount2, {{ Reference }, 1, Value }},
- { ocCountEmptyCells, {{ Reference }, 0, Value }},
- { ocCountIf, {{ Reference, Value }, 0, Value }},
- { ocCountIfs, {{ Reference, Value }, 2, Value }},
+ { ocCount, {{ ReferenceOrRefArray }, 1, Value }},
+ { ocCount2, {{ ReferenceOrRefArray }, 1, Value }},
+ { ocCountEmptyCells, {{ ReferenceOrRefArray }, 0, Value }},
+ { ocCountIf, {{ ReferenceOrRefArray, Value }, 0, Value }},
+ { ocCountIfs, {{ ReferenceOrRefArray, Value }, 2, Value }},
{ ocCovar, {{ ForceArray, ForceArray }, 0, Value }},
{ ocCovarianceP, {{ ForceArray, ForceArray }, 0, Value }},
{ ocCovarianceS, {{ ForceArray, ForceArray }, 0, Value }},
@@ -176,11 +176,13 @@ const ScParameterClassification::RawData ScParameterClassification::pRawData[] =
{ ocMatTrans, {{ Array }, 0, Value }}, // strange, but Xcl doesn't force MatTrans array
{ ocMatValue, {{ Reference, Value, Value }, 0, Value }},
{ ocMatch, {{ Value, ReferenceOrForceArray, Value }, 0, Value }},
- { ocMax, {{ Reference }, 1, Value }},
- { ocMaxA, {{ Reference }, 1, Value }},
+ { ocMax, {{ ReferenceOrRefArray }, 1, Value }},
+ { ocMaxA, {{ ReferenceOrRefArray }, 1, Value }},
+ { ocMaxIfs_MS, {{ ReferenceOrRefArray, ReferenceOrRefArray, Value }, 2, Value }},
{ ocMedian, {{ Reference }, 1, Value }},
- { ocMin, {{ Reference }, 1, Value }},
- { ocMinA, {{ Reference }, 1, Value }},
+ { ocMin, {{ ReferenceOrRefArray }, 1, Value }},
+ { ocMinA, {{ ReferenceOrRefArray }, 1, Value }},
+ { ocMinIfs_MS, {{ ReferenceOrRefArray, ReferenceOrRefArray, Value }, 2, Value }},
{ ocModalValue, {{ ForceArray }, 1, Value }},
{ ocModalValue_MS, {{ ForceArray }, 1, Value }},
{ ocModalValue_Multi,{{ ForceArray }, 1, Value }},
@@ -206,7 +208,7 @@ const ScParameterClassification::RawData ScParameterClassification::pRawData[] =
{ ocPow, {{ Array, Array }, 0, Value }},
{ ocPower, {{ Array, Array }, 0, Value }},
{ ocProb, {{ ForceArray, ForceArray, Value, Value }, 0, Value }},
- { ocProduct, {{ Reference }, 1, Value }},
+ { ocProduct, {{ ReferenceOrRefArray }, 1, Value }},
{ ocQuartile, {{ Reference, Value }, 0, Value }},
{ ocQuartile_Exc, {{ Reference, Value }, 0, Value }},
{ ocQuartile_Inc, {{ Reference, Value }, 0, Value }},
@@ -231,12 +233,12 @@ const ScParameterClassification::RawData ScParameterClassification::pRawData[] =
{ ocStDevP_MS, {{ Reference }, 1, Value }},
{ ocStDevS, {{ Reference }, 1, Value }},
{ ocSub, {{ Array, Array }, 0, Value }},
- { ocSubTotal, {{ Value, Reference }, 1, Value }},
- { ocSum, {{ Reference }, 1, Value }},
- { ocSumIf, {{ Reference, Value, Reference }, 0, Value }},
- { ocSumIfs, {{ Reference, Reference, Value }, 2, Value }},
+ { ocSubTotal, {{ Value, ReferenceOrRefArray }, 1, Value }},
+ { ocSum, {{ ReferenceOrRefArray }, 1, Value }},
+ { ocSumIf, {{ ReferenceOrRefArray, Value, Reference }, 0, Value }},
+ { ocSumIfs, {{ ReferenceOrRefArray, ReferenceOrRefArray, Value }, 2, Value }},
{ ocSumProduct, {{ ForceArray }, 1, Value }},
- { ocSumSQ, {{ Reference }, 1, Value }},
+ { ocSumSQ, {{ ReferenceOrRefArray }, 1, Value }},
{ ocSumX2DY2, {{ ForceArray, ForceArray }, 0, Value }},
{ ocSumX2MY2, {{ ForceArray, ForceArray }, 0, Value }},
{ ocSumXMY2, {{ ForceArray, ForceArray }, 0, Value }},
@@ -246,10 +248,10 @@ const ScParameterClassification::RawData ScParameterClassification::pRawData[] =
{ ocTrimMean, {{ Reference, Value }, 0, Value }},
{ ocUnion, {{ Reference, Reference }, 0, Reference }},
{ ocVLookup, {{ Value, ReferenceOrForceArray, Value, Value }, 0, Value }},
- { ocVar, {{ Reference }, 1, Value }},
- { ocVarA, {{ Reference }, 1, Value }},
- { ocVarP, {{ Reference }, 1, Value }},
- { ocVarPA, {{ Reference }, 1, Value }},
+ { ocVar, {{ ReferenceOrRefArray }, 1, Value }},
+ { ocVarA, {{ ReferenceOrRefArray }, 1, Value }},
+ { ocVarP, {{ ReferenceOrRefArray }, 1, Value }},
+ { ocVarPA, {{ ReferenceOrRefArray }, 1, Value }},
{ ocVarP_MS, {{ Reference }, 1, Value }},
{ ocVarS, {{ Reference }, 1, Value }},
{ ocWorkday_MS, {{ Value, Value, Value, Reference }, 0, Value }},
@@ -613,6 +615,9 @@ void ScParameterClassification::GenerateDocumentation()
case Reference :
aStr.append(" Reference");
break;
+ case ReferenceOrRefArray :
+ aStr.append(" ReferenceOrRefArray");
+ break;
case Array :
aStr.append(" Array");
break;
@@ -664,6 +669,9 @@ void ScParameterClassification::GenerateDocumentation()
case Reference :
aStr.append(" -> Reference");
break;
+ case ReferenceOrRefArray :
+ aStr.append(" -> ReferenceOrRefArray");
+ break;
case Array :
aStr.append(" -> Array");
break;