ADDED: support for ERC & DRC errors and warnings in text variables.

Also fixes some bugs in storing exclusions in
symbol fields and children.

Also fixes some bugs in checking for resolved text
variables in symbol children.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18279
This commit is contained in:
Jeff Young 2024-06-28 16:40:13 +01:00
parent 16340e6cf4
commit 9e6884f656
11 changed files with 425 additions and 100 deletions

View File

@ -37,6 +37,7 @@
#include <wx/stdpaths.h>
#include <wx/url.h>
#include <wx/utils.h>
#include <wx/regex.h>
#ifdef _WIN32
#include <Windows.h>
@ -70,8 +71,9 @@ wxString ExpandTextVars( const wxString& aSource, const PROJECT* aProject )
wxString ExpandTextVars( const wxString& aSource,
const std::function<bool( wxString* )>* aResolver )
{
wxString newbuf;
size_t sourceLen = aSource.length();
static wxRegEx userDefinedWarningError( wxS( "^(ERC|DRC)_(WARNING|ERROR).*$" ) );
wxString newbuf;
size_t sourceLen = aSource.length();
newbuf.Alloc( sourceLen ); // best guess (improves performance)
@ -92,7 +94,11 @@ wxString ExpandTextVars( const wxString& aSource,
if( token.IsEmpty() )
continue;
if( aResolver && (*aResolver)( &token ) )
if( userDefinedWarningError.Matches( token ) )
{
// Only show user-defined warnings/errors during ERC/DRC
}
else if( aResolver && (*aResolver)( &token ) )
{
newbuf.append( token );
}

View File

@ -182,11 +182,44 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
{
DS_DRAW_ITEM_LIST wsItems( schIUScale );
auto unresolved = [this]( wxString str )
{
str = ExpandEnvVarSubstitutions( str, &m_schematic->Prj() );
return str.Matches( wxS( "*${*}*" ) );
};
auto unresolved =
[this]( wxString str )
{
str = ExpandEnvVarSubstitutions( str, &m_schematic->Prj() );
return str.Matches( wxS( "*${*}*" ) );
};
auto testAssertion =
[]( const SCH_ITEM* item, const SCH_SHEET_PATH& sheet, SCH_SCREEN* screen,
const wxString& text )
{
static wxRegEx warningExpr( wxS( "^\\$\\{ERC_WARNING\\s*([^}]*)\\}(.*)$" ) );
static wxRegEx errorExpr( wxS( "^\\$\\{ERC_ERROR\\s*([^}]*)\\}(.*)$" ) );
if( warningExpr.Matches( text ) )
{
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_GENERIC_WARNING );
ercItem->SetItems( item );
ercItem->SetSheetSpecificPath( sheet );
ercItem->SetErrorMessage( warningExpr.GetMatch( text, 1 ) );
SCH_MARKER* marker = new SCH_MARKER( ercItem, item->GetPosition() );
screen->Append( marker );
}
if( errorExpr.Matches( text ) )
{
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_GENERIC_ERROR );
ercItem->SetItems( item );
ercItem->SetSheetSpecificPath( sheet );
ercItem->SetErrorMessage( errorExpr.GetMatch( text, 1 ) );
SCH_MARKER* marker = new SCH_MARKER( ercItem, item->GetPosition() );
screen->Append( marker );
}
};
if( aDrawingSheet )
{
@ -214,13 +247,64 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
if( unresolved( field.GetShownText( &sheet, true ) ) )
{
auto ercItem = ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
ercItem->SetItems( &field );
ercItem->SetItems( symbol );
ercItem->SetSheetSpecificPath( sheet );
SCH_MARKER* marker = new SCH_MARKER( ercItem, field.GetPosition() );
screen->Append( marker );
}
testAssertion( &field, sheet, screen, field.GetText() );
}
symbol->GetLibSymbolRef()->RunOnChildren(
[&]( SCH_ITEM* child )
{
if( child->Type() == SCH_FIELD_T )
{
// test only SCH_SYMBOL fields, not LIB_SYMBOL fields
}
else if( child->Type() == SCH_TEXT_T )
{
SCH_TEXT* textItem = static_cast<SCH_TEXT*>( child );
if( unresolved( textItem->GetShownText( &sheet, true ) ) )
{
auto ercItem = ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
ercItem->SetItems( symbol );
ercItem->SetSheetSpecificPath( sheet );
BOX2I bbox = textItem->GetBoundingBox();
bbox = symbol->GetTransform().TransformCoordinate( bbox );
VECTOR2I pos = bbox.Centre() + symbol->GetPosition();
SCH_MARKER* marker = new SCH_MARKER( ercItem, pos );
screen->Append( marker );
}
testAssertion( symbol, sheet, screen, textItem->GetText() );
}
else if( child->Type() == SCH_TEXTBOX_T )
{
SCH_TEXTBOX* textboxItem = static_cast<SCH_TEXTBOX*>( child );
if( unresolved( textboxItem->GetShownText( &sheet, true ) ) )
{
auto ercItem = ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
ercItem->SetItems( symbol );
ercItem->SetSheetSpecificPath( sheet );
BOX2I bbox = textboxItem->GetBoundingBox();
bbox = symbol->GetTransform().TransformCoordinate( bbox );
VECTOR2I pos = bbox.Centre() + symbol->GetPosition();
SCH_MARKER* marker = new SCH_MARKER( ercItem, pos );
screen->Append( marker );
}
testAssertion( symbol, sheet, screen, textboxItem->GetText() );
}
} );
}
else if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( item ) )
{
@ -229,12 +313,14 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
if( unresolved( field.GetShownText( &sheet, true ) ) )
{
auto ercItem = ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
ercItem->SetItems( &field );
ercItem->SetItems( label );
ercItem->SetSheetSpecificPath( sheet );
SCH_MARKER* marker = new SCH_MARKER( ercItem, field.GetPosition() );
screen->Append( marker );
}
testAssertion( &field, sheet, screen, field.GetText() );
}
}
else if( item->Type() == SCH_SHEET_T )
@ -246,12 +332,14 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
if( unresolved( field.GetShownText( &sheet, true ) ) )
{
auto ercItem = ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
ercItem->SetItems( &field );
ercItem->SetItems( subSheet );
ercItem->SetSheetSpecificPath( sheet );
SCH_MARKER* marker = new SCH_MARKER( ercItem, field.GetPosition() );
screen->Append( marker );
}
testAssertion( &field, sheet, screen, field.GetText() );
}
SCH_SHEET_PATH subSheetPath = sheet;
@ -281,6 +369,8 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
SCH_MARKER* marker = new SCH_MARKER( ercItem, text->GetPosition() );
screen->Append( marker );
}
testAssertion( text, sheet, screen, text->GetText() );
}
else if( SCH_TEXTBOX* textBox = dynamic_cast<SCH_TEXTBOX*>( item ) )
{
@ -293,6 +383,8 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
SCH_MARKER* marker = new SCH_MARKER( ercItem, textBox->GetPosition() );
screen->Append( marker );
}
testAssertion( textBox, sheet, screen, textBox->GetText() );
}
}

View File

@ -42,6 +42,7 @@
ERC_ITEM ERC_ITEM::heading_connections( 0, _( "Connections" ), "" );
ERC_ITEM ERC_ITEM::heading_conflicts( 0, _( "Conflicts" ), "" );
ERC_ITEM ERC_ITEM::heading_misc( 0, _( "Miscellaneous" ), "" );
ERC_ITEM ERC_ITEM::heading_internal( 0, "", "" );
ERC_ITEM ERC_ITEM::duplicateSheetName( ERCE_DUPLICATE_SHEET_NAME,
_( "Duplicate sheet names within a given sheet" ),
@ -75,6 +76,14 @@ ERC_ITEM ERC_ITEM::pinTableError( ERCE_PIN_TO_PIN_ERROR,
_( "Conflict problem between pins" ),
wxT( "pin_to_pin" ) );
ERC_ITEM ERC_ITEM::genericWarning( ERCE_GENERIC_WARNING,
_( "Warning" ),
wxT( "generic-warning" ) );
ERC_ITEM ERC_ITEM::genericError( ERCE_GENERIC_ERROR,
_( "Error" ),
wxT( "generic-error" ) );
ERC_ITEM ERC_ITEM::hierLabelMismatch( ERCE_HIERACHICAL_LABEL,
_( "Mismatch between hierarchical labels and sheet pins" ),
wxT( "hier_label_mismatch" ) );
@ -207,55 +216,63 @@ ERC_ITEM ERC_ITEM::busEntryNeeded( ERCE_BUS_ENTRY_NEEDED,
_( "Bus Entry needed" ),
wxT( "bus_entry_needed" ) );
std::vector<std::reference_wrapper<RC_ITEM>> ERC_ITEM::allItemTypes( {
ERC_ITEM::heading_connections,
ERC_ITEM::pinNotConnected,
ERC_ITEM::pinNotDriven,
ERC_ITEM::powerpinNotDriven,
ERC_ITEM::noConnectConnected,
ERC_ITEM::noConnectDangling,
ERC_ITEM::labelDangling,
ERC_ITEM::globalLabelDangling,
ERC_ITEM::singleGlobalLabel,
ERC_ITEM::wireDangling,
ERC_ITEM::busEntryNeeded,
ERC_ITEM::endpointOffGrid,
ERC_ITEM::fourWayJunction,
ERC_ITEM::duplicatePinError,
std::vector<std::reference_wrapper<RC_ITEM>> ERC_ITEM::allItemTypes(
{
ERC_ITEM::heading_connections,
ERC_ITEM::pinNotConnected,
ERC_ITEM::pinNotDriven,
ERC_ITEM::powerpinNotDriven,
ERC_ITEM::noConnectConnected,
ERC_ITEM::noConnectDangling,
ERC_ITEM::globalLabelDangling,
ERC_ITEM::singleGlobalLabel,
ERC_ITEM::wireDangling,
ERC_ITEM::busEntryNeeded,
ERC_ITEM::endpointOffGrid,
ERC_ITEM::fourWayJunction,
ERC_ITEM::duplicatePinError,
ERC_ITEM::heading_conflicts,
ERC_ITEM::duplicateReference,
ERC_ITEM::pinTableWarning,
ERC_ITEM::differentUnitValue,
ERC_ITEM::differentUnitFootprint,
ERC_ITEM::differentUnitNet,
ERC_ITEM::duplicateSheetName,
ERC_ITEM::hierLabelMismatch,
ERC_ITEM::multipleNetNames,
ERC_ITEM::busDefinitionConflict,
ERC_ITEM::busToBusConflict,
ERC_ITEM::busToNetConflict,
ERC_ITEM::netNotBusMember,
ERC_ITEM::netclassConflict,
ERC_ITEM::heading_conflicts,
ERC_ITEM::duplicateReference,
ERC_ITEM::pinTableWarning,
ERC_ITEM::differentUnitValue,
ERC_ITEM::differentUnitFootprint,
ERC_ITEM::differentUnitNet,
ERC_ITEM::duplicateSheetName,
ERC_ITEM::hierLabelMismatch,
ERC_ITEM::multipleNetNames,
ERC_ITEM::busDefinitionConflict,
ERC_ITEM::busToBusConflict,
ERC_ITEM::busToNetConflict,
ERC_ITEM::netNotBusMember,
ERC_ITEM::netclassConflict,
ERC_ITEM::heading_misc,
ERC_ITEM::unannotated,
ERC_ITEM::unresolvedVariable,
ERC_ITEM::simulationModelIssues,
ERC_ITEM::similarLabels,
// Commented out until the logic for this element is coded
// TODO: Add bus label syntax checking
// ERC_ITEM::busLabelSyntax,
ERC_ITEM::libSymbolIssues,
ERC_ITEM::libSymbolMismatch,
ERC_ITEM::footprintLinkIssues,
ERC_ITEM::extraUnits,
ERC_ITEM::missingUnits,
ERC_ITEM::missingInputPin,
ERC_ITEM::missingBidiPin,
ERC_ITEM::missingPowerInputPin,
ERC_ITEM::overlappingRuleAreas
} );
ERC_ITEM::heading_misc,
ERC_ITEM::unannotated,
ERC_ITEM::unresolvedVariable,
ERC_ITEM::simulationModelIssues,
ERC_ITEM::similarLabels,
// Commented out until the logic for this element is coded
// TODO: Add bus label syntax checking
// ERC_ITEM::busLabelSyntax,
ERC_ITEM::libSymbolIssues,
ERC_ITEM::libSymbolMismatch,
ERC_ITEM::footprintLinkIssues,
ERC_ITEM::extraUnits,
ERC_ITEM::missingUnits,
ERC_ITEM::missingInputPin,
ERC_ITEM::missingBidiPin,
ERC_ITEM::missingPowerInputPin,
ERC_ITEM::overlappingRuleAreas,
// ERC_ITEM types with no user-editable severities
// NOTE: this MUST be the last grouping in the list!
ERC_ITEM::heading_internal,
ERC_ITEM::pinTableWarning,
ERC_ITEM::pinTableError,
ERC_ITEM::genericWarning,
ERC_ITEM::genericError
} );
@ -271,6 +288,8 @@ std::shared_ptr<ERC_ITEM> ERC_ITEM::Create( int aErrorCode )
case ERCE_DUPLICATE_PIN_ERROR: return std::make_shared<ERC_ITEM>( duplicatePinError );
case ERCE_PIN_TO_PIN_WARNING: return std::make_shared<ERC_ITEM>( pinTableWarning );
case ERCE_PIN_TO_PIN_ERROR: return std::make_shared<ERC_ITEM>( pinTableError );
case ERCE_GENERIC_WARNING: return std::make_shared<ERC_ITEM>( genericWarning );
case ERCE_GENERIC_ERROR: return std::make_shared<ERC_ITEM>( genericError );
case ERCE_HIERACHICAL_LABEL: return std::make_shared<ERC_ITEM>( hierLabelMismatch );
case ERCE_NOCONNECT_CONNECTED: return std::make_shared<ERC_ITEM>( noConnectConnected );
case ERCE_NOCONNECT_NOT_CONNECTED: return std::make_shared<ERC_ITEM>( noConnectDangling );

View File

@ -75,7 +75,20 @@ public:
static std::vector<std::reference_wrapper<RC_ITEM>> GetItemsWithSeverities()
{
return allItemTypes;
static std::vector<std::reference_wrapper<RC_ITEM>> itemsWithSeverities;
if( itemsWithSeverities.empty() )
{
for( RC_ITEM& item : allItemTypes )
{
if( &item == &heading_internal )
break;
itemsWithSeverities.push_back( item );
}
}
return itemsWithSeverities;
}
/**
@ -182,6 +195,7 @@ private:
static ERC_ITEM heading_connections;
static ERC_ITEM heading_conflicts;
static ERC_ITEM heading_misc;
static ERC_ITEM heading_internal;
static ERC_ITEM duplicateSheetName;
static ERC_ITEM endpointOffGrid;
@ -191,6 +205,8 @@ private:
static ERC_ITEM duplicatePinError;
static ERC_ITEM pinTableWarning;
static ERC_ITEM pinTableError;
static ERC_ITEM genericWarning;
static ERC_ITEM genericError;
static ERC_ITEM hierLabelMismatch;
static ERC_ITEM noConnectConnected;
static ERC_ITEM fourWayJunction;

View File

@ -268,6 +268,14 @@ SEVERITY ERC_SETTINGS::GetSeverity( int aErrorCode ) const
else
return RPT_SEVERITY_WARNING;
}
else if( aErrorCode == ERCE_GENERIC_WARNING )
{
return RPT_SEVERITY_WARNING;
}
else if( aErrorCode == ERCE_GENERIC_ERROR )
{
return RPT_SEVERITY_ERROR;
}
wxCHECK_MSG( m_ERCSeverities.count( aErrorCode ), RPT_SEVERITY_IGNORE,
wxS( "Missing severity from map in ERC_SETTINGS!" ) );

View File

@ -92,8 +92,10 @@ enum ERCE_T
ERCE_DUPLICATE_PIN_ERROR,
ERCE_PIN_TO_PIN_WARNING, // pin connected to an other pin: warning level
ERCE_PIN_TO_PIN_ERROR, // pin connected to an other pin: error level
ERCE_ANNOTATION_ACTION // Not actually an error; just an action performed during
ERCE_ANNOTATION_ACTION, // Not actually an error; just an action performed during
// annotation which is passed back through the error handler.
ERCE_GENERIC_WARNING,
ERCE_GENERIC_ERROR
};
/// The values a pin-to-pin entry in the pin matrix can take on

View File

@ -102,14 +102,59 @@ wxString SCH_MARKER::SerializeToString() const
if( erc->AuxItemHasSheetPath() )
auxItemPath = erc->GetAuxItemSheetPath().Path().AsString();
return wxString::Format( wxT( "%s|%d|%d|%s|%s|%s|%s|%s" ), m_rcItem->GetSettingsKey(), m_Pos.x,
m_Pos.y, m_rcItem->GetMainItemID().AsString(),
m_rcItem->GetAuxItemID().AsString(), sheetSpecificPath, mainItemPath,
auxItemPath );
if( m_rcItem->GetErrorCode() == ERCE_GENERIC_WARNING
|| m_rcItem->GetErrorCode() == ERCE_GENERIC_ERROR )
{
SCH_ITEM* sch_item = Schematic()->GetItem( erc->GetMainItemID() );
SCH_ITEM* parent = static_cast<SCH_ITEM*>( sch_item->GetParent() );
EDA_TEXT* text_item = dynamic_cast<EDA_TEXT*>( sch_item );
// SCH_FIELDs and SCH_ITEMs inside LIB_SYMBOLs don't have persistent KIIDs. So the
// exclusion must refer to the parent's KIID, and include the text of the original text
// item for later look-up.
if( parent->IsType( { SCH_SYMBOL_T, SCH_LABEL_T, SCH_SHEET_T } ) )
{
return wxString::Format( wxT( "%s|%d|%d|%s|%s|%s|%s|%s" ),
m_rcItem->GetSettingsKey(),
m_Pos.x,
m_Pos.y,
parent->m_Uuid.AsString(),
text_item->GetText(),
sheetSpecificPath,
mainItemPath,
wxEmptyString );
}
else
{
return wxString::Format( wxT( "%s|%d|%d|%s|%s|%s|%s|%s" ),
m_rcItem->GetSettingsKey(),
m_Pos.x,
m_Pos.y,
sch_item->m_Uuid.AsString(),
wxEmptyString,
sheetSpecificPath,
mainItemPath,
wxEmptyString );
}
}
else
{
return wxString::Format( wxT( "%s|%d|%d|%s|%s|%s|%s|%s" ),
m_rcItem->GetSettingsKey(),
m_Pos.x,
m_Pos.y,
m_rcItem->GetMainItemID().AsString(),
m_rcItem->GetAuxItemID().AsString(),
sheetSpecificPath,
mainItemPath,
auxItemPath );
}
}
SCH_MARKER* SCH_MARKER::DeserializeFromString( const SCH_SHEET_LIST& aSheetList, const wxString& data )
SCH_MARKER* SCH_MARKER::DeserializeFromString( const SCH_SHEET_LIST& aSheetList,
const wxString& data )
{
wxArrayString props = wxSplit( data, '|' );
VECTOR2I markerPos( (int) strtol( props[1].c_str(), nullptr, 10 ),
@ -120,7 +165,61 @@ SCH_MARKER* SCH_MARKER::DeserializeFromString( const SCH_SHEET_LIST& aSheetList,
if( !ercItem )
return nullptr;
ercItem->SetItems( KIID( props[3] ), KIID( props[4] ) );
if( ercItem->GetErrorCode() == ERCE_GENERIC_WARNING
|| ercItem->GetErrorCode() == ERCE_GENERIC_ERROR )
{
// SCH_FIELDs and SCH_ITEMs inside LIB_SYMBOLs don't have persistent KIIDs. So the
// exclusion will contain the parent's KIID in prop[3], and the text of the original
// text item in prop[4].
if( !props[4].IsEmpty() )
{
KIID uuid = niluuid;
SCH_ITEM* parent = aSheetList.GetItem( KIID( props[3] ) );
// Check fields and pins for a match
parent->RunOnChildren(
[&]( SCH_ITEM* child )
{
if( EDA_TEXT* text_item = dynamic_cast<EDA_TEXT*>( child ) )
{
if( text_item->GetText() == props[4] )
uuid = child->m_Uuid;
}
} );
// If it's a symbol, we must also check non-overridden LIB_SYMBOL text children
if( uuid == niluuid && parent->Type() == SCH_SYMBOL_T )
{
static_cast<SCH_SYMBOL*>( parent )->GetLibSymbolRef()->RunOnChildren(
[&]( SCH_ITEM* child )
{
if( child->Type() == SCH_FIELD_T )
{
// Match only on SCH_SYMBOL fields, not LIB_SYMBOL fields.
}
else if( EDA_TEXT* text_item = dynamic_cast<EDA_TEXT*>( child ) )
{
if( text_item->GetText() == props[4] )
uuid = child->m_Uuid;
}
} );
}
if( uuid != niluuid )
ercItem->SetItems( uuid );
else
return nullptr;
}
else
{
ercItem->SetItems( KIID( props[3] ) );
}
}
else
{
ercItem->SetItems( KIID( props[3] ), KIID( props[4] ) );
}
bool isLegacyMarker = true;

View File

@ -48,6 +48,7 @@ DRC_ITEM DRC_ITEM::heading_schematic_parity( 0, _( "Schematic Parity" ), "" );
DRC_ITEM DRC_ITEM::heading_signal_integrity( 0, _( "Signal Integrity" ), "" );
DRC_ITEM DRC_ITEM::heading_readability( 0, _( "Readability" ), "" );
DRC_ITEM DRC_ITEM::heading_misc( 0, _( "Miscellaneous" ), "" );
DRC_ITEM DRC_ITEM::heading_internal( 0, "", "" );
DRC_ITEM DRC_ITEM::unconnectedItems( DRCE_UNCONNECTED_ITEMS,
_( "Missing connection between items" ),
@ -205,6 +206,14 @@ DRC_ITEM DRC_ITEM::assertionFailure( DRCE_ASSERTION_FAILURE,
_( "Assertion failure" ),
wxT( "assertion_failure" ) );
DRC_ITEM DRC_ITEM::genericWarning( DRCE_GENERIC_WARNING,
_( "Warning" ),
wxT( "generic_warning" ) );
DRC_ITEM DRC_ITEM::genericError( DRCE_GENERIC_ERROR,
_( "Error" ),
wxT( "generic_error" ) );
DRC_ITEM DRC_ITEM::copperSliver( DRCE_COPPER_SLIVER,
_( "Copper sliver" ),
wxT( "copper_sliver" ) );
@ -267,7 +276,8 @@ DRC_ITEM DRC_ITEM::footprintTHPadhasNoHole( DRCE_PAD_TH_WITH_NO_HOLE,
wxT( "through_hole_pad_without_hole" ) );
std::vector<std::reference_wrapper<RC_ITEM>> DRC_ITEM::allItemTypes( {
std::vector<std::reference_wrapper<RC_ITEM>> DRC_ITEM::allItemTypes(
{
DRC_ITEM::heading_electrical,
DRC_ITEM::shortingItems,
DRC_ITEM::tracksCrossing,
@ -321,17 +331,21 @@ std::vector<std::reference_wrapper<RC_ITEM>> DRC_ITEM::allItemTypes( {
DRC_ITEM::isolatedCopper,
DRC_ITEM::footprint,
DRC_ITEM::padstack,
// Do not include padstackInvalid; it flags invalid states so must always be an error
// DRC_ITEM::padStackInvalid;
DRC_ITEM::pthInsideCourtyard,
DRC_ITEM::npthInsideCourtyard,
DRC_ITEM::itemOnDisabledLayer,
DRC_ITEM::unresolvedVariable,
DRC_ITEM::footprintTypeMismatch,
DRC_ITEM::libFootprintIssues,
DRC_ITEM::libFootprintMismatch,
DRC_ITEM::footprintTHPadhasNoHole
DRC_ITEM::footprintTHPadhasNoHole,
// DRC_ITEM types with no user-editable severities
// NOTE: this MUST be the last grouping in the list!
DRC_ITEM::heading_internal,
DRC_ITEM::padstackInvalid,
DRC_ITEM::genericError,
DRC_ITEM::genericWarning
} );
@ -378,6 +392,8 @@ std::shared_ptr<DRC_ITEM> DRC_ITEM::Create( int aErrorCode )
case DRCE_LIB_FOOTPRINT_MISMATCH: return std::make_shared<DRC_ITEM>( libFootprintMismatch );
case DRCE_UNRESOLVED_VARIABLE: return std::make_shared<DRC_ITEM>( unresolvedVariable );
case DRCE_ASSERTION_FAILURE: return std::make_shared<DRC_ITEM>( assertionFailure );
case DRCE_GENERIC_WARNING: return std::make_shared<DRC_ITEM>( genericWarning );
case DRCE_GENERIC_ERROR: return std::make_shared<DRC_ITEM>( genericError );
case DRCE_COPPER_SLIVER: return std::make_shared<DRC_ITEM>( copperSliver );
case DRCE_OVERLAPPING_SILK: return std::make_shared<DRC_ITEM>( silkOverlaps );
case DRCE_SILK_CLEARANCE: return std::make_shared<DRC_ITEM>( silkClearance );

View File

@ -82,6 +82,8 @@ enum PCB_DRC_CODE {
DRCE_UNRESOLVED_VARIABLE,
DRCE_ASSERTION_FAILURE, // user-defined (custom rule) assertion
DRCE_GENERIC_WARNING, // generic warning
DRCE_GENERIC_ERROR, // generic error
DRCE_COPPER_SLIVER,
DRCE_SOLDERMASK_BRIDGE, // failure to maintain min soldermask web thickness
@ -123,7 +125,20 @@ public:
static std::vector<std::reference_wrapper<RC_ITEM>> GetItemsWithSeverities()
{
return allItemTypes;
static std::vector<std::reference_wrapper<RC_ITEM>> itemsWithSeverities;
if( itemsWithSeverities.empty() )
{
for( RC_ITEM& item : allItemTypes )
{
if( &item == &heading_internal )
break;
itemsWithSeverities.push_back( item );
}
}
return itemsWithSeverities;
}
void SetViolatingRule ( DRC_RULE *aRule ) { m_violatingRule = aRule; }
@ -155,6 +170,7 @@ private:
static DRC_ITEM heading_signal_integrity;
static DRC_ITEM heading_readability;
static DRC_ITEM heading_misc;
static DRC_ITEM heading_internal;
static DRC_ITEM unconnectedItems;
static DRC_ITEM shortingItems;
@ -195,6 +211,8 @@ private:
static DRC_ITEM libFootprintMismatch;
static DRC_ITEM unresolvedVariable;
static DRC_ITEM assertionFailure;
static DRC_ITEM genericWarning;
static DRC_ITEM genericError;
static DRC_ITEM copperSliver;
static DRC_ITEM silkClearance;
static DRC_ITEM silkEdgeClearance;

View File

@ -39,7 +39,9 @@
- DRCE_DISABLED_LAYER_ITEM, ///< item on a disabled layer
- DRCE_INVALID_OUTLINE, ///< invalid board outline
- DRCE_UNRESOLVED_VARIABLE,
- DRCE_ASSERTION_FAILURE ///< user-defined assertions
- DRCE_ASSERTION_FAILURE, ///< user-defined assertions
- DRCE_GENERIC_WARNING ///< user-defined warnings
- DRCE_GENERIC_ERROR ///< user-defined errors
*/
class DRC_TEST_PROVIDER_MISC : public DRC_TEST_PROVIDER
@ -260,23 +262,61 @@ void DRC_TEST_PROVIDER_MISC::testAssertions()
auto checkAssertions =
[&]( BOARD_ITEM* item ) -> bool
{
if( m_drcEngine->IsErrorLimitExceeded( DRCE_ASSERTION_FAILURE ) )
return false;
if( !reportProgress( ii++, items, progressDelta ) )
return false;
m_drcEngine->ProcessAssertions( item,
[&]( const DRC_CONSTRAINT* c )
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_ASSERTION_FAILURE ) )
{
m_drcEngine->ProcessAssertions( item,
[&]( const DRC_CONSTRAINT* c )
{
auto drcItem = DRC_ITEM::Create( DRCE_ASSERTION_FAILURE );
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " (" )
+ c->GetName() + wxS( ")" ) );
drcItem->SetItems( item );
drcItem->SetViolatingRule( c->GetParentRule() );
reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
} );
}
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_GENERIC_WARNING ) )
{
if( EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( item ) )
{
static wxRegEx warningExpr( wxS( "^\\$\\{DRC_WARNING\\s*([^}]*)\\}(.*)$" ) );
wxString text = textItem->GetText();
if( warningExpr.Matches( text ) )
{
auto drcItem = DRC_ITEM::Create( DRCE_ASSERTION_FAILURE );
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " (" )
+ c->GetName() + wxS( ")" ) );
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_GENERIC_WARNING );
drcItem->SetItems( item );
drcItem->SetViolatingRule( c->GetParentRule() );
drcItem->SetErrorMessage( warningExpr.GetMatch( text, 1 ) );
reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
} );
}
}
}
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_GENERIC_ERROR ) )
{
if( EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( item ) )
{
static wxRegEx errorExpr( wxS( "^\\$\\{DRC_ERROR\\s*([^}]*)\\}(.*)$" ) );
wxString text = textItem->GetText();
if( errorExpr.Matches( text ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_GENERIC_ERROR );
drcItem->SetItems( item );
drcItem->SetErrorMessage( errorExpr.GetMatch( text, 1 ) );
reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
}
}
}
return true;
};
@ -315,21 +355,18 @@ void DRC_TEST_PROVIDER_MISC::testTextVars()
if( !reportProgress( ii++, items, progressDelta ) )
return false;
BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( item );
EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( boardItem );
if( !textItem )
return true;
wxString resolved = ExpandEnvVarSubstitutions( textItem->GetShownText( true ),
nullptr /*project already done*/ );
if( resolved.Matches( wxT( "*${*}*" ) ) )
if( EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( item ) )
{
std::shared_ptr<DRC_ITEM>drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
drcItem->SetItems( item );
wxString result = ExpandEnvVarSubstitutions( textItem->GetShownText( true ),
nullptr /*project already done*/ );
reportViolation( drcItem, boardItem->GetPosition(), boardItem->GetLayer() );
if( result.Matches( wxT( "*${*}*" ) ) )
{
auto drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
drcItem->SetItems( item );
reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
}
}
return true;
@ -398,7 +435,9 @@ bool DRC_TEST_PROVIDER_MISC::Run()
testTextVars();
}
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_ASSERTION_FAILURE ) )
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_ASSERTION_FAILURE )
|| !m_drcEngine->IsErrorLimitExceeded( DRCE_GENERIC_WARNING )
|| !m_drcEngine->IsErrorLimitExceeded( DRCE_GENERIC_ERROR ) )
{
if( !reportPhase( _( "Checking assertions..." ) ) )
return false; // DRC cancelled

View File

@ -95,7 +95,9 @@ PCB_MARKER::~PCB_MARKER()
wxString PCB_MARKER::SerializeToString() const
{
if( m_rcItem->GetErrorCode() == DRCE_COPPER_SLIVER )
if( m_rcItem->GetErrorCode() == DRCE_COPPER_SLIVER
|| m_rcItem->GetErrorCode() == DRCE_GENERIC_WARNING
|| m_rcItem->GetErrorCode() == DRCE_GENERIC_ERROR )
{
return wxString::Format( wxT( "%s|%d|%d|%s|%s" ),
m_rcItem->GetSettingsKey(),
@ -156,12 +158,14 @@ PCB_MARKER* PCB_MARKER::DeserializeFromString( const wxString& data )
VECTOR2I markerPos( (int) strtol( props[1].c_str(), nullptr, 10 ),
(int) strtol( props[2].c_str(), nullptr, 10 ) );
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( props[0] );
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( props[0] );
if( !drcItem )
return nullptr;
if( drcItem->GetErrorCode() == DRCE_COPPER_SLIVER )
if( drcItem->GetErrorCode() == DRCE_COPPER_SLIVER
|| drcItem->GetErrorCode() == DRCE_GENERIC_WARNING
|| drcItem->GetErrorCode() == DRCE_GENERIC_ERROR )
{
drcItem->SetItems( KIID( props[3] ) );
markerLayer = getMarkerLayer( props[4] );
@ -279,6 +283,12 @@ SEVERITY PCB_MARKER::GetSeverity() const
return RPT_SEVERITY_EXCLUSION;
DRC_ITEM* item = static_cast<DRC_ITEM*>( m_rcItem.get() );
if( item->GetErrorCode() == DRCE_GENERIC_WARNING )
return RPT_SEVERITY_WARNING;
else if( item->GetErrorCode() == DRCE_GENERIC_ERROR )
return RPT_SEVERITY_ERROR;
DRC_RULE* rule = item->GetViolatingRule();
if( rule && rule->m_Severity != RPT_SEVERITY_UNDEFINED )