Kaydet (Commit) 6ce84da7 authored tarafından Eike Rathke's avatar Eike Rathke

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/63201Reviewed-by: 's avatarEike Rathke <erack@redhat.com>
Tested-by: Jenkins
üst 717cdaf4
......@@ -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)
......
......@@ -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
......
......@@ -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:
......
......@@ -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
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment