office-gobmx/sw/source/core/doc/docftn.cxx
Stephan Bergmann 16e3b84d2e Improve loplugin:dyncastvisibility to check for non-inline key functions
This would have caught the issue discussed in
709b1f3ddb "Make sure VCLXPopupMenu has unique
RTTI".  (The commit message talks about RTTI there, while what Clang actually
compared for an optimized implementation of a dynamic_cast to a final class is
vtable pointers, but the overall picture remains the same.  Both RTTI and
vtables are emitted along the key function, and if that is missing or inline,
they are emitted for each dynamic library individually, and as internal symbols
on macOS.)

This commit also addresses all the issues found by the improved
loplugin:dyncastvisibility on Linux.  See the newly added TODO in
compilerplugins/clang/dyncastvisibility.cxx and
86b86ac87e "Give DocumentEventHolder (aka
EventHolder<DocumentEvent>) a key function" for an issue with key functions for
class template instantiations.

Change-Id: Ia19155efb1d23692c92b9c97ff17f18ae7a1f3ee
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176576
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
Tested-by: Jenkins
2024-11-14 12:49:22 +01:00

569 lines
19 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <ftnidx.hxx>
#include <rootfrm.hxx>
#include <txtftn.hxx>
#include <fmtftn.hxx>
#include <pam.hxx>
#include <pagedesc.hxx>
#include <charfmt.hxx>
#include <UndoAttribute.hxx>
#include <rolbck.hxx>
#include <doc.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <IDocumentUndoRedo.hxx>
#include <IDocumentState.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <IDocumentStylePoolAccess.hxx>
#include <ndtxt.hxx>
#include <poolfmt.hxx>
#include <ftninfo.hxx>
#include <fmtftntx.hxx>
#include <unoprnms.hxx>
SwEndNoteInfo& SwEndNoteInfo::operator=(const SwEndNoteInfo& rInfo)
{
m_pTextFormatColl = rInfo.m_pTextFormatColl;
m_pPageDesc = rInfo.m_pPageDesc;
m_pCharFormat = rInfo.m_pCharFormat;
m_pAnchorFormat = rInfo.m_pAnchorFormat;
m_aDepends.EndListeningAll();
m_aDepends.StartListening(m_pTextFormatColl);
m_aDepends.StartListening(m_pPageDesc);
m_aDepends.StartListening(m_pCharFormat);
m_aDepends.StartListening(m_pAnchorFormat);
m_aFormat = rInfo.m_aFormat;
m_nFootnoteOffset = rInfo.m_nFootnoteOffset;
m_bEndNote = rInfo.m_bEndNote;
m_sPrefix = rInfo.m_sPrefix;
m_sSuffix = rInfo.m_sSuffix;
return *this;
}
bool SwEndNoteInfo::operator==( const SwEndNoteInfo& rInfo ) const
{
return
m_pTextFormatColl == rInfo.m_pTextFormatColl &&
m_pPageDesc == rInfo.m_pPageDesc &&
m_pCharFormat == rInfo.m_pCharFormat &&
m_pAnchorFormat == rInfo.m_pAnchorFormat &&
m_aFormat.GetNumberingType() == rInfo.m_aFormat.GetNumberingType() &&
m_nFootnoteOffset == rInfo.m_nFootnoteOffset &&
m_bEndNote == rInfo.m_bEndNote &&
m_sPrefix == rInfo.m_sPrefix &&
m_sSuffix == rInfo.m_sSuffix;
}
SwEndNoteInfo::SwEndNoteInfo(const SwEndNoteInfo& rInfo) :
SwClient(nullptr),
m_aDepends(*this),
m_pTextFormatColl(rInfo.m_pTextFormatColl),
m_pPageDesc(rInfo.m_pPageDesc),
m_pCharFormat(rInfo.m_pCharFormat),
m_pAnchorFormat(rInfo.m_pAnchorFormat),
m_sPrefix( rInfo.m_sPrefix ),
m_sSuffix( rInfo.m_sSuffix ),
m_bEndNote( true ),
m_aFormat( rInfo.m_aFormat ),
m_nFootnoteOffset( rInfo.m_nFootnoteOffset )
{
m_aDepends.StartListening(m_pTextFormatColl);
m_aDepends.StartListening(m_pPageDesc);
m_aDepends.StartListening(m_pCharFormat);
m_aDepends.StartListening(m_pAnchorFormat);
}
SwEndNoteInfo::SwEndNoteInfo() :
SwClient(nullptr),
m_aDepends(*this),
m_pTextFormatColl(nullptr),
m_pPageDesc(nullptr),
m_pCharFormat(nullptr),
m_pAnchorFormat(nullptr),
m_bEndNote( true ),
m_nFootnoteOffset( 0 )
{
m_aFormat.SetNumberingType(SVX_NUM_ROMAN_LOWER);
}
SwPageDesc* SwEndNoteInfo::GetPageDesc(SwDoc& rDoc) const
{
if(!m_pPageDesc)
{
m_pPageDesc = rDoc.getIDocumentStylePoolAccess().GetPageDescFromPool( o3tl::narrowing<sal_uInt16>(
m_bEndNote ? RES_POOLPAGE_ENDNOTE : RES_POOLPAGE_FOOTNOTE ) );
m_aDepends.StartListening(m_pPageDesc);
}
return m_pPageDesc;
}
bool SwEndNoteInfo::KnowsPageDesc() const
{
return m_pPageDesc != nullptr;
}
bool SwEndNoteInfo::DependsOn(const SwPageDesc* pDesc) const
{
return m_pPageDesc == pDesc;
}
void SwEndNoteInfo::ChgPageDesc(SwPageDesc* pDesc)
{
m_aDepends.EndListening(m_pPageDesc);
m_pPageDesc = pDesc;
m_aDepends.StartListening(m_pPageDesc);
}
SwSection* SwEndNoteInfo::GetSwSection(SwDoc& rDoc) const
{
if (!m_pSwSection)
{
SwSectionFormat* pFormat = rDoc.MakeSectionFormat();
pFormat->SetFormatName(UNO_NAME_ENDNOTE);
pFormat->SetFormatAttr(SwFormatEndAtTextEnd(FTNEND_ATTXTEND));
m_pSwSection.reset(new SwSection(SectionType::Content, pFormat->GetName(), *pFormat));
}
return m_pSwSection.get();
}
void SwEndNoteInfo::ResetSwSection()
{
m_pSwSection.reset();
}
void SwEndNoteInfo::SetFootnoteTextColl(SwTextFormatColl& rFormat)
{
m_aDepends.EndListening(m_pTextFormatColl);
m_pTextFormatColl = &rFormat;
m_aDepends.StartListening(m_pTextFormatColl);
}
SwCharFormat* SwEndNoteInfo::GetCharFormat(SwDoc& rDoc) const
{
auto pCharFormatFromDoc = rDoc.getIDocumentStylePoolAccess().GetCharFormatFromPool( o3tl::narrowing<sal_uInt16>(
m_bEndNote ? RES_POOLCHR_ENDNOTE : RES_POOLCHR_FOOTNOTE ) );
if (m_pCharFormat != pCharFormatFromDoc)
{
m_aDepends.EndListening(m_pCharFormat);
m_aDepends.StartListening(pCharFormatFromDoc);
m_pCharFormat = pCharFormatFromDoc;
}
return m_pCharFormat;
}
namespace
{
void lcl_ResetPoolIdForDocAndSync(const sal_uInt16 nId, SwCharFormat* pFormat, const SwEndNoteInfo& rInfo)
{
auto pDoc = pFormat->GetDoc();
if(!pDoc)
return;
for(auto pDocFormat : *pDoc->GetCharFormats())
{
if(pDocFormat == pFormat)
pDocFormat->SetPoolFormatId(nId);
else if(pDocFormat->GetPoolFormatId() == nId)
pDocFormat->SetPoolFormatId(0);
}
rInfo.GetCharFormat(*pDoc);
rInfo.GetAnchorCharFormat(*pDoc);
}
}
void SwEndNoteInfo::SetCharFormat(SwCharFormat* pFormat)
{
lcl_ResetPoolIdForDocAndSync(
o3tl::narrowing<sal_uInt16>(m_bEndNote
? RES_POOLCHR_ENDNOTE
: RES_POOLCHR_FOOTNOTE),
pFormat,
*this);
}
SwCharFormat* SwEndNoteInfo::GetAnchorCharFormat(SwDoc& rDoc) const
{
auto pAnchorFormatFromDoc = rDoc.getIDocumentStylePoolAccess().GetCharFormatFromPool( o3tl::narrowing<sal_uInt16>(
m_bEndNote ? RES_POOLCHR_ENDNOTE_ANCHOR : RES_POOLCHR_FOOTNOTE_ANCHOR ) );
if(m_pAnchorFormat != pAnchorFormatFromDoc)
{
m_aDepends.EndListening(m_pAnchorFormat);
m_aDepends.StartListening(pAnchorFormatFromDoc);
m_pAnchorFormat = pAnchorFormatFromDoc;
}
return m_pAnchorFormat;
}
void SwEndNoteInfo::SetAnchorCharFormat(SwCharFormat* pFormat)
{
lcl_ResetPoolIdForDocAndSync(
o3tl::narrowing<sal_uInt16>(m_bEndNote
? RES_POOLCHR_ENDNOTE_ANCHOR
: RES_POOLCHR_FOOTNOTE_ANCHOR),
pFormat,
*this);
}
SwCharFormat* SwEndNoteInfo::GetCurrentCharFormat(const bool bAnchor) const
{
return bAnchor
? m_pAnchorFormat
: m_pCharFormat;
}
void SwEndNoteInfo::UpdateFormatOrAttr()
{
auto pFormat = GetCurrentCharFormat(m_pCharFormat == nullptr);
if (!pFormat || !m_aDepends.IsListeningTo(pFormat) || pFormat->IsFormatInDTOR())
return;
SwDoc* pDoc = pFormat->GetDoc();
SwFootnoteIdxs& rFootnoteIdxs = pDoc->GetFootnoteIdxs();
for(auto pTextFootnote : rFootnoteIdxs)
{
const SwFormatFootnote &rFootnote = pTextFootnote->GetFootnote();
if(rFootnote.IsEndNote() == m_bEndNote)
pTextFootnote->SetNumber(rFootnote.GetNumber(), rFootnote.GetNumberRLHidden(), rFootnote.GetNumStr());
}
}
void SwEndNoteInfo::SwClientNotify( const SwModify& rModify, const SfxHint& rHint)
{
if (rHint.GetId() == SfxHintId::SwLegacyModify)
{
auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint);
switch(pLegacyHint->GetWhich())
{
case RES_ATTRSET_CHG:
case RES_FMT_CHG:
UpdateFormatOrAttr();
break;
default:
CheckRegistration( pLegacyHint->m_pOld );
}
}
else if (rHint.GetId() == SfxHintId::SwModifyChanged)
{
auto pModifyChangedHint = static_cast<const sw::ModifyChangedHint*>(&rHint);
auto pNew = const_cast<sw::BroadcastingModify*>(static_cast<const sw::BroadcastingModify*>(pModifyChangedHint->m_pNew));
if(m_pAnchorFormat == &rModify)
m_pAnchorFormat = static_cast<SwCharFormat*>(pNew);
else if(m_pCharFormat == &rModify)
m_pCharFormat = static_cast<SwCharFormat*>(pNew);
else if(m_pPageDesc == &rModify)
m_pPageDesc = static_cast<SwPageDesc*>(pNew);
else if(m_pTextFormatColl == &rModify)
m_pTextFormatColl = static_cast<SwTextFormatColl*>(pNew);
}
}
SwFootnoteInfo& SwFootnoteInfo::operator=(const SwFootnoteInfo& rInfo)
{
SwEndNoteInfo::operator=(rInfo);
m_aQuoVadis = rInfo.m_aQuoVadis;
m_aErgoSum = rInfo.m_aErgoSum;
m_ePos = rInfo.m_ePos;
m_eNum = rInfo.m_eNum;
return *this;
}
bool SwFootnoteInfo::operator==( const SwFootnoteInfo& rInfo ) const
{
return m_ePos == rInfo.m_ePos &&
m_eNum == rInfo.m_eNum &&
SwEndNoteInfo::operator==(rInfo) &&
m_aQuoVadis == rInfo.m_aQuoVadis &&
m_aErgoSum == rInfo.m_aErgoSum;
}
SwFootnoteInfo::SwFootnoteInfo(const SwFootnoteInfo& rInfo) :
SwEndNoteInfo( rInfo ),
m_aQuoVadis( rInfo.m_aQuoVadis ),
m_aErgoSum( rInfo.m_aErgoSum ),
m_ePos( rInfo.m_ePos ),
m_eNum( rInfo.m_eNum )
{
m_bEndNote = false;
}
SwFootnoteInfo::SwFootnoteInfo() :
m_ePos( FTNPOS_PAGE ),
m_eNum( FTNNUM_DOC )
{
m_aFormat.SetNumberingType(SVX_NUM_ARABIC);
m_bEndNote = false;
}
SwFootnoteInfo::~SwFootnoteInfo() = default;
void SwDoc::SetFootnoteInfo(const SwFootnoteInfo& rInfo)
{
SwRootFrame* pTmpRoot = getIDocumentLayoutAccess().GetCurrentLayout();
if( GetFootnoteInfo() == rInfo )
return;
const SwFootnoteInfo &rOld = GetFootnoteInfo();
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoFootNoteInfo>(rOld, *this) );
}
bool bFootnotePos = rInfo.m_ePos != rOld.m_ePos;
bool bFootnoteDesc = rOld.m_ePos == FTNPOS_CHAPTER &&
rInfo.GetPageDesc( *this ) != rOld.GetPageDesc( *this );
bool bExtra = rInfo.m_aQuoVadis != rOld.m_aQuoVadis ||
rInfo.m_aErgoSum != rOld.m_aErgoSum ||
rInfo.m_aFormat.GetNumberingType() != rOld.m_aFormat.GetNumberingType() ||
rInfo.GetPrefix() != rOld.GetPrefix() ||
rInfo.GetSuffix() != rOld.GetSuffix();
SwCharFormat *pOldChrFormat = rOld.GetCharFormat( *this ),
*pNewChrFormat = rInfo.GetCharFormat( *this );
bool bFootnoteChrFormats = pOldChrFormat != pNewChrFormat;
*mpFootnoteInfo = rInfo;
if (pTmpRoot)
{
o3tl::sorted_vector<SwRootFrame*> aAllLayouts = GetAllLayouts();
if ( bFootnotePos )
for( auto aLayout : aAllLayouts )
aLayout->AllRemoveFootnotes();
else
{
for( auto aLayout : aAllLayouts )
aLayout->UpdateFootnoteNums();
if ( bFootnoteDesc )
for( auto aLayout : aAllLayouts )
aLayout->CheckFootnotePageDescs(false);
if ( bExtra )
{
// For messages regarding ErgoSum etc. we save the extra code and use the
// available methods.
SwFootnoteIdxs& rFootnoteIdxs = GetFootnoteIdxs();
for( size_t nPos = 0; nPos < rFootnoteIdxs.size(); ++nPos )
{
SwTextFootnote *pTextFootnote = rFootnoteIdxs[ nPos ];
const SwFormatFootnote &rFootnote = pTextFootnote->GetFootnote();
if ( !rFootnote.IsEndNote() )
pTextFootnote->SetNumber(rFootnote.GetNumber(), rFootnote.GetNumberRLHidden(), rFootnote.GetNumStr());
}
}
}
}
if( FTNNUM_PAGE != rInfo.m_eNum )
GetFootnoteIdxs().UpdateAllFootnote();
else if( bFootnoteChrFormats )
{
mpFootnoteInfo->UpdateFormatOrAttr();
}
// #i81002# no update during loading
if ( !IsInReading() )
{
getIDocumentFieldsAccess().UpdateRefFields();
}
getIDocumentState().SetModified();
}
void SwDoc::SetEndNoteInfo(const SwEndNoteInfo& rInfo)
{
SwRootFrame* pTmpRoot = getIDocumentLayoutAccess().GetCurrentLayout();
if( GetEndNoteInfo() == rInfo )
return;
if(GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().AppendUndo(
std::make_unique<SwUndoEndNoteInfo>( GetEndNoteInfo(), *this ) );
}
bool bNumChg = rInfo.m_nFootnoteOffset != GetEndNoteInfo().m_nFootnoteOffset;
// this seems to be an optimization: UpdateAllFootnote() is only called
// if the offset changes; if the offset is the same,
// but type/prefix/suffix changes, just set new numbers.
bool const bExtra = !bNumChg &&
( (rInfo.m_aFormat.GetNumberingType() !=
GetEndNoteInfo().m_aFormat.GetNumberingType())
|| (rInfo.GetPrefix() != GetEndNoteInfo().GetPrefix())
|| (rInfo.GetSuffix() != GetEndNoteInfo().GetSuffix())
);
bool bFootnoteDesc = rInfo.GetPageDesc( *this ) !=
GetEndNoteInfo().GetPageDesc( *this );
SwCharFormat *pOldChrFormat = GetEndNoteInfo().GetCharFormat( *this ),
*pNewChrFormat = rInfo.GetCharFormat( *this );
bool bFootnoteChrFormats = pOldChrFormat != pNewChrFormat;
*mpEndNoteInfo = rInfo;
if ( pTmpRoot )
{
if ( bFootnoteDesc )
{
for( auto aLayout : GetAllLayouts() )
aLayout->CheckFootnotePageDescs(true);
}
if ( bExtra )
{
// For messages regarding ErgoSum etc. we save the extra code and use the
// available methods.
SwFootnoteIdxs& rFootnoteIdxs = GetFootnoteIdxs();
for( size_t nPos = 0; nPos < rFootnoteIdxs.size(); ++nPos )
{
SwTextFootnote *pTextFootnote = rFootnoteIdxs[ nPos ];
const SwFormatFootnote &rFootnote = pTextFootnote->GetFootnote();
if ( rFootnote.IsEndNote() )
pTextFootnote->SetNumber(rFootnote.GetNumber(), rFootnote.GetNumberRLHidden(), rFootnote.GetNumStr());
}
}
}
if( bNumChg )
GetFootnoteIdxs().UpdateAllFootnote();
else if( bFootnoteChrFormats )
{
mpEndNoteInfo->UpdateFormatOrAttr();
}
// #i81002# no update during loading
if ( !IsInReading() )
{
getIDocumentFieldsAccess().UpdateRefFields();
}
getIDocumentState().SetModified();
}
bool SwDoc::SetCurFootnote( const SwPaM& rPam, const OUString& rNumStr,
bool bIsEndNote)
{
SwFootnoteIdxs& rFootnoteArr = GetFootnoteIdxs();
SwRootFrame* pTmpRoot = getIDocumentLayoutAccess().GetCurrentLayout();
auto [pStt, pEnd] = rPam.StartEnd(); // SwPosition*
const SwNodeOffset nSttNd = pStt->GetNodeIndex();
const sal_Int32 nSttCnt = pStt->GetContentIndex();
const SwNodeOffset nEndNd = pEnd->GetNodeIndex();
const sal_Int32 nEndCnt = pEnd->GetContentIndex();
size_t nPos = 0;
rFootnoteArr.SeekEntry( pStt->GetNode(), &nPos );
std::unique_ptr<SwUndoChangeFootNote> pUndo;
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().ClearRedo(); // AppendUndo far below, so leave it
pUndo.reset(new SwUndoChangeFootNote( rPam, rNumStr, bIsEndNote ));
}
bool bChg = false;
bool bTypeChgd = false;
const size_t nPosSave = nPos;
while( nPos < rFootnoteArr.size() )
{
SwTextFootnote* pTextFootnote = rFootnoteArr[ nPos++ ];
SwNodeOffset nIdx = SwTextFootnote_GetIndex(pTextFootnote);
if( nIdx >= nEndNd &&
( nIdx != nEndNd || nEndCnt < pTextFootnote->GetStart() ) )
continue;
if( nIdx > nSttNd || ( nIdx == nSttNd &&
nSttCnt <= pTextFootnote->GetStart() ) )
{
const SwFormatFootnote& rFootnote = pTextFootnote->GetFootnote();
if( rFootnote.GetNumStr() != rNumStr ||
rFootnote.IsEndNote() != bIsEndNote )
{
bChg = true;
if ( pUndo )
{
pUndo->GetHistory().AddFootnote(*pTextFootnote);
}
pTextFootnote->SetNumber(rFootnote.GetNumber(), rFootnote.GetNumberRLHidden(), rNumStr);
if( rFootnote.IsEndNote() != bIsEndNote )
{
const_cast<SwFormatFootnote&>(rFootnote).SetEndNote( bIsEndNote );
bTypeChgd = true;
pTextFootnote->CheckCondColl();
//#i11339# dispose UNO wrapper when a footnote is changed to an endnote or vice versa
const_cast<SwFormatFootnote&>(rFootnote).InvalidateFootnote();
}
}
}
}
nPos = nPosSave; // There are more in the front!
while (nPos > 0)
{
SwTextFootnote* pTextFootnote = rFootnoteArr[ --nPos ];
SwNodeOffset nIdx = SwTextFootnote_GetIndex(pTextFootnote);
if( nIdx <= nSttNd &&
( nIdx != nSttNd || nSttCnt > pTextFootnote->GetStart() ) )
continue;
if( nIdx < nEndNd || ( nIdx == nEndNd &&
nEndCnt >= pTextFootnote->GetStart() ) )
{
const SwFormatFootnote& rFootnote = pTextFootnote->GetFootnote();
if( rFootnote.GetNumStr() != rNumStr ||
rFootnote.IsEndNote() != bIsEndNote )
{
bChg = true;
if ( pUndo )
{
pUndo->GetHistory().AddFootnote(*pTextFootnote);
}
pTextFootnote->SetNumber(rFootnote.GetNumber(), rFootnote.GetNumberRLHidden(), rNumStr);
if( rFootnote.IsEndNote() != bIsEndNote )
{
const_cast<SwFormatFootnote&>(rFootnote).SetEndNote( bIsEndNote );
bTypeChgd = true;
pTextFootnote->CheckCondColl();
}
}
}
}
// Who needs to be triggered?
if( bChg )
{
if( pUndo )
{
GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
}
if ( bTypeChgd )
rFootnoteArr.UpdateAllFootnote();
if( FTNNUM_PAGE != GetFootnoteInfo().m_eNum )
{
if ( !bTypeChgd )
rFootnoteArr.UpdateAllFootnote();
}
else if( pTmpRoot )
{
for( auto aLayout : GetAllLayouts() )
aLayout->UpdateFootnoteNums();
}
getIDocumentState().SetModified();
}
return bChg;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */