tdf#155369 ScIndirect: handle names that resolve to...

table structured references.

Conflicts:
	sc/qa/unit/subsequent_filters_test2.cxx

Change-Id: I897feeeb49e63c1758cf64450799acb192e2d593
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151888
Tested-by: Jenkins
Reviewed-by: Dennis Francis <dennis.francis@collabora.com>
Signed-off-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152083
diff --git a/sc/qa/unit/data/xlsx/tablerefsnamed.xlsx b/sc/qa/unit/data/xlsx/tablerefsnamed.xlsx
new file mode 100644
index 0000000..825103d
--- /dev/null
+++ b/sc/qa/unit/data/xlsx/tablerefsnamed.xlsx
Binary files differ
diff --git a/sc/qa/unit/subsequent_filters_test2.cxx b/sc/qa/unit/subsequent_filters_test2.cxx
index da79b48..177fcc7 100644
--- a/sc/qa/unit/subsequent_filters_test2.cxx
+++ b/sc/qa/unit/subsequent_filters_test2.cxx
@@ -190,6 +190,7 @@ public:
    void testTdf83671_SmartArt_import();
    void testTdf83671_SmartArt_import2();
    void testTdf151818_SmartArtFontColor();
    void testNamedTableRef();

    CPPUNIT_TEST_SUITE(ScFiltersTest2);

@@ -310,6 +311,7 @@ public:
    CPPUNIT_TEST(testTdf83671_SmartArt_import);
    CPPUNIT_TEST(testTdf83671_SmartArt_import2);
    CPPUNIT_TEST(testTdf151818_SmartArtFontColor);
    CPPUNIT_TEST(testNamedTableRef);

    CPPUNIT_TEST_SUITE_END();
};
@@ -3035,6 +3037,21 @@ void ScFiltersTest2::testTdf151818_SmartArtFontColor()
    }
}

void ScFiltersTest2::testNamedTableRef()
{
    createScDoc("xlsx/tablerefsnamed.xlsx");
    ScDocument* pDoc = getScDoc();
    for (sal_Int32 nRow = 1; nRow < 7; ++nRow)
    {
        ScFormulaCell* pFC = pDoc->GetFormulaCell(ScAddress(5, nRow, 0));
        CPPUNIT_ASSERT(pFC);
        // Without the fix there will be #REF in F2:F7.
        CPPUNIT_ASSERT_EQUAL(FormulaError::NONE, pFC->GetErrCode());
        // Without the fix value will be 0 (FALSE).
        CPPUNIT_ASSERT_EQUAL(1.0, pDoc->GetValue(ScAddress(6, nRow, 0)));
    }
}

CPPUNIT_TEST_SUITE_REGISTRATION(ScFiltersTest2);

CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index b833e3f..32ec733 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -8181,6 +8181,12 @@ void ScInterpreter::ScDBVarP()
    PushDouble(fVal/fCount);
}

static bool lcl_IsTableStructuredRef(const OUString& sRefStr, sal_Int32& nIndex)
{
    nIndex = ScGlobal::FindUnquoted(sRefStr, '[');
    return (nIndex > 0 && ScGlobal::FindUnquoted(sRefStr, ']', nIndex + 1) > nIndex);
}

void ScInterpreter::ScIndirect()
{
    sal_uInt8 nParamCount = GetByte();
@@ -8217,6 +8223,10 @@ void ScInterpreter::ScIndirect()
    const ScAddress::Details aDetailsXlA1( FormulaGrammar::CONV_XL_A1, aPos );
    SCTAB nTab = aPos.Tab();

    bool bTableRefNamed = false;
    sal_Int32 nTableRefNamedIndex = -1;
    OUString sTabRefStr;

    // Named expressions and DB range names need to be tried first, as older 1K
    // columns allowed names that would now match a 16k columns cell address.
    do
@@ -8232,8 +8242,14 @@ void ScInterpreter::ScIndirect()

        // This is the usual way to treat named ranges containing
        // relative references.
        if (!pData->IsReference( aRange, aPos))
        if (!pData->IsReference(aRange, aPos))
        {
            sTabRefStr = pData->GetSymbol();
            bTableRefNamed = lcl_IsTableStructuredRef(sTabRefStr, nTableRefNamedIndex);
            // if bTableRefNamed is true, we have a name that maps to a table structured reference.
            // Such a case is handled below.
            break;
        }

        if (aRange.aStart == aRange.aEnd)
            PushSingleRef( aRange.aStart.Col(), aRange.aStart.Row(),
@@ -8250,6 +8266,9 @@ void ScInterpreter::ScIndirect()

    do
    {
        if (bTableRefNamed)
            break;

        const OUString & aName( sSharedRefStr.getIgnoreCaseString() );
        ScDBCollection::NamedDBs& rDBs = mrDoc.GetDBCollection()->getNamedDBs();
        const ScDBData* pData = rDBs.findByUpperName( aName);
@@ -8285,9 +8304,10 @@ void ScInterpreter::ScIndirect()

    ScRefAddress aRefAd, aRefAd2;
    ScAddress::ExternalInfo aExtInfo;
    if ( ConvertDoubleRef(mrDoc, sRefStr, nTab, aRefAd, aRefAd2, aDetails, &aExtInfo) ||
         ( bTryXlA1 && ConvertDoubleRef(mrDoc, sRefStr, nTab, aRefAd,
                                        aRefAd2, aDetailsXlA1, &aExtInfo) ) )
    if ( !bTableRefNamed &&
         (ConvertDoubleRef(mrDoc, sRefStr, nTab, aRefAd, aRefAd2, aDetails, &aExtInfo) ||
            ( bTryXlA1 && ConvertDoubleRef(mrDoc, sRefStr, nTab, aRefAd,
                                           aRefAd2, aDetailsXlA1, &aExtInfo) ) ) )
    {
        if (aExtInfo.mbExternal)
        {
@@ -8299,9 +8319,10 @@ void ScInterpreter::ScIndirect()
        else
            PushDoubleRef( aRefAd, aRefAd2);
    }
    else if ( ConvertSingleRef(mrDoc, sRefStr, nTab, aRefAd, aDetails, &aExtInfo) ||
              ( bTryXlA1 && ConvertSingleRef (mrDoc, sRefStr, nTab, aRefAd,
                                              aDetailsXlA1, &aExtInfo) ) )
    else if ( !bTableRefNamed &&
              (ConvertSingleRef(mrDoc, sRefStr, nTab, aRefAd, aDetails, &aExtInfo) ||
                ( bTryXlA1 && ConvertSingleRef (mrDoc, sRefStr, nTab, aRefAd,
                                                aDetailsXlA1, &aExtInfo) ) ) )
    {
        if (aExtInfo.mbExternal)
        {
@@ -8317,8 +8338,10 @@ void ScInterpreter::ScIndirect()
        // Anything else that resolves to one reference could be added
        // here, but we don't want to compile every arbitrary string. This
        // is already nasty enough...
        sal_Int32 nIndex = ScGlobal::FindUnquoted( sRefStr, '[');
        const bool bTableRef = (nIndex > 0 && ScGlobal::FindUnquoted( sRefStr, ']', nIndex+1) > nIndex);
        sal_Int32 nIndex = bTableRefNamed ? nTableRefNamedIndex : -1;
        bool bTableRef = bTableRefNamed;
        if (!bTableRefNamed)
            bTableRef = lcl_IsTableStructuredRef(sRefStr, nIndex);
        bool bExternalName = false;     // External references would had been consumed above already.
        if (!bTableRef)
        {
@@ -8355,7 +8378,7 @@ void ScInterpreter::ScIndirect()
            {
                ScCompiler aComp( mrDoc, aPos, mrDoc.GetGrammar());
                aComp.SetRefConvention( eConv);     // must be after grammar
                std::unique_ptr<ScTokenArray> pTokArr( aComp.CompileString( sRefStr));
                std::unique_ptr<ScTokenArray> pTokArr( aComp.CompileString(bTableRefNamed ? sTabRefStr : sRefStr));

                if (pTokArr->GetCodeError() != FormulaError::NONE || !pTokArr->GetLen())
                    break;