diff --git a/pcbnew/dialogs/dialog_drc.cpp b/pcbnew/dialogs/dialog_drc.cpp
index f4b5b0d7cc..bf75e6bbc6 100644
--- a/pcbnew/dialogs/dialog_drc.cpp
+++ b/pcbnew/dialogs/dialog_drc.cpp
@@ -606,7 +606,8 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
|| rcItem->GetErrorCode() == DRCE_ANNULAR_WIDTH
|| rcItem->GetErrorCode() == DRCE_DRILL_OUT_OF_RANGE
|| rcItem->GetErrorCode() == DRCE_MICROVIA_DRILL_OUT_OF_RANGE
- || rcItem->GetErrorCode() == DRCE_CONNECTION_WIDTH )
+ || rcItem->GetErrorCode() == DRCE_CONNECTION_WIDTH
+ || rcItem->GetErrorCode() == DRCE_ASSERTION_FAILURE )
{
menu.Append( 3, _( "Run Inspect > Constraints Resolution" ) );
}
diff --git a/pcbnew/dialogs/panel_setup_rules_help.md b/pcbnew/dialogs/panel_setup_rules_help.md
index e1f4074345..69206e196c 100644
--- a/pcbnew/dialogs/panel_setup_rules_help.md
+++ b/pcbnew/dialogs/panel_setup_rules_help.md
@@ -176,8 +176,14 @@ matches items in the `/CLK_P` and `/CLK_N` nets.
True if `A` and `B` are members of the same diff pair.
- A.memberOf('')
-True if `A` is a member of the given group. Includes nested membership.
+ A.memberOfGroup('')
+True if `A` is a member of the given group. The name can contain wildcards.
+Includes nested membership.
+
+
+ A.memberOfFootprint('')
+True if `A` is a member of a footprint matching the given reference designator. The
+reference can contain wildcards.
A.existsOnLayer('')
@@ -188,6 +194,10 @@ the canonical name (ie: `F.Cu`).
NB: this returns true if `A` is on the given layer, independently
of whether or not the rule is being evaluated for that layer.
For the latter use a `(layer "layer_name")` clause in the rule.
+
+
+ !!! A.memberOf('') !!!
+Deprecated; use `memberOfGroup()` instead.
!!! A.insideCourtyard('') !!!
diff --git a/pcbnew/dialogs/panel_setup_rules_help_md.h b/pcbnew/dialogs/panel_setup_rules_help_md.h
index abccac1285..5e60a639c2 100644
--- a/pcbnew/dialogs/panel_setup_rules_help_md.h
+++ b/pcbnew/dialogs/panel_setup_rules_help_md.h
@@ -177,8 +177,14 @@ _HKI( "### Top-level Clauses\n"
"True if `A` and `B` are members of the same diff pair.\n"
"
\n"
"\n"
-" A.memberOf('')\n"
-"True if `A` is a member of the given group. Includes nested membership.\n"
+" A.memberOfGroup('')\n"
+"True if `A` is a member of the given group. The name can contain wildcards.\n"
+"Includes nested membership.\n"
+"
\n"
+"\n"
+" A.memberOfFootprint('')\n"
+"True if `A` is a member of a footprint matching the given reference designator. The\n"
+"reference can contain wildcards.\n"
"
\n"
"\n"
" A.existsOnLayer('')\n"
@@ -191,6 +197,10 @@ _HKI( "### Top-level Clauses\n"
"For the latter use a `(layer \"layer_name\")` clause in the rule.\n"
"
\n"
"\n"
+" !!! A.memberOf('') !!!\n"
+"Deprecated; use `memberOfGroup()` instead.\n"
+"
\n"
+"\n"
" !!! A.insideCourtyard('') !!!\n"
"Deprecated; use `intersectsCourtyard()` instead.\n"
"
\n"
diff --git a/pcbnew/pcb_expr_functions.cpp b/pcbnew/pcb_expr_functions.cpp
index 58c95308a5..3bb0ca09b7 100644
--- a/pcbnew/pcb_expr_functions.cpp
+++ b/pcbnew/pcb_expr_functions.cpp
@@ -755,7 +755,7 @@ static void enclosedByAreaFunc( LIBEVAL::CONTEXT* aCtx, void* self )
#define MISSING_GROUP_ARG( f ) \
wxString::Format( _( "Missing group name argument to %s." ), f )
-static void memberOfFunc( LIBEVAL::CONTEXT* aCtx, void* self )
+static void memberOfGroupFunc( LIBEVAL::CONTEXT* aCtx, void* self )
{
LIBEVAL::VALUE* arg = aCtx->Pop();
LIBEVAL::VALUE* result = aCtx->AllocValue();
@@ -766,7 +766,7 @@ static void memberOfFunc( LIBEVAL::CONTEXT* aCtx, void* self )
if( !arg )
{
if( aCtx->HasErrorCallback() )
- aCtx->ReportError( MISSING_GROUP_ARG( wxT( "memberOf()" ) ) );
+ aCtx->ReportError( MISSING_GROUP_ARG( wxT( "memberOfGroup()" ) ) );
return;
}
@@ -798,6 +798,47 @@ static void memberOfFunc( LIBEVAL::CONTEXT* aCtx, void* self )
}
+#define MISSING_REF_ARG( f ) \
+ wxString::Format( _( "Missing footprint argument (reference designator) to %s." ), f )
+
+static void memberOfFootprintFunc( LIBEVAL::CONTEXT* aCtx, void* self )
+{
+ LIBEVAL::VALUE* arg = aCtx->Pop();
+ LIBEVAL::VALUE* result = aCtx->AllocValue();
+
+ result->Set( 0.0 );
+ aCtx->Push( result );
+
+ if( !arg )
+ {
+ if( aCtx->HasErrorCallback() )
+ aCtx->ReportError( MISSING_REF_ARG( wxT( "memberOfFootprint()" ) ) );
+
+ return;
+ }
+
+ PCB_EXPR_VAR_REF* vref = static_cast( self );
+ BOARD_ITEM* item = vref ? vref->GetObject( aCtx ) : nullptr;
+
+ if( !item )
+ return;
+
+ result->SetDeferredEval(
+ [item, arg]() -> double
+ {
+ ;
+
+ if( FOOTPRINT* parentFP = item->GetParentFootprint() )
+ {
+ if( parentFP->GetReference().Matches( arg->AsString() ) )
+ return 1.0;
+ }
+
+ return 0.0;
+ } );
+}
+
+
static void isMicroVia( LIBEVAL::CONTEXT* aCtx, void* self )
{
PCB_EXPR_VAR_REF* vref = static_cast( self );
@@ -988,7 +1029,9 @@ void PCB_EXPR_BUILTIN_FUNCTIONS::RegisterAllFunctions()
RegisterFunc( wxT( "isMicroVia()" ), isMicroVia );
RegisterFunc( wxT( "isBlindBuriedVia()" ), isBlindBuriedViaFunc );
- RegisterFunc( wxT( "memberOf('x')" ), memberOfFunc );
+ RegisterFunc( wxT( "memberOf('x') DEPRECATED" ), memberOfGroupFunc );
+ RegisterFunc( wxT( "memberOfGroup('x')" ), memberOfGroupFunc );
+ RegisterFunc( wxT( "memberOfFootprint('x')" ), memberOfFootprintFunc );
RegisterFunc( wxT( "fromTo('x','y')" ), fromToFunc );
RegisterFunc( wxT( "isCoupledDiffPair()" ), isCoupledDiffPairFunc );
diff --git a/pcbnew/tools/board_inspection_tool.cpp b/pcbnew/tools/board_inspection_tool.cpp
index bf5423f25a..f9765f129c 100644
--- a/pcbnew/tools/board_inspection_tool.cpp
+++ b/pcbnew/tools/board_inspection_tool.cpp
@@ -543,6 +543,16 @@ void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr& aDR
break;
+ case DRCE_ASSERTION_FAILURE:
+ r = dialog->AddHTMLPage( _( "Assertions" ) );
+ reportHeader( _( "Assertions for:" ), a, r );
+
+ if( compileError )
+ reportCompileError( r );
+
+ drcEngine.ProcessAssertions( a, []( const DRC_CONSTRAINT* c ){}, r );
+ break;
+
default:
return;
}