Don't reference stack variables from a long-life lambda.

In particular, a lambda for conditional menus should
never capture more than `[this]`.  Even the tool's
frame pointer could change.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21615
This commit is contained in:
Jeff Young 2025-09-01 12:36:44 +01:00
parent 32e9ab9b75
commit 1c6d8b3f5e
15 changed files with 114 additions and 91 deletions

View File

@ -109,13 +109,13 @@ bool SCH_DRAWING_TOOLS::Init()
SCH_TOOL_BASE::Init();
auto belowRootSheetCondition =
[&]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
};
auto inDrawingRuleArea =
[&]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
return m_drawingRuleArea;
};

View File

@ -343,7 +343,7 @@ bool SCH_EDIT_TOOL::Init()
auto sheetSelection = S_C::Count( 1 ) && S_C::OnlyTypes( sheetTypes );
auto haveHighlight =
[&]( const SELECTION& sel )
[this]( const SELECTION& sel )
{
SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
@ -379,7 +379,7 @@ bool SCH_EDIT_TOOL::Init()
};
auto propertiesCondition =
[&]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
if( aSel.GetSize() == 0 )
{

View File

@ -186,10 +186,11 @@ bool SCH_LINE_WIRE_BUS_TOOL::Init()
{
SCH_TOOL_BASE::Init();
const auto busGetter = [this]()
{
return getBusForUnfolding();
};
const auto busGetter =
[this]()
{
return getBusForUnfolding();
};
std::shared_ptr<BUS_UNFOLD_MENU>
busUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>( busGetter );
@ -214,7 +215,7 @@ bool SCH_LINE_WIRE_BUS_TOOL::Init()
};
auto belowRootSheetCondition =
[&]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
};
@ -223,7 +224,7 @@ bool SCH_LINE_WIRE_BUS_TOOL::Init()
&& SCH_CONDITIONS::OnlyTypes( { SCH_ITEM_LOCATE_BUS_T } );
auto haveHighlight =
[&]( const SELECTION& sel )
[this]( const SELECTION& sel )
{
SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );

View File

@ -232,7 +232,7 @@ bool SCH_SELECTION_TOOL::Init()
// clang-format on
auto schEditSheetPageNumberCondition =
[&] ( const SELECTION& aSel )
[this] ( const SELECTION& aSel )
{
if( m_isSymbolEditor || m_isSymbolViewer )
return false;
@ -248,7 +248,7 @@ bool SCH_SELECTION_TOOL::Init()
};
auto belowRootSheetCondition =
[&]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
@ -257,7 +257,7 @@ bool SCH_SELECTION_TOOL::Init()
};
auto haveHighlight =
[&]( const SELECTION& sel )
[this]( const SELECTION& sel )
{
SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
@ -265,14 +265,14 @@ bool SCH_SELECTION_TOOL::Init()
};
auto haveSymbol =
[&]( const SELECTION& sel )
[this]( const SELECTION& sel )
{
return m_isSymbolEditor &&
static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
};
auto symbolDisplayNameIsEditable =
[&]( const SELECTION& sel )
[this]( const SELECTION& sel )
{
if ( !m_isSymbolEditor )
return false;

View File

@ -55,79 +55,104 @@ bool SYMBOL_EDITOR_CONTROL::Init()
{
LIBRARY_EDITOR_CONTROL* libraryTreeTool = m_toolMgr->GetTool<LIBRARY_EDITOR_CONTROL>();
CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu();
SYMBOL_EDIT_FRAME* editFrame = getEditFrame<SYMBOL_EDIT_FRAME>();
wxCHECK( editFrame, false );
auto libSelectedCondition =
[ editFrame ]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
LIB_ID sel = editFrame->GetTreeLIBID();
return !sel.GetLibNickname().empty() && sel.GetLibItemName().empty();
if( SYMBOL_EDIT_FRAME* editFrame = getEditFrame<SYMBOL_EDIT_FRAME>() )
{
LIB_ID sel = editFrame->GetTreeLIBID();
return !sel.GetLibNickname().empty() && sel.GetLibItemName().empty();
}
return false;
};
// The libInferredCondition allows you to do things like New Symbol and Paste with a
// symbol selected (in other words, when we know the library context even if the library
// itself isn't selected.
auto libInferredCondition =
[ editFrame ]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
LIB_ID sel = editFrame->GetTreeLIBID();
return !sel.GetLibNickname().empty();
if( SYMBOL_EDIT_FRAME* editFrame = getEditFrame<SYMBOL_EDIT_FRAME>() )
{
LIB_ID sel = editFrame->GetTreeLIBID();
return !sel.GetLibNickname().empty();
}
return false;
};
auto symbolSelectedCondition =
[ editFrame ]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
LIB_ID sel = editFrame->GetTargetLibId();
return !sel.GetLibNickname().empty() && !sel.GetLibItemName().empty();
if( SYMBOL_EDIT_FRAME* editFrame = getEditFrame<SYMBOL_EDIT_FRAME>() )
{
LIB_ID sel = editFrame->GetTargetLibId();
return !sel.GetLibNickname().empty() && !sel.GetLibItemName().empty();
}
return false;
};
/* not used, but used to be used
auto multiSelectedCondition =
[ editFrame ]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
return editFrame->GetTreeSelectionCount() > 1;
SYMBOL_EDIT_FRAME* editFrame = getEditFrame<SYMBOL_EDIT_FRAME>();
return editFrame && editFrame->GetTreeSelectionCount() > 1;
};
*/
auto multiSymbolSelectedCondition =
[ editFrame ]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
if( editFrame->GetTreeSelectionCount() > 1 )
SYMBOL_EDIT_FRAME* editFrame = getEditFrame<SYMBOL_EDIT_FRAME>();
if( editFrame && editFrame->GetTreeSelectionCount() > 1 )
{
for( LIB_ID& sel : editFrame->GetSelectedLibIds() )
{
if( !sel.IsValid() )
return false;
}
return true;
}
return false;
};
/* not used, yet
auto multiLibrarySelectedCondition =
[ editFrame ]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
if( editFrame->GetTreeSelectionCount() > 1 )
SYMBOL_EDIT_FRAME* editFrame = getEditFrame<SYMBOL_EDIT_FRAME>();
if( editFrame && editFrame->GetTreeSelectionCount() > 1 )
{
for( LIB_ID& sel : editFrame->GetSelectedLibIds() )
{
if( sel.IsValid() )
return false;
}
return true;
}
return false;
};
*/
auto canOpenExternally =
[ editFrame ]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
// The option is shown if the lib has no current edits
LIB_SYMBOL_LIBRARY_MANAGER& libMgr = editFrame->GetLibManager();
wxString libName = editFrame->GetTargetLibId().GetLibNickname();
bool ret = !libMgr.IsLibraryModified( libName );
return ret;
if( SYMBOL_EDIT_FRAME* editFrame = getEditFrame<SYMBOL_EDIT_FRAME>() )
{
LIB_SYMBOL_LIBRARY_MANAGER& libMgr = editFrame->GetLibManager();
wxString libName = editFrame->GetTargetLibId().GetLibNickname();
return !libMgr.IsLibraryModified( libName );
}
return false;
};
// clang-format off

View File

@ -100,12 +100,11 @@ bool SYMBOL_EDITOR_PIN_TOOL::Init()
SCH_TOOL_BASE::Init();
auto canEdit =
[&]( const SELECTION& sel )
[this]( const SELECTION& sel )
{
SYMBOL_EDIT_FRAME* editor = static_cast<SYMBOL_EDIT_FRAME*>( m_frame );
wxCHECK( editor, false );
return editor->IsSymbolEditable() && !editor->IsSymbolAlias();
return editor && editor->IsSymbolEditable() && !editor->IsSymbolAlias();
};
static const std::vector<KICAD_T> pinTypes = { SCH_PIN_T };

View File

@ -49,7 +49,7 @@ protected:
PCB_TABLECELL_T } );
auto cellBlockSelection =
[&]( const SELECTION& sel )
[this]( const SELECTION& sel )
{
if( sel.Size() < 2 )
return false;
@ -77,7 +77,7 @@ protected:
};
auto mergedCellsSelection =
[&]( const SELECTION& sel )
[this]( const SELECTION& sel )
{
for( EDA_ITEM* item : sel )
{
@ -95,18 +95,13 @@ protected:
// Add editing actions to the selection tool menu
//
selToolMenu.AddSeparator( 100 );
selToolMenu.AddItem( ACTIONS::addRowAbove,
cellSelection && SELECTION_CONDITIONS::Idle, 100 );
selToolMenu.AddItem( ACTIONS::addRowBelow,
cellSelection && SELECTION_CONDITIONS::Idle, 100 );
selToolMenu.AddItem( ACTIONS::addColBefore,
cellSelection && SELECTION_CONDITIONS::Idle, 100 );
selToolMenu.AddItem( ACTIONS::addColAfter,
cellSelection && SELECTION_CONDITIONS::Idle, 100 );
selToolMenu.AddItem( ACTIONS::addRowAbove, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
selToolMenu.AddItem( ACTIONS::addRowBelow, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
selToolMenu.AddItem( ACTIONS::addColBefore, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
selToolMenu.AddItem( ACTIONS::addColAfter, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
selToolMenu.AddSeparator( 100 );
selToolMenu.AddItem( ACTIONS::deleteRows,
cellSelection && SELECTION_CONDITIONS::Idle, 100 );
selToolMenu.AddItem( ACTIONS::deleteRows, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
selToolMenu.AddItem( ACTIONS::deleteColumns, cellSelection && SELECTION_CONDITIONS::Idle,
100 );
@ -115,8 +110,7 @@ protected:
selToolMenu.AddItem( ACTIONS::unmergeCells, cellSelection && mergedCellsSelection, 100 );
selToolMenu.AddSeparator( 100 );
selToolMenu.AddItem( ACTIONS::editTable,
cellSelection && SELECTION_CONDITIONS::Idle, 100 );
selToolMenu.AddItem( ACTIONS::editTable, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
selToolMenu.AddSeparator( 100 );
}

View File

@ -485,7 +485,7 @@ bool ROUTER_TOOL::Init()
m_menu->RegisterSubMenu( m_diffPairMenu );
auto haveHighlight =
[&]( const SELECTION& sel )
[this]( const SELECTION& sel )
{
KIGFX::RENDER_SETTINGS* cfg = m_toolMgr->GetView()->GetPainter()->GetSettings();
@ -499,7 +499,7 @@ bool ROUTER_TOOL::Init()
};
auto hasOtherEnd =
[&]( const SELECTION& )
[this]( const SELECTION& )
{
std::vector<PNS::NET_HANDLE> currentNets = m_router->GetCurrentNets();

View File

@ -194,7 +194,7 @@ DRAWING_TOOL::~DRAWING_TOOL()
bool DRAWING_TOOL::Init()
{
auto haveHighlight =
[&]( const SELECTION& sel )
[this]( const SELECTION& sel )
{
KIGFX::RENDER_SETTINGS* cfg = m_toolMgr->GetView()->GetPainter()->GetSettings();

View File

@ -219,7 +219,7 @@ bool EDIT_TOOL::Init()
m_selectionTool->GetToolMenu().RegisterSubMenu( shapeModificationSubMenu );
auto positioningToolsCondition =
[&]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
std::shared_ptr<CONDITIONAL_MENU> subMenu = makePositioningToolsMenu( this );
subMenu->Evaluate( aSel );
@ -227,7 +227,7 @@ bool EDIT_TOOL::Init()
};
auto shapeModificationCondition =
[&]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
std::shared_ptr<CONDITIONAL_MENU> subMenu = makeShapeModificationMenu( this );
subMenu->Evaluate( aSel );
@ -235,7 +235,7 @@ bool EDIT_TOOL::Init()
};
auto propertiesCondition =
[&]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
if( aSel.GetSize() == 0 )
{
@ -264,13 +264,13 @@ bool EDIT_TOOL::Init()
};
auto inFootprintEditor =
[ this ]( const SELECTION& aSelection )
[this]( const SELECTION& aSelection )
{
return m_isFootprintEditor;
};
auto canMirror =
[ this ]( const SELECTION& aSelection )
[this]( const SELECTION& aSelection )
{
if( !m_isFootprintEditor
&& SELECTION_CONDITIONS::OnlyTypes( padTypes )( aSelection ) )
@ -307,7 +307,7 @@ bool EDIT_TOOL::Init()
};
auto noActiveToolCondition =
[ this ]( const SELECTION& aSelection )
[this]( const SELECTION& aSelection )
{
return frame()->ToolStackIsEmpty();
};
@ -319,13 +319,13 @@ bool EDIT_TOOL::Init()
};
auto noItemsCondition =
[ this ]( const SELECTION& aSelections ) -> bool
[this]( const SELECTION& aSelections ) -> bool
{
return frame()->GetBoard() && !frame()->GetBoard()->IsEmpty();
};
auto isSkippable =
[ this ]( const SELECTION& aSelection )
[this]( const SELECTION& aSelection )
{
return frame()->IsCurrentTool( PCB_ACTIONS::moveIndividually );
};

View File

@ -83,7 +83,7 @@ bool FOOTPRINT_EDITOR_CONTROL::Init()
CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu();
auto libSelectedCondition =
[ this ]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
LIB_ID sel = m_frame->GetLibTree()->GetSelectedLibId();
return !sel.GetLibNickname().empty() && sel.GetLibItemName().empty();
@ -93,28 +93,28 @@ bool FOOTPRINT_EDITOR_CONTROL::Init()
// symbol selected (in other words, when we know the library context even if the library
// itself isn't selected.
auto libInferredCondition =
[ this ]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
LIB_ID sel = m_frame->GetLibTree()->GetSelectedLibId();
return !sel.GetLibNickname().empty();
};
auto fpSelectedCondition =
[ this ]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
LIB_ID sel = m_frame->GetLibTree()->GetSelectedLibId();
return !sel.GetLibNickname().empty() && !sel.GetLibItemName().empty();
};
auto fpExportCondition =
[ this ]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
FOOTPRINT* fp = m_frame->GetBoard()->GetFirstFootprint();
return fp != nullptr;
};
auto canOpenExternally =
[ this ]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
// The option is shown if the editor has no current edits,
// dumb/simple guard against opening a new file that does not exist on disk

View File

@ -98,13 +98,13 @@ bool PAD_TOOL::Init()
SELECTION_CONDITIONS::OnlyTypes( padTypes );
auto explodeCondition =
[&]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
return m_editPad == niluuid && aSel.Size() == 1 && aSel[0]->Type() == PCB_PAD_T;
};
auto recombineCondition =
[&]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
return m_editPad != niluuid;
};

View File

@ -1947,22 +1947,25 @@ bool PCB_POINT_EDITOR::Init()
wxASSERT_MSG( m_selectionTool, wxT( "pcbnew.InteractiveSelection tool is not available" ) );
const auto addCornerCondition = [&]( const SELECTION& aSelection ) -> bool
{
const EDA_ITEM* item = aSelection.Front();
return ( item != nullptr ) && canAddCorner( *item );
};
const auto addCornerCondition =
[this]( const SELECTION& aSelection ) -> bool
{
const EDA_ITEM* item = aSelection.Front();
return ( item != nullptr ) && canAddCorner( *item );
};
const auto addChamferCondition = [&]( const SELECTION& aSelection ) -> bool
{
const EDA_ITEM* item = aSelection.Front();
return ( item != nullptr ) && canChamferCorner( *item );
};
const auto addChamferCondition =
[this]( const SELECTION& aSelection ) -> bool
{
const EDA_ITEM* item = aSelection.Front();
return ( item != nullptr ) && canChamferCorner( *item );
};
const auto removeCornerCondition = [&]( const SELECTION& aSelection ) -> bool
{
return PCB_POINT_EDITOR::removeCornerCondition( aSelection );
};
const auto removeCornerCondition =
[this]( const SELECTION& aSelection ) -> bool
{
return PCB_POINT_EDITOR::removeCornerCondition( aSelection );
};
using S_C = SELECTION_CONDITIONS;

View File

@ -176,13 +176,14 @@ bool PCB_SELECTION_TOOL::Init()
auto& menu = m_menu->GetMenu();
auto activeToolCondition =
[ frame ] ( const SELECTION& aSel )
[this] ( const SELECTION& aSel )
{
return !frame->ToolStackIsEmpty();
PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
return frame && !frame->ToolStackIsEmpty();
};
auto haveHighlight =
[&]( const SELECTION& sel )
[this]( const SELECTION& sel )
{
KIGFX::RENDER_SETTINGS* cfg = m_toolMgr->GetView()->GetPainter()->GetSettings();

View File

@ -42,7 +42,7 @@ bool PCB_VIEWER_TOOLS::Init()
{
// Populate the context menu displayed during the tool (primarily the measure tool)
auto activeToolCondition =
[ this ] ( const SELECTION& aSel )
[this] ( const SELECTION& aSel )
{
return !frame()->ToolStackIsEmpty();
};