Resolves: tdf#96915 implement other-sheet-local named expressions

Change-Id: I0d62536caa6eb455473a755067abc585662cd9a5
diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx
index 22d3c84..7009d94 100644
--- a/formula/source/core/api/token.cxx
+++ b/formula/source/core/api/token.cxx
@@ -221,15 +221,15 @@ void FormulaToken::SetIndex( sal_uInt16 )
    SAL_WARN( "formula.core", "FormulaToken::SetIndex: virtual dummy called" );
}

bool FormulaToken::IsGlobal() const
sal_Int16 FormulaToken::GetSheet() const
{
    SAL_WARN( "formula.core", "FormulaToken::IsGlobal: virtual dummy called" );
    return true;
    SAL_WARN( "formula.core", "FormulaToken::GetSheet: virtual dummy called" );
    return -1;
}

void FormulaToken::SetGlobal( bool )
void FormulaToken::SetSheet( sal_Int16 )
{
    SAL_WARN( "formula.core", "FormulaToken::SetGlobal: virtual dummy called" );
    SAL_WARN( "formula.core", "FormulaToken::SetSheet: virtual dummy called" );
}

short* FormulaToken::GetJump() const
@@ -1724,12 +1724,12 @@ bool FormulaStringOpToken::operator==( const FormulaToken& r ) const

sal_uInt16  FormulaIndexToken::GetIndex() const             { return nIndex; }
void        FormulaIndexToken::SetIndex( sal_uInt16 n )     { nIndex = n; }
bool        FormulaIndexToken::IsGlobal() const             { return mbGlobal; }
void        FormulaIndexToken::SetGlobal( bool b )          { mbGlobal = b; }
sal_Int16   FormulaIndexToken::GetSheet() const             { return mnSheet; }
void        FormulaIndexToken::SetSheet( sal_Int16 n )      { mnSheet = n; }
bool FormulaIndexToken::operator==( const FormulaToken& r ) const
{
    return FormulaToken::operator==( r ) && nIndex == r.GetIndex() &&
        mbGlobal == r.IsGlobal();
        mnSheet == r.GetSheet();
}
const OUString& FormulaExternalToken::GetExternal() const       { return aExternal; }
sal_uInt8       FormulaExternalToken::GetByte() const           { return nByte; }
diff --git a/include/formula/token.hxx b/include/formula/token.hxx
index 618168e..e0cd6b7 100644
--- a/include/formula/token.hxx
+++ b/include/formula/token.hxx
@@ -154,8 +154,8 @@ public:
    virtual void                SetString( const svl::SharedString& rStr );
    virtual sal_uInt16          GetIndex() const;
    virtual void                SetIndex( sal_uInt16 n );
    virtual bool                IsGlobal() const;
    virtual void                SetGlobal( bool b );
    virtual sal_Int16           GetSheet() const;
    virtual void                SetSheet( sal_Int16 n );
    virtual short*              GetJump() const;
    virtual const OUString&     GetExternal() const;
    virtual FormulaToken*       GetFAPOrigToken() const;
@@ -310,18 +310,18 @@ class FORMULA_DLLPUBLIC FormulaIndexToken : public FormulaToken
{
private:
            sal_uInt16          nIndex;
            bool                mbGlobal;
            sal_Int16           mnSheet;
public:
                                FormulaIndexToken( OpCode e, sal_uInt16 n, bool bGlobal = true ) :
                                    FormulaToken(  svIndex, e ), nIndex( n ), mbGlobal( bGlobal ) {}
                                FormulaIndexToken( OpCode e, sal_uInt16 n, sal_Int16 nSheet = -1 ) :
                                    FormulaToken(  svIndex, e ), nIndex( n ), mnSheet( nSheet ) {}
                                FormulaIndexToken( const FormulaIndexToken& r ) :
                                    FormulaToken( r ), nIndex( r.nIndex ), mbGlobal( r.mbGlobal ) {}
                                    FormulaToken( r ), nIndex( r.nIndex ), mnSheet( r.mnSheet ) {}

    virtual FormulaToken*       Clone() const override { return new FormulaIndexToken(*this); }
    virtual sal_uInt16          GetIndex() const override;
    virtual void                SetIndex( sal_uInt16 n ) override;
    virtual bool                IsGlobal() const override;
    virtual void                SetGlobal( bool b ) override;
    virtual sal_Int16           GetSheet() const override;
    virtual void                SetSheet( sal_Int16 n ) override;
    virtual bool                operator==( const FormulaToken& rToken ) const override;
};

diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx
index a917de7..218f346 100644
--- a/sc/inc/address.hxx
+++ b/sc/inc/address.hxx
@@ -308,11 +308,19 @@ public:
        nTabP = nTab;
    }

    /**
        @param  pSheetEndPos
                If given and Parse() sucessfully parsed a sheet name it returns
                the end position (exclusive) behind the sheet name AND a
                following sheet name separator. This independent of whether the
                resulting reference is fully valid or not.
     */
    SC_DLLPUBLIC ScRefFlags Parse(
                    const OUString&, ScDocument* = nullptr,
                    const Details& rDetails = detailsOOOa1,
                    ExternalInfo* pExtInfo = nullptr,
                    const css::uno::Sequence<css::sheet::ExternalLinkInfo>* pExternalLinks = nullptr );
                    const css::uno::Sequence<css::sheet::ExternalLinkInfo>* pExternalLinks = nullptr,
                    sal_Int32* pSheetEndPos = nullptr );

    SC_DLLPUBLIC void Format( OStringBuffer& r, ScRefFlags nFlags = ScRefFlags::ZERO,
                                  const ScDocument* pDocument = nullptr,
diff --git a/sc/inc/compiler.hxx b/sc/inc/compiler.hxx
index 2af43e4..e1887aa 100644
--- a/sc/inc/compiler.hxx
+++ b/sc/inc/compiler.hxx
@@ -120,7 +120,7 @@ public:
            sal_Unicode cName[MAXSTRLEN+1];
        } extname;
        struct {
            bool        bGlobal;
            sal_Int16   nSheet;
            sal_uInt16  nIndex;
        } name;
        struct {
@@ -157,7 +157,7 @@ public:
    void SetErrorConstant( sal_uInt16 nErr );

    // These methods are ok to use, reference count not cleared.
    void SetName(bool bGlobal, sal_uInt16 nIndex);
    void SetName(sal_Int16 nSheet, sal_uInt16 nIndex);
    void SetExternalSingleRef( sal_uInt16 nFileId, const OUString& rTabName, const ScSingleRefData& rRef );
    void SetExternalDoubleRef( sal_uInt16 nFileId, const OUString& rTabName, const ScComplexRefData& rRef );
    void SetExternalName( sal_uInt16 nFileId, const OUString& rName );
@@ -272,6 +272,9 @@ private:

    SvNumberFormatter* mpFormatter;

    SCTAB       mnCurrentSheetTab;      // indicates current sheet number parsed so far
    sal_Int32   mnCurrentSheetEndPos;   // position after current sheet name if parsed

    // For CONV_XL_OOX, may be set via API by MOOXML filter.
    css::uno::Sequence<css::sheet::ExternalLinkInfo> maExternalLinks;

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 7da2b4d..825e511 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -535,6 +535,15 @@ public:
    void SetRangeName(SCTAB nTab, ScRangeName* pNew);
    void SetRangeName( ScRangeName* pNewRangeName );

    /** Find a named expression / range name in either global or a local scope.
        @param  nIndex
                Index of named expression / range name.
        @param  nTab
                If <0 search nIndex in global scope, if >=0 search nIndex in scope of nTab.
        @return nullptr if indexed name not found.
     */
    ScRangeData* FindRangeNameByIndexAndSheet( sal_uInt16 nIndex, SCTAB nTab ) const;

    /**
     * Call this immediately before updating all named ranges.
     */
diff --git a/sc/inc/token.hxx b/sc/inc/token.hxx
index 63c5ec7..b056d41 100644
--- a/sc/inc/token.hxx
+++ b/sc/inc/token.hxx
@@ -231,7 +231,7 @@ public:

    virtual sal_uInt16          GetIndex() const override;
    virtual void                SetIndex( sal_uInt16 n ) override;
    virtual bool                IsGlobal() const override;
    virtual sal_Int16           GetSheet() const override;
    virtual bool                operator==( const formula::FormulaToken& rToken ) const override;
    virtual FormulaToken*       Clone() const override { return new ScTableRefToken(*this); }

diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index 26d6ca4..e495346 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -95,7 +95,7 @@ public:
    /** ScSingleRefOpToken with ocMatRef. */
    formula::FormulaToken* AddMatrixSingleReference( const ScSingleRefData& rRef );
    formula::FormulaToken* AddDoubleReference( const ScComplexRefData& rRef );
    formula::FormulaToken* AddRangeName( sal_uInt16 n, bool bGlobal );
    formula::FormulaToken* AddRangeName( sal_uInt16 n, sal_Int16 nSheet );
    formula::FormulaToken* AddDBRange( sal_uInt16 n );
    formula::FormulaToken* AddExternalName( sal_uInt16 nFileId, const OUString& rName );
    void AddExternalSingleReference( sal_uInt16 nFileId, const OUString& rTabName, const ScSingleRefData& rRef );
diff --git a/sc/source/core/data/conditio.cxx b/sc/source/core/data/conditio.cxx
index b67b04f..84de73c 100644
--- a/sc/source/core/data/conditio.cxx
+++ b/sc/source/core/data/conditio.cxx
@@ -107,7 +107,7 @@ static bool lcl_HasRelRef( ScDocument* pDoc, ScTokenArray* pFormula, sal_uInt16 
                case svIndex:
                {
                    if( t->GetOpCode() == ocName )      // DB areas always absolute
                        if( ScRangeData* pRangeData = pDoc->GetRangeName()->findByIndex( t->GetIndex() ) )
                        if( ScRangeData* pRangeData = pDoc->FindRangeNameByIndexAndSheet( t->GetIndex(), t->GetSheet()) )
                            if( (nRecursion < 42) && lcl_HasRelRef( pDoc, pRangeData->GetCode(), nRecursion + 1 ) )
                                return true;
                }
diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx
index 9f10d88..bada3af 100644
--- a/sc/source/core/data/documen3.cxx
+++ b/sc/source/core/data/documen3.cxx
@@ -234,6 +234,12 @@ const ScRangeData* ScDocument::GetRangeAtBlock( const ScRange& rBlock, OUString*
    return pData;
}

ScRangeData* ScDocument::FindRangeNameByIndexAndSheet( sal_uInt16 nIndex, SCTAB nTab ) const
{
    const ScRangeName* pRN = (nTab < 0 ? GetRangeName() : GetRangeName(nTab));
    return (pRN ? pRN->findByIndex( nIndex) : nullptr);
}

void ScDocument::SetDBCollection( ScDBCollection* pNewDBCollection, bool bRemoveAutoFilter )
{
    if (pDBCollection && bRemoveAutoFilter)
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index c97e330..0db0ab4 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -422,16 +422,22 @@ bool lcl_isReference(const FormulaToken& rToken)

void adjustRangeName(formula::FormulaToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldDoc, const ScAddress& aNewPos, const ScAddress& aOldPos)
{
    bool bOldGlobal = pToken->IsGlobal();
    SCTAB aOldTab = aOldPos.Tab();
    bool bSameDoc = (rNewDoc.GetPool() == const_cast<ScDocument*>(pOldDoc)->GetPool());
    SCTAB nOldSheet = pToken->GetSheet();
    if (bSameDoc && (nOldSheet < 0 || nOldSheet != aOldPos.Tab()))
        // Same doc and global name or sheet-local name on other sheet stays
        // the same.
        return;

    OUString aRangeName;
    int nOldIndex = pToken->GetIndex();
    ScRangeData* pOldRangeData = nullptr;

    //search the name of the RangeName
    if (!bOldGlobal)
    if (nOldSheet >= 0)
    {
        pOldRangeData = pOldDoc->GetRangeName(aOldTab)->findByIndex(nOldIndex);
        const ScRangeName* pRangeName = pOldDoc->GetRangeName(nOldSheet);
        pOldRangeData = pRangeName ? pRangeName->findByIndex(nOldIndex) : nullptr;
        if (!pOldRangeData)
            return;     //might be an error in the formula array
        aRangeName = pOldRangeData->GetUpperName();
@@ -444,12 +450,15 @@ void adjustRangeName(formula::FormulaToken* pToken, ScDocument& rNewDoc, const S
        aRangeName = pOldRangeData->GetUpperName();
    }

    SAL_WARN_IF( !bSameDoc && nOldSheet >= 0 && nOldSheet != aOldPos.Tab(),
            "sc.core", "adjustRangeName - sheet-local name was on other sheet in other document");
    /* TODO: can we do something about that? e.g. loop over sheets? */

    //find corresponding range name in new document
    //first search for local range name then global range names
    SCTAB aNewTab = aNewPos.Tab();
    ScRangeName* pRangeName = rNewDoc.GetRangeName(aNewTab);
    SCTAB nNewSheet = aNewPos.Tab();
    ScRangeName* pRangeName = rNewDoc.GetRangeName(nNewSheet);
    ScRangeData* pRangeData = nullptr;
    bool bNewGlobal = false;
    //search local range names
    if (pRangeName)
    {
@@ -458,7 +467,7 @@ void adjustRangeName(formula::FormulaToken* pToken, ScDocument& rNewDoc, const S
    //search global range names
    if (!pRangeData)
    {
        bNewGlobal = true;
        nNewSheet = -1;
        pRangeName = rNewDoc.GetRangeName();
        if (pRangeName)
            pRangeData = pRangeName->findByUpperName(aRangeName);
@@ -466,21 +475,24 @@ void adjustRangeName(formula::FormulaToken* pToken, ScDocument& rNewDoc, const S
    //if no range name was found copy it
    if (!pRangeData)
    {
        bNewGlobal = bOldGlobal;
        if (nOldSheet < 0)
            nNewSheet = -1;
        else
            nNewSheet = aNewPos.Tab();
        pRangeData = new ScRangeData(*pOldRangeData, &rNewDoc);
        pRangeData->SetIndex(0);    // needed for insert to assign a new index
        ScTokenArray* pRangeNameToken = pRangeData->GetCode();
        if (rNewDoc.GetPool() != const_cast<ScDocument*>(pOldDoc)->GetPool())
        if (!bSameDoc)
        {
            pRangeNameToken->ReadjustAbsolute3DReferences(pOldDoc, &rNewDoc, pRangeData->GetPos(), true);
            pRangeNameToken->AdjustAbsoluteRefs(pOldDoc, aOldPos, aNewPos, false, true);
        }

        bool bInserted;
        if (bNewGlobal)
        if (nNewSheet < 0)
            bInserted = rNewDoc.GetRangeName()->insert(pRangeData);
        else
            bInserted = rNewDoc.GetRangeName(aNewTab)->insert(pRangeData);
            bInserted = rNewDoc.GetRangeName(nNewSheet)->insert(pRangeData);
        if (!bInserted)
        {
            //if this happened we have a real problem
@@ -492,7 +504,7 @@ void adjustRangeName(formula::FormulaToken* pToken, ScDocument& rNewDoc, const S
    }
    sal_Int32 nIndex = pRangeData->GetIndex();
    pToken->SetIndex(nIndex);
    pToken->SetGlobal(bNewGlobal);
    pToken->SetSheet(nNewSheet);
}

void adjustDBRange(formula::FormulaToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldDoc)
@@ -3603,7 +3615,7 @@ void ScFormulaCell::UpdateTranspose( const ScRange& rSource, const ScAddress& rD
    {
        if( t->GetOpCode() == ocName )
        {
            ScRangeData* pName = pDocument->GetRangeName()->findByIndex( t->GetIndex() );
            const ScRangeData* pName = pDocument->FindRangeNameByIndexAndSheet( t->GetIndex(), t->GetSheet());
            if (pName)
            {
                if (pName->IsModified())
@@ -3657,7 +3669,7 @@ void ScFormulaCell::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY
    {
        if( t->GetOpCode() == ocName )
        {
            ScRangeData* pName = pDocument->GetRangeName()->findByIndex( t->GetIndex() );
            const ScRangeData* pName = pDocument->FindRangeNameByIndexAndSheet( t->GetIndex(), t->GetSheet());
            if (pName)
            {
                if (pName->IsModified())
@@ -3694,6 +3706,12 @@ static void lcl_FindRangeNamesInUse(std::set<sal_uInt16>& rIndexes, ScTokenArray
    {
        if (p->GetOpCode() == ocName)
        {
            /* TODO: this should collect also sheet-local names, currently it
             * collects only global names. But looking even for indexes of
             * local names.. this always was wrong. Probably use
             * UpdatedRangeNames instead of the set, but doing so would also
             * need more work in copying things over clipboard and such. */

            sal_uInt16 nTokenIndex = p->GetIndex();
            rIndexes.insert( nTokenIndex );

diff --git a/sc/source/core/data/validat.cxx b/sc/source/core/data/validat.cxx
index 2535990a..278ae4e 100644
--- a/sc/source/core/data/validat.cxx
+++ b/sc/source/core/data/validat.cxx
@@ -694,7 +694,7 @@ bool ScValidationData::GetSelectionFromFormula(
        }
        else if (eOpCode == ocName)
        {
            ScRangeData* pName = pDocument->GetRangeName()->findByIndex( t->GetIndex() );
            const ScRangeData* pName = pDocument->FindRangeNameByIndexAndSheet( t->GetIndex(), t->GetSheet());
            if (pName && pName->IsReference(aRange))
            {
                bRef = true;
diff --git a/sc/source/core/tool/address.cxx b/sc/source/core/tool/address.cxx
index ef2e492..c016102 100644
--- a/sc/source/core/tool/address.cxx
+++ b/sc/source/core/tool/address.cxx
@@ -704,8 +704,12 @@ static ScRefFlags lcl_ScRange_Parse_XL_R1C1( ScRange& r,
                                             ScDocument* pDoc,
                                             const ScAddress::Details& rDetails,
                                             bool bOnlyAcceptSingle,
                                             ScAddress::ExternalInfo* pExtInfo )
                                             ScAddress::ExternalInfo* pExtInfo,
                                             sal_Int32* pSheetEndPos )
{
    const sal_Unicode* const pStart = p;
    if (pSheetEndPos)
        *pSheetEndPos = 0;
    const sal_Unicode* pTmp = nullptr;
    OUString aExternDocName, aStartTabName, aEndTabName;
    ScRefFlags nFlags = ScRefFlags::VALID | ScRefFlags::TAB_VALID;
@@ -715,6 +719,13 @@ static ScRefFlags lcl_ScRange_Parse_XL_R1C1( ScRange& r,
    p = r.Parse_XL_Header( p, pDoc, aExternDocName, aStartTabName,
            aEndTabName, nFlags, bOnlyAcceptSingle );

    ScRefFlags nBailOutFlags = ScRefFlags::ZERO;
    if (pSheetEndPos && pStart < p && (nFlags & ScRefFlags::TAB_VALID) && (nFlags & ScRefFlags::TAB_3D))
    {
        *pSheetEndPos = p - pStart;
        nBailOutFlags = ScRefFlags::TAB_VALID | ScRefFlags::TAB_3D;
    }

    if (!aExternDocName.isEmpty())
        lcl_ScRange_External_TabSpan( r, nFlags, pExtInfo, aExternDocName,
                aStartTabName, aEndTabName, pDoc);
@@ -725,7 +736,7 @@ static ScRefFlags lcl_ScRange_Parse_XL_R1C1( ScRange& r,
    if( *p == 'R' || *p == 'r' )
    {
        if( nullptr == (p = lcl_r1c1_get_row( p, rDetails, &r.aStart, &nFlags )) )
            return ScRefFlags::ZERO;
            return nBailOutFlags;

        if( *p != 'C' && *p != 'c' )    // full row R#
        {
@@ -800,7 +811,7 @@ static ScRefFlags lcl_ScRange_Parse_XL_R1C1( ScRange& r,
    else if( *p == 'C' || *p == 'c' )   // full col C#
    {
        if( nullptr == (p = lcl_r1c1_get_col( p, rDetails, &r.aStart, &nFlags )))
            return ScRefFlags::ZERO;
            return nBailOutFlags;

        if( p[0] != ':' || (p[1] != 'C' && p[1] != 'c') ||
            nullptr == (pTmp = lcl_r1c1_get_col( p+1, rDetails, &r.aEnd, &nFlags2 )))
@@ -831,7 +842,7 @@ static ScRefFlags lcl_ScRange_Parse_XL_R1C1( ScRange& r,
        return bOnlyAcceptSingle ? ScRefFlags::ZERO : nFlags;
    }

    return ScRefFlags::ZERO;
    return nBailOutFlags;
}

static inline const sal_Unicode* lcl_a1_get_col( const sal_Unicode* p,
@@ -897,8 +908,12 @@ static ScRefFlags lcl_ScRange_Parse_XL_A1( ScRange& r,
                                           ScDocument* pDoc,
                                           bool bOnlyAcceptSingle,
                                           ScAddress::ExternalInfo* pExtInfo,
                                           const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks )
                                           const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks,
                                           sal_Int32* pSheetEndPos )
{
    const sal_Unicode* const pStart = p;
    if (pSheetEndPos)
        *pSheetEndPos = 0;
    const sal_Unicode* tmp1, *tmp2;
    OUString aExternDocName, aStartTabName, aEndTabName; // for external link table
    ScRefFlags nFlags = ScRefFlags::VALID | ScRefFlags::TAB_VALID, nFlags2 = ScRefFlags::TAB_VALID;
@@ -906,29 +921,36 @@ static ScRefFlags lcl_ScRange_Parse_XL_A1( ScRange& r,
    p = r.Parse_XL_Header( p, pDoc, aExternDocName, aStartTabName,
            aEndTabName, nFlags, bOnlyAcceptSingle, pExternalLinks );

    ScRefFlags nBailOutFlags = ScRefFlags::ZERO;
    if (pSheetEndPos && pStart < p && (nFlags & ScRefFlags::TAB_VALID) && (nFlags & ScRefFlags::TAB_3D))
    {
        *pSheetEndPos = p - pStart;
        nBailOutFlags = ScRefFlags::TAB_VALID | ScRefFlags::TAB_3D;
    }

    if (!aExternDocName.isEmpty())
        lcl_ScRange_External_TabSpan( r, nFlags, pExtInfo, aExternDocName,
                aStartTabName, aEndTabName, pDoc);

    if( nullptr == p )
        return ScRefFlags::ZERO;
        return nBailOutFlags;

    tmp1 = lcl_a1_get_col( p, &r.aStart, &nFlags );
    if( tmp1 == nullptr )          // Is it a row only reference 3:5
    {
        if( bOnlyAcceptSingle ) // by definition full row refs are ranges
            return ScRefFlags::ZERO;
            return nBailOutFlags;

        tmp1 = lcl_a1_get_row( p, &r.aStart, &nFlags );

        tmp1 = lcl_eatWhiteSpace( tmp1 );
        if( !tmp1 || *tmp1++ != ':' ) // Even a singleton requires ':' (eg 2:2)
            return ScRefFlags::ZERO;
            return nBailOutFlags;

        tmp1 = lcl_eatWhiteSpace( tmp1 );
        tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2 );
        if( !tmp2 || *tmp2 != 0 )   // Must have fully parsed a singleton.
            return ScRefFlags::ZERO;
            return nBailOutFlags;

        r.aStart.SetCol( 0 ); r.aEnd.SetCol( MAXCOL );
        nFlags |=
@@ -942,16 +964,16 @@ static ScRefFlags lcl_ScRange_Parse_XL_A1( ScRange& r,
    if( tmp2 == nullptr )          // check for col only reference F:H
    {
        if( bOnlyAcceptSingle ) // by definition full col refs are ranges
            return ScRefFlags::ZERO;
            return nBailOutFlags;

        tmp1 = lcl_eatWhiteSpace( tmp1 );
        if( *tmp1++ != ':' )    // Even a singleton requires ':' (eg F:F)
            return ScRefFlags::ZERO;
            return nBailOutFlags;

        tmp1 = lcl_eatWhiteSpace( tmp1 );
        tmp2 = lcl_a1_get_col( tmp1, &r.aEnd, &nFlags2 );
        if( !tmp2 || *tmp2 != 0 )   // Must have fully parsed a singleton.
            return ScRefFlags::ZERO;
            return nBailOutFlags;

        r.aStart.SetRow( 0 ); r.aEnd.SetRow( MAXROW );
        nFlags |=
@@ -1047,8 +1069,13 @@ static ScRefFlags lcl_ScRange_Parse_XL_A1( ScRange& r,
 */
static ScRefFlags lcl_ScAddress_Parse_OOo( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr,
                                           ScRefFlags& rRawRes,
                                           ScAddress::ExternalInfo* pExtInfo = nullptr, ScRange* pRange = nullptr )
                                           ScAddress::ExternalInfo* pExtInfo,
                                           ScRange* pRange,
                                           sal_Int32* pSheetEndPos )
{
    const sal_Unicode* const pStart = p;
    if (pSheetEndPos)
        *pSheetEndPos = 0;
    ScRefFlags  nRes = ScRefFlags::ZERO;
    rRawRes = ScRefFlags::ZERO;
    OUString aDocName;       // the pure Document Name
@@ -1061,7 +1088,6 @@ static ScRefFlags lcl_ScAddress_Parse_OOo( const sal_Unicode* p, ScDocument* pDo
    // document name is always quoted and has a trailing #.
    if (*p == '\'')
    {
        const sal_Unicode* pStart = p;
        OUString aTmp;
        p = parseQuotedName(p, aTmp);
        aDocName = aTmp;
@@ -1081,7 +1107,8 @@ static ScRefFlags lcl_ScAddress_Parse_OOo( const sal_Unicode* p, ScDocument* pDo
    SCCOL   nCol = 0;
    SCROW   nRow = 0;
    SCTAB   nTab = 0;
    ScRefFlags  nBits = ScRefFlags::TAB_VALID;
    ScRefFlags nBailOutFlags = ScRefFlags::ZERO;
    ScRefFlags nBits = ScRefFlags::TAB_VALID;
    const sal_Unicode* q;
    if ( ScGlobal::FindUnquoted( p, '.') )
    {
@@ -1121,6 +1148,12 @@ static ScRefFlags lcl_ScAddress_Parse_OOo( const sal_Unicode* p, ScDocument* pDo
        if( *p++ != '.' )
            nBits = ScRefFlags::ZERO;

        if (pSheetEndPos && (nBits & ScRefFlags::TAB_VALID))
        {
            *pSheetEndPos = p - pStart;
            nBailOutFlags = ScRefFlags::TAB_VALID | ScRefFlags::TAB_3D;
        }

        if (!bExtDoc && (!pDoc || !pDoc->GetTable( aTab, nTab )))
        {
            // Specified table name is not found in this document.  Assume this is an external document.
@@ -1305,14 +1338,15 @@ static ScRefFlags lcl_ScAddress_Parse_OOo( const sal_Unicode* p, ScDocument* pDo
            nRes |= ScRefFlags::VALID;
    }
    else
        nRes = ScRefFlags::ZERO;
        nRes = nBailOutFlags;
    return nRes;
}

static ScRefFlags lcl_ScAddress_Parse ( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr,
                                        const ScAddress::Details& rDetails,
                                        ScAddress::ExternalInfo* pExtInfo = nullptr,
                                        const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks = nullptr )
                                        const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks = nullptr,
                                        sal_Int32* pSheetEndPos = nullptr )
{
    if( !*p )
        return ScRefFlags::ZERO;
@@ -1324,15 +1358,16 @@ static ScRefFlags lcl_ScAddress_Parse ( const sal_Unicode* p, ScDocument* pDoc, 
        {
            ScRange rRange = rAddr;
            ScRefFlags nFlags = lcl_ScRange_Parse_XL_A1(
                                    rRange, p, pDoc, true, pExtInfo,
                                    (rDetails.eConv == formula::FormulaGrammar::CONV_XL_OOX ? pExternalLinks : nullptr) );
                    rRange, p, pDoc, true, pExtInfo,
                    (rDetails.eConv == formula::FormulaGrammar::CONV_XL_OOX ? pExternalLinks : nullptr),
                    pSheetEndPos);
            rAddr = rRange.aStart;
            return nFlags;
        }
        case formula::FormulaGrammar::CONV_XL_R1C1:
        {
            ScRange rRange = rAddr;
            ScRefFlags nFlags = lcl_ScRange_Parse_XL_R1C1( rRange, p, pDoc, rDetails, true, pExtInfo );
            ScRefFlags nFlags = lcl_ScRange_Parse_XL_R1C1( rRange, p, pDoc, rDetails, true, pExtInfo, pSheetEndPos);
            rAddr = rRange.aStart;
            return nFlags;
        }
@@ -1340,7 +1375,7 @@ static ScRefFlags lcl_ScAddress_Parse ( const sal_Unicode* p, ScDocument* pDoc, 
        case formula::FormulaGrammar::CONV_OOO:
        {
            ScRefFlags nRawRes = ScRefFlags::ZERO;
            return lcl_ScAddress_Parse_OOo( p, pDoc, rAddr, nRawRes, pExtInfo );
            return lcl_ScAddress_Parse_OOo( p, pDoc, rAddr, nRawRes, pExtInfo, nullptr, pSheetEndPos);
        }
    }
}
@@ -1396,9 +1431,10 @@ bool ConvertDoubleRef( ScDocument* pDoc, const OUString& rRefString, SCTAB nDefT
ScRefFlags ScAddress::Parse( const OUString& r, ScDocument* pDoc,
                             const Details& rDetails,
                             ExternalInfo* pExtInfo,
                             const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks )
                             const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks,
                             sal_Int32* pSheetEndPos )
{
    return lcl_ScAddress_Parse( r.getStr(), pDoc, *this, rDetails, pExtInfo, pExternalLinks );
    return lcl_ScAddress_Parse( r.getStr(), pDoc, *this, rDetails, pExtInfo, pExternalLinks, pSheetEndPos );
}

bool ScRange::Intersects( const ScRange& rRange ) const
@@ -1476,13 +1512,14 @@ static ScRefFlags lcl_ScRange_Parse_OOo( ScRange& rRange,
        aTmp[nPos] = 0;
        const sal_Unicode* p = aTmp.getStr();
        ScRefFlags nRawRes1 = ScRefFlags::ZERO;
        if (((nRes1 = lcl_ScAddress_Parse_OOo( p, pDoc, rRange.aStart, nRawRes1, pExtInfo)) != ScRefFlags::ZERO) ||
        nRes1 = lcl_ScAddress_Parse_OOo( p, pDoc, rRange.aStart, nRawRes1, pExtInfo, nullptr, nullptr);
        if ((nRes1 != ScRefFlags::ZERO) ||
                ((nRawRes1 & (ScRefFlags::COL_VALID | ScRefFlags::ROW_VALID)) &&
                 (nRawRes1 & ScRefFlags::TAB_VALID)))
        {
            rRange.aEnd = rRange.aStart;  // sheet must be initialized identical to first sheet
            ScRefFlags nRawRes2 = ScRefFlags::ZERO;
            nRes2 = lcl_ScAddress_Parse_OOo( p + nPos+ 1, pDoc, rRange.aEnd, nRawRes2, pExtInfo, &rRange);
            nRes2 = lcl_ScAddress_Parse_OOo( p + nPos+ 1, pDoc, rRange.aEnd, nRawRes2, pExtInfo, &rRange, nullptr);
            if (!((nRes1 & ScRefFlags::VALID) && (nRes2 & ScRefFlags::VALID)) &&
                    // If not fully valid addresses, check if both have a valid
                    // column or row, and both have valid (or omitted) sheet references.
@@ -1596,12 +1633,12 @@ ScRefFlags ScRange::Parse( const OUString& rString, ScDocument* pDoc,
        case formula::FormulaGrammar::CONV_XL_OOX:
        {
            return lcl_ScRange_Parse_XL_A1( *this, rString.getStr(), pDoc, false, pExtInfo,
                    (rDetails.eConv == formula::FormulaGrammar::CONV_XL_OOX ? pExternalLinks : nullptr) );
                    (rDetails.eConv == formula::FormulaGrammar::CONV_XL_OOX ? pExternalLinks : nullptr), nullptr );
        }

        case formula::FormulaGrammar::CONV_XL_R1C1:
        {
            return lcl_ScRange_Parse_XL_R1C1( *this, rString.getStr(), pDoc, rDetails, false, pExtInfo );
            return lcl_ScRange_Parse_XL_R1C1( *this, rString.getStr(), pDoc, rDetails, false, pExtInfo, nullptr );
        }

        default:
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index 2f88dd9..c57f192 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -2892,14 +2892,34 @@ bool ScCompiler::IsDoubleReference( const OUString& rName )

bool ScCompiler::IsSingleReference( const OUString& rName )
{
    mnCurrentSheetEndPos = 0;
    mnCurrentSheetTab = -1;
    ScAddress aAddr( aPos );
    const ScAddress::Details aDetails( pConv->meConv, aPos );
    ScAddress::ExternalInfo aExtInfo;
    ScRefFlags nFlags = aAddr.Parse( rName, pDoc, aDetails, &aExtInfo, &maExternalLinks );
    ScRefFlags nFlags = aAddr.Parse( rName, pDoc, aDetails, &aExtInfo, &maExternalLinks, &mnCurrentSheetEndPos);
    // Something must be valid in order to recognize Sheet1.blah or blah.a1
    // as a (wrong) reference.
    if( nFlags & ( ScRefFlags::COL_VALID|ScRefFlags::ROW_VALID|ScRefFlags::TAB_VALID ) )
    {
        // Valid given tab and invalid col or row may indicate a sheet-local
        // named expression, bail out early and don't create a reference token.
        if (!(nFlags & ScRefFlags::VALID) && mnCurrentSheetEndPos > 0 &&
                (nFlags & ScRefFlags::TAB_VALID) && (nFlags & ScRefFlags::TAB_3D))
        {
            if (aExtInfo.mbExternal)
            {
                // External names are handled separately.
                mnCurrentSheetEndPos = 0;
                mnCurrentSheetTab = -1;
            }
            else
            {
                mnCurrentSheetTab = aAddr.Tab();
            }
            return false;
        }

        ScSingleRefData aRef;
        aRef.InitAddress( aAddr );
        aRef.SetColRel( (nFlags & ScRefFlags::COL_ABS) == ScRefFlags::ZERO );
@@ -3093,8 +3113,8 @@ bool ScCompiler::IsNamedRange( const OUString& rUpperName )
    // IsNamedRange is called only from NextNewToken, with an upper-case string

    // try local names first
    bool bGlobal = false;
    ScRangeName* pRangeName = pDoc->GetRangeName(aPos.Tab());
    sal_Int16 nSheet = aPos.Tab();
    ScRangeName* pRangeName = pDoc->GetRangeName(nSheet);
    const ScRangeData* pData = nullptr;
    if (pRangeName)
        pData = pRangeName->findByUpperName(rUpperName);
@@ -3104,16 +3124,32 @@ bool ScCompiler::IsNamedRange( const OUString& rUpperName )
        if (pRangeName)
            pData = pRangeName->findByUpperName(rUpperName);
        if (pData)
            bGlobal = true;
            nSheet = -1;
    }

    if (pData)
    {
        maRawToken.SetName(bGlobal, pData->GetIndex());
        maRawToken.SetName( nSheet, pData->GetIndex());
        return true;
    }
    else
        return false;

    // Sheet-local name with sheet specified.
    if (mnCurrentSheetEndPos > 0 && mnCurrentSheetTab >= 0)
    {
        OUString aName( rUpperName.copy( mnCurrentSheetEndPos));
        pRangeName = pDoc->GetRangeName( mnCurrentSheetTab);
        if (pRangeName)
        {
            pData = pRangeName->findByUpperName(aName);
            if (pData)
            {
                maRawToken.SetName( mnCurrentSheetTab, pData->GetIndex());
                return true;
            }
        }
    }

    return false;
}

bool ScCompiler::IsExternalNamedRange( const OUString& rSymbol, bool& rbInvalidExternalNameRange )
@@ -3161,7 +3197,7 @@ bool ScCompiler::IsDBRange( const OUString& rName )
    if (!p)
        return false;

    maRawToken.SetName(true, p->GetIndex()); // DB range is always global.
    maRawToken.SetName( -1, p->GetIndex()); // DB range is always global.
    maRawToken.eOp = ocDBArea;
    return true;
}
@@ -4387,19 +4423,7 @@ ScTokenArray* ScCompiler::CompileString( const OUString& rFormula, const OUStrin

ScRangeData* ScCompiler::GetRangeData( const FormulaToken& rToken ) const
{
    ScRangeData* pRangeData = nullptr;
    bool bGlobal = rToken.IsGlobal();
    if (bGlobal)
        // global named range.
        pRangeData = pDoc->GetRangeName()->findByIndex( rToken.GetIndex());
    else
    {
        // sheet local named range.
        const ScRangeName* pRN = pDoc->GetRangeName( aPos.Tab());
        if (pRN)
            pRangeData = pRN->findByIndex( rToken.GetIndex());
    }
    return pRangeData;
    return pDoc->FindRangeNameByIndexAndSheet( rToken.GetIndex(), rToken.GetSheet());
}

bool ScCompiler::HandleRange()
@@ -4759,7 +4783,20 @@ void ScCompiler::CreateStringFromIndex( OUStringBuffer& rBuffer, const FormulaTo
        {
            const ScRangeData* pData = GetRangeData( *_pTokenP);
            if (pData)
            {
                SCTAB nTab = _pTokenP->GetSheet();
                if (nTab >= 0 && nTab != aPos.Tab())
                {
                    // Sheet-local on other sheet.
                    OUString aName;
                    if (pDoc->GetName( nTab, aName))
                        aBuffer.append( aName);
                    else
                        aBuffer.append( ScGlobal::GetRscString( STR_NO_NAME_REF));
                    aBuffer.append( pConv->getSpecialSymbol( ScCompiler::Convention::SHEET_SEPARATOR));
                }
                aBuffer.append(pData->GetName());
            }
        }
        break;
        case ocDBArea:
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 6a3f271..3d82694 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -293,12 +293,12 @@ void ScRawToken::SetErrorConstant( sal_uInt16 nErr )
    nError = nErr;
}

void ScRawToken::SetName(bool bGlobal, sal_uInt16 nIndex)
void ScRawToken::SetName(sal_Int16 nSheet, sal_uInt16 nIndex)
{
    eOp = ocName;
    eType = svIndex;

    name.bGlobal = bGlobal;
    name.nSheet = nSheet;
    name.nIndex = nIndex;
}

@@ -409,7 +409,7 @@ FormulaToken* ScRawToken::CreateToken() const
            if (eOp == ocTableRef)
                return new ScTableRefToken( table.nIndex, table.eItem);
            else
                return new FormulaIndexToken( eOp, name.nIndex, name.bGlobal);
                return new FormulaIndexToken( eOp, name.nIndex, name.nSheet);
        case svExternalSingleRef:
            {
                OUString aTabName(extref.cTabName);
@@ -933,13 +933,13 @@ void ScTableRefToken::SetIndex( sal_uInt16 n )
    mnIndex = n;
}

bool ScTableRefToken::IsGlobal() const
sal_Int16 ScTableRefToken::GetSheet() const
{
    // Code asking for this may have to be adapted as it might assume an
    // svIndex token would always be ocName or ocDBArea.
    SAL_WARN("sc.core","ScTableRefToken::IsGlobal - maybe adapt caller to know about TableRef?");
    SAL_WARN("sc.core","ScTableRefToken::GetSheet - maybe adapt caller to know about TableRef?");
    // Database range is always global.
    return true;
    return -1;
}

ScTableRefToken::Item ScTableRefToken::GetItem() const
@@ -1212,7 +1212,16 @@ bool ScTokenArray::AddFormulaToken(
                        sheet::NameToken aTokenData;
                        rToken.Data >>= aTokenData;
                        if ( eOpCode == ocName )
                            AddRangeName(aTokenData.Index, aTokenData.Global);
                        {
                            /* TODO: new token type with sheet number */
                            if (aTokenData.Global)
                                AddRangeName(aTokenData.Index, -1);
                            else
                                bError = true;
                            /* FIXME: resolve the non-global case to the
                             * current position's sheet as it implicitly was
                             * before, currently this is broken. */
                        }
                        else if (eOpCode == ocDBArea)
                            AddDBRange(aTokenData.Index);
                        else if (eOpCode == ocTableRef)
@@ -2059,9 +2068,9 @@ FormulaToken* ScTokenArray::AddMatrix( const ScMatrixRef& p )
    return Add( new ScMatrixToken( p ) );
}

FormulaToken* ScTokenArray::AddRangeName( sal_uInt16 n, bool bGlobal )
FormulaToken* ScTokenArray::AddRangeName( sal_uInt16 n, sal_Int16 nSheet )
{
    return Add( new FormulaIndexToken( ocName, n, bGlobal));
    return Add( new FormulaIndexToken( ocName, n, nSheet));
}

FormulaToken* ScTokenArray::AddDBRange( sal_uInt16 n )
@@ -2826,7 +2835,7 @@ bool expandRangeByEdge( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, co
bool isNameModified( const sc::UpdatedRangeNames& rUpdatedNames, SCTAB nOldTab, const formula::FormulaToken& rToken )
{
    SCTAB nTab = -1;
    if (!rToken.IsGlobal())
    if (rToken.GetSheet() >= 0)
        nTab = nOldTab;

    // Check if this named expression has been modified.
@@ -3003,8 +3012,17 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateCon
                switch ((*pp)->GetOpCode())
                {
                    case ocName:
                        if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **pp))
                            aRes.mbNameModified = true;
                        {
                            SCTAB nOldTab = (*pp)->GetSheet();
                            if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
                                aRes.mbNameModified = true;
                            if (rCxt.mnTabDelta &&
                                    rCxt.maRange.aStart.Tab() <= nOldTab && nOldTab <= rCxt.maRange.aEnd.Tab())
                            {
                                aRes.mbNameModified = true;
                                (*pp)->SetSheet( nOldTab + rCxt.mnTabDelta);
                            }
                        }
                        break;
                    case ocDBArea:
                    case ocTableRef:
@@ -3099,8 +3117,17 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMove(
                switch ((*pp)->GetOpCode())
                {
                    case ocName:
                        if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **pp))
                            aRes.mbNameModified = true;
                        {
                            SCTAB nOldTab = (*pp)->GetSheet();
                            if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
                                aRes.mbNameModified = true;
                            if (rCxt.mnTabDelta &&
                                    rCxt.maRange.aStart.Tab() <= nOldTab && nOldTab <= rCxt.maRange.aEnd.Tab())
                            {
                                aRes.mbNameModified = true;
                                (*pp)->SetSheet( nOldTab + rCxt.mnTabDelta);
                            }
                        }
                        break;
                    case ocDBArea:
                    case ocTableRef:
@@ -3171,8 +3198,17 @@ sc::RefUpdateResult ScTokenArray::MoveReference( const ScAddress& rPos, const sc
                switch ((*p)->GetOpCode())
                {
                    case ocName:
                        if (isNameModified(rCxt.maUpdatedNames, aOldRange.aStart.Tab(), **p))
                            aRes.mbNameModified = true;
                        {
                            SCTAB nOldTab = (*p)->GetSheet();
                            if (isNameModified(rCxt.maUpdatedNames, nOldTab, **p))
                                aRes.mbNameModified = true;
                            if (rCxt.mnTabDelta &&
                                    rCxt.maRange.aStart.Tab() <= nOldTab && nOldTab <= rCxt.maRange.aEnd.Tab())
                            {
                                aRes.mbNameModified = true;
                                (*p)->SetSheet( nOldTab + rCxt.mnTabDelta);
                            }
                        }
                        break;
                    case ocDBArea:
                    case ocTableRef:
@@ -3868,8 +3904,20 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnDeletedTab( sc::RefUpdateDele
                switch ((*pp)->GetOpCode())
                {
                    case ocName:
                        if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **pp))
                            aRes.mbNameModified = true;
                        {
                            SCTAB nOldTab = (*pp)->GetSheet();
                            if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
                                aRes.mbNameModified = true;
                            if (rCxt.mnDeletePos <= nOldTab)
                            {
                                aRes.mbNameModified = true;
                                if (rCxt.mnDeletePos + rCxt.mnSheets < nOldTab)
                                    (*pp)->SetSheet( nOldTab - rCxt.mnSheets);
                                else
                                    // Would point to a deleted sheet. Invalidate.
                                    (*pp)->SetSheet( SCTAB_MAX);
                            }
                        }
                        break;
                    case ocDBArea:
                    case ocTableRef:
@@ -3932,8 +3980,16 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnInsertedTab( sc::RefUpdateIns
                switch ((*pp)->GetOpCode())
                {
                    case ocName:
                        if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **pp))
                            aRes.mbNameModified = true;
                        {
                            SCTAB nOldTab = (*pp)->GetSheet();
                            if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
                                aRes.mbNameModified = true;
                            if (rCxt.mnInsertPos <= nOldTab)
                            {
                                aRes.mbNameModified = true;
                                (*pp)->SetSheet( nOldTab + rCxt.mnSheets);
                            }
                        }
                        break;
                    case ocDBArea:
                    case ocTableRef:
@@ -4017,8 +4073,17 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMovedTab( sc::RefUpdateMoveTa
                switch ((*pp)->GetOpCode())
                {
                    case ocName:
                        if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **pp))
                            aRes.mbNameModified = true;
                        {
                            SCTAB nOldTab = (*pp)->GetSheet();
                            if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
                                aRes.mbNameModified = true;
                            SCTAB nNewTab = rCxt.getNewTab( nOldTab);
                            if (nNewTab != nOldTab)
                            {
                                aRes.mbNameModified = true;
                                (*pp)->SetSheet( nNewTab);
                            }
                        }
                        break;
                    case ocDBArea:
                    case ocTableRef:
@@ -4614,7 +4679,8 @@ void appendTokenByType( sc::TokenStringContext& rCxt, OUStringBuffer& rBuf, cons
            {
                case ocName:
                {
                    if (rToken.IsGlobal())
                    SCTAB nTab = rToken.GetSheet();
                    if (nTab < 0)
                    {
                        // global named range
                        NameType::const_iterator it = rCxt.maGlobalRangeNames.find(nIndex);
@@ -4629,7 +4695,20 @@ void appendTokenByType( sc::TokenStringContext& rCxt, OUStringBuffer& rBuf, cons
                    else
                    {
                        // sheet-local named range
                        sc::TokenStringContext::TabIndexMapType::const_iterator itTab = rCxt.maSheetRangeNames.find(rPos.Tab());
                        if (nTab != rPos.Tab())
                        {
                            // On other sheet.
                            OUString aName;
                            if (static_cast<size_t>(nTab) < rCxt.maTabNames.size())
                                aName = rCxt.maTabNames[nTab];
                            if (!aName.isEmpty())
                                rBuf.append( aName);
                            else
                                rBuf.append( ScGlobal::GetRscString( STR_NO_NAME_REF));
                            rBuf.append( rCxt.mpRefConv->getSpecialSymbol( ScCompiler::Convention::SHEET_SEPARATOR));
                        }

                        sc::TokenStringContext::TabIndexMapType::const_iterator itTab = rCxt.maSheetRangeNames.find(nTab);
                        if (itTab == rCxt.maSheetRangeNames.end())
                        {
                            rBuf.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
diff --git a/sc/source/filter/excel/excform.cxx b/sc/source/filter/excel/excform.cxx
index 2be528a..33ec52f 100644
--- a/sc/source/filter/excel/excform.cxx
+++ b/sc/source/filter/excel/excform.cxx
@@ -544,7 +544,7 @@ ConvErr ExcelToSc::Convert( const ScTokenArray*& pErgebnis, XclImpStream& aIn, s
                if(pName && !pName->GetScRangeData())
                    aStack << aPool.Store( ocMacro, pName->GetXclName() );
                else
                    aStack << aPool.StoreName(nUINT16, true);
                    aStack << aPool.StoreName(nUINT16, -1);
            }
                break;
            case 0x44:
@@ -733,7 +733,7 @@ ConvErr ExcelToSc::Convert( const ScTokenArray*& pErgebnis, XclImpStream& aIn, s
                    aPool >> aStack;
                }
                else
                    aStack << aPool.StoreName( nUINT16, true );
                    aStack << aPool.StoreName( nUINT16, -1 );
                aIn.Ignore( 12 );
                break;
            }
diff --git a/sc/source/filter/excel/excform8.cxx b/sc/source/filter/excel/excform8.cxx
index c13876c..f0668cb 100644
--- a/sc/source/filter/excel/excform8.cxx
+++ b/sc/source/filter/excel/excform8.cxx
@@ -493,7 +493,7 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
                        // user-defined macro name.
                        aStack << aPool.Store(ocMacro, pName->GetXclName());
                    else
                        aStack << aPool.StoreName(nUINT16, pName->IsGlobal());
                        aStack << aPool.StoreName(nUINT16, pName->IsGlobal() ? -1 : pName->GetScTab());
                }
                break;
            }
@@ -680,7 +680,7 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
                    if (pName)
                    {
                        if (pName->GetScRangeData())
                            aStack << aPool.StoreName( nNameIdx, pName->IsGlobal());
                            aStack << aPool.StoreName( nNameIdx, pName->IsGlobal() ? -1 : pName->GetScTab());
                        else
                            aStack << aPool.Store(ocMacro, pName->GetXclName());
                    }
diff --git a/sc/source/filter/excel/tokstack.cxx b/sc/source/filter/excel/tokstack.cxx
index 31e8995..9323f93 100644
--- a/sc/source/filter/excel/tokstack.cxx
+++ b/sc/source/filter/excel/tokstack.cxx
@@ -425,7 +425,7 @@ bool TokenPool::GetElement( const sal_uInt16 nId )
                if (n < maRangeNames.size())
                {
                    const RangeName& r = maRangeNames[n];
                    pScToken->AddRangeName(r.mnIndex, r.mbGlobal);
                    pScToken->AddRangeName(r.mnIndex, r.mnSheet);
                }
            }
            break;
@@ -623,7 +623,7 @@ const TokenId TokenPool::Store( const double& rDouble )

const TokenId TokenPool::Store( const sal_uInt16 nIndex )
{
    return StoreName(nIndex, true);
    return StoreName(nIndex, -1);
}

const TokenId TokenPool::Store( const OUString& rString )
@@ -790,7 +790,7 @@ const TokenId TokenPool::StoreMatrix()
    return static_cast<const TokenId>(nElementAkt);
}

const TokenId TokenPool::StoreName( sal_uInt16 nIndex, bool bGlobal )
const TokenId TokenPool::StoreName( sal_uInt16 nIndex, sal_Int16 nSheet )
{
    if ( nElementAkt >= nElement )
        if (!GrowElement())
@@ -802,7 +802,7 @@ const TokenId TokenPool::StoreName( sal_uInt16 nIndex, bool bGlobal )
    maRangeNames.push_back(RangeName());
    RangeName& r = maRangeNames.back();
    r.mnIndex = nIndex;
    r.mbGlobal = bGlobal;
    r.mnSheet = nSheet;

    ++nElementAkt;

diff --git a/sc/source/filter/excel/xeformula.cxx b/sc/source/filter/excel/xeformula.cxx
index 29ac7a0..9742cb6a 100644
--- a/sc/source/filter/excel/xeformula.cxx
+++ b/sc/source/filter/excel/xeformula.cxx
@@ -2079,10 +2079,8 @@ void XclExpFmlaCompImpl::ProcessExternalRangeRef( const XclExpScToken& rTokData 

void XclExpFmlaCompImpl::ProcessDefinedName( const XclExpScToken& rTokData )
{
    SCTAB nTab = SCTAB_GLOBAL;
    bool bGlobal = rTokData.mpScToken->IsGlobal();
    if (!bGlobal)
        nTab = GetCurrScTab();
    sal_Int16 nSheet = rTokData.mpScToken->GetSheet();
    SCTAB nTab = (nSheet < 0 ? SCTAB_GLOBAL : nSheet);

    XclExpNameManager& rNameMgr = GetNameManager();
    sal_uInt16 nNameIdx = rNameMgr.InsertName(nTab, rTokData.mpScToken->GetIndex());
diff --git a/sc/source/filter/inc/tokstack.hxx b/sc/source/filter/inc/tokstack.hxx
index 9ceb2a4..71ef978 100644
--- a/sc/source/filter/inc/tokstack.hxx
+++ b/sc/source/filter/inc/tokstack.hxx
@@ -126,7 +126,7 @@ private:
        struct RangeName
        {
            sal_uInt16 mnIndex;
            bool mbGlobal;
            sal_Int16  mnSheet;
        };
        ::std::vector<RangeName> maRangeNames;

@@ -205,7 +205,7 @@ public:
                                        // 4 externals (e.g. AddIns, Macros...)
        const TokenId               StoreNlf( const ScSingleRefData& rTr );
        const TokenId               StoreMatrix();
        const TokenId               StoreName( sal_uInt16 nIndex, bool bGlobal );
        const TokenId               StoreName( sal_uInt16 nIndex, sal_Int16 nSheet );
        const TokenId               StoreExtName( sal_uInt16 nFileId, const OUString& rName );
        const TokenId               StoreExtRef( sal_uInt16 nFileId, const OUString& rTabName, const ScSingleRefData& rRef );
        const TokenId               StoreExtRef( sal_uInt16 nFileId, const OUString& rTabName, const ScComplexRefData& rRef );
diff --git a/sc/source/ui/unoobj/tokenuno.cxx b/sc/source/ui/unoobj/tokenuno.cxx
index 6e769d0..edea996 100644
--- a/sc/source/ui/unoobj/tokenuno.cxx
+++ b/sc/source/ui/unoobj/tokenuno.cxx
@@ -424,7 +424,8 @@ bool ScTokenConversion::ConvertToTokenSequence( const ScDocument& rDoc,
                    {
                        sheet::NameToken aNameToken;
                        aNameToken.Index = static_cast<sal_Int32>( rToken.GetIndex() );
                        aNameToken.Global = rToken.IsGlobal();
                        /* FIXME: we need a new token with sheet number */
                        aNameToken.Global = (rToken.GetSheet() < 0);
                        rAPI.Data <<= aNameToken;
                    }
                    break;