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 0c8e7a7137
commit 4024a15a17
17 changed files with 132 additions and 106 deletions

View File

@ -147,9 +147,9 @@ void EC_CIRCLE::Apply( EDIT_POINT& aHandle, const GRID_HELPER& aGrid )
EC_CONVERGING::EC_CONVERGING( EDIT_LINE& aLine, EDIT_POINTS& aPoints ) :
EDIT_CONSTRAINT<EDIT_LINE>( aLine ),
m_colinearConstraint( nullptr ),
m_prevOrigin( aPoints.Previous( aLine.GetOrigin(), false ) ),
m_nextEnd( aPoints.Next( aLine.GetEnd(), false ) ),
m_colinearConstraint( nullptr ),
m_editPoints( aPoints )
{
// Dragged segment endings

View File

@ -107,13 +107,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

@ -353,7 +353,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 );
@ -389,7 +389,7 @@ bool SCH_EDIT_TOOL::Init()
};
auto propertiesCondition =
[&]( const SELECTION& aSel )
[this]( const SELECTION& aSel )
{
if( aSel.GetSize() == 0 )
{

View File

@ -189,10 +189,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 );
@ -217,7 +218,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();
};
@ -226,7 +227,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

@ -237,7 +237,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;
@ -253,7 +253,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 );
@ -262,7 +262,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 );
@ -270,7 +270,7 @@ 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();

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

@ -92,12 +92,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

@ -484,7 +484,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();
@ -498,7 +498,7 @@ bool ROUTER_TOOL::Init()
};
auto hasOtherEnd =
[&]( const SELECTION& )
[this]( const SELECTION& )
{
std::vector<PNS::NET_HANDLE> currentNets = m_router->GetCurrentNets();

View File

@ -193,7 +193,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

@ -94,13 +94,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

@ -45,16 +45,18 @@ PCB_PICKER_TOOL::PCB_PICKER_TOOL() :
bool PCB_PICKER_TOOL::Init()
{
PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
CONDITIONAL_MENU& menu = m_menu->GetMenu();
CONDITIONAL_MENU& menu = m_menu->GetMenu();
const auto snapIsSetToAllLayers =
[=]( const SELECTION& aSel )
auto snapIsSetToAllLayers =
[this]( const SELECTION& aSel )
{
if( frame )
return frame->GetMagneticItemsSettings()->allLayers;
else
return false;
if( PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>() )
{
if( frame->GetMagneticItemsSettings() )
return frame->GetMagneticItemsSettings()->allLayers;
}
return false;
};
// "Cancel" goes at the top of the context menu when a tool is active
@ -67,7 +69,7 @@ bool PCB_PICKER_TOOL::Init()
menu.AddSeparator( 1 );
if( frame )
if( PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>() )
frame->AddStandardSubMenus( *m_menu.get() );
return true;

View File

@ -1776,29 +1776,33 @@ 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 =
[]( 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 =
[]( 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 );
};
const auto arcIsEdited = [&]( const SELECTION& aSelection ) -> bool
{
const EDA_ITEM* item = aSelection.Front();
return ( item != nullptr ) && ( item->Type() == PCB_SHAPE_T )
&& static_cast<const PCB_SHAPE*>( item )->GetShape() == SHAPE_T::ARC;
};
const auto arcIsEdited =
[]( const SELECTION& aSelection ) -> bool
{
const EDA_ITEM* item = aSelection.Front();
return ( item != nullptr ) && ( item->Type() == PCB_SHAPE_T )
&& static_cast<const PCB_SHAPE*>( item )->GetShape() == SHAPE_T::ARC;
};
using S_C = SELECTION_CONDITIONS;

View File

@ -164,13 +164,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

@ -43,7 +43,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();
};