7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-21 00:21:25 +00:00

Handle ERC/DRC assertions in drawing sheet.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19132
This commit is contained in:
Jeff Young 2024-12-02 20:12:53 +00:00
parent 55ca13e7cf
commit 4883c27972
8 changed files with 122 additions and 76 deletions

View File

@ -56,7 +56,7 @@ enum Bracket
};
wxString ExpandTextVars( const wxString& aSource, const PROJECT* aProject )
wxString ExpandTextVars( const wxString& aSource, const PROJECT* aProject, int aFlags )
{
std::function<bool( wxString* )> projectResolver =
[&]( wxString* token ) -> bool
@ -64,12 +64,12 @@ wxString ExpandTextVars( const wxString& aSource, const PROJECT* aProject )
return aProject->TextVarResolver( token );
};
return ExpandTextVars( aSource, &projectResolver );
return ExpandTextVars( aSource, &projectResolver, aFlags );
}
wxString ExpandTextVars( const wxString& aSource,
const std::function<bool( wxString* )>* aResolver )
const std::function<bool( wxString* )>* aResolver, int aFlags )
{
static wxRegEx userDefinedWarningError( wxS( "^(ERC|DRC)_(WARNING|ERROR).*$" ) );
wxString newbuf;
@ -94,7 +94,7 @@ wxString ExpandTextVars( const wxString& aSource,
if( token.IsEmpty() )
continue;
if( userDefinedWarningError.Matches( token ) )
if( ( aFlags & FOR_ERC_DRC ) == 0 && userDefinedWarningError.Matches( token ) )
{
// Only show user-defined warnings/errors during ERC/DRC
}

View File

@ -173,7 +173,7 @@ wxString DS_DRAW_ITEM_LIST::BuildFullText( const wxString& aTextbase )
}
else if( m_titleBlock )
{
if( m_titleBlock->TextVarResolver( token, m_project ) )
if( m_titleBlock->TextVarResolver( token, m_project, m_flags ) )
{
// No need for tokenUpdated; TITLE_BLOCK::TextVarResolver() already goes
// up to the project.
@ -185,7 +185,7 @@ wxString DS_DRAW_ITEM_LIST::BuildFullText( const wxString& aTextbase )
m_titleBlock = nullptr;
{
*token = ExpandTextVars( *token, &wsResolver );
*token = ExpandTextVars( *token, &wsResolver, m_flags );
}
m_titleBlock = savedTitleBlock;
@ -200,7 +200,7 @@ wxString DS_DRAW_ITEM_LIST::BuildFullText( const wxString& aTextbase )
if( tokenUpdated )
{
*token = ExpandTextVars( *token, m_project );
*token = ExpandTextVars( *token, m_project, m_flags );
return true;
}
@ -210,7 +210,7 @@ wxString DS_DRAW_ITEM_LIST::BuildFullText( const wxString& aTextbase )
return false;
};
return ExpandTextVars( aTextbase, &wsResolver );
return ExpandTextVars( aTextbase, &wsResolver, m_flags );
}

View File

@ -92,7 +92,7 @@ void TITLE_BLOCK::GetContextualTextVars( wxArrayString* aVars )
}
bool TITLE_BLOCK::TextVarResolver( wxString* aToken, const PROJECT* aProject ) const
bool TITLE_BLOCK::TextVarResolver( wxString* aToken, const PROJECT* aProject, int aFlags ) const
{
bool tokenUpdated = false;
wxString originalToken = *aToken;
@ -159,7 +159,7 @@ bool TITLE_BLOCK::TextVarResolver( wxString* aToken, const PROJECT* aProject ) c
if( aToken->IsSameAs( wxT( "CURRENT_DATE" ) ) )
*aToken = getCurrentDate();
else if( aProject )
*aToken = ExpandTextVars( *aToken, aProject );
*aToken = ExpandTextVars( *aToken, aProject, aFlags );
// This is the default fallback, so don't claim we resolved it
if( *aToken == wxT( "${" ) + originalToken + wxT( "}" ) )

View File

@ -182,7 +182,7 @@ int ERC_TESTER::TestDuplicateSheetNames( bool aCreateMarker )
void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
{
DS_DRAW_ITEM_LIST wsItems( schIUScale );
DS_DRAW_ITEM_LIST wsItems( schIUScale, FOR_ERC_DRC );
auto unresolved =
[this]( wxString str )
@ -193,7 +193,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
auto testAssertion =
[]( const SCH_ITEM* item, const SCH_SHEET_PATH& sheet, SCH_SCREEN* screen,
const wxString& text )
const wxString& text, const VECTOR2I& pos )
{
static wxRegEx warningExpr( wxS( "^\\$\\{ERC_WARNING\\s*([^}]*)\\}(.*)$" ) );
static wxRegEx errorExpr( wxS( "^\\$\\{ERC_ERROR\\s*([^}]*)\\}(.*)$" ) );
@ -201,26 +201,42 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
if( warningExpr.Matches( text ) )
{
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_GENERIC_WARNING );
wxString ercText = warningExpr.GetMatch( text, 1 );
if( item )
ercItem->SetItems( item );
else
ercText += _( " (in drawing sheet)" );
ercItem->SetItems( item );
ercItem->SetSheetSpecificPath( sheet );
ercItem->SetErrorMessage( warningExpr.GetMatch( text, 1 ) );
ercItem->SetErrorMessage( ercText );
SCH_MARKER* marker = new SCH_MARKER( ercItem, item->GetPosition() );
SCH_MARKER* marker = new SCH_MARKER( ercItem, pos );
screen->Append( marker );
return true;
}
if( errorExpr.Matches( text ) )
{
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_GENERIC_ERROR );
wxString ercText = errorExpr.GetMatch( text, 1 );
if( item )
ercItem->SetItems( item );
else
ercText += _( " (in drawing sheet)" );
ercItem->SetItems( item );
ercItem->SetSheetSpecificPath( sheet );
ercItem->SetErrorMessage( errorExpr.GetMatch( text, 1 ) );
ercItem->SetErrorMessage( ercText );
SCH_MARKER* marker = new SCH_MARKER( ercItem, item->GetPosition() );
SCH_MARKER* marker = new SCH_MARKER( ercItem, pos );
screen->Append( marker );
return true;
}
return false;
};
if( aDrawingSheet )
@ -256,7 +272,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
screen->Append( marker );
}
testAssertion( &field, sheet, screen, field.GetText() );
testAssertion( &field, sheet, screen, field.GetText(), field.GetPosition() );
}
symbol->GetLibSymbolRef()->RunOnChildren(
@ -284,7 +300,8 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
screen->Append( marker );
}
testAssertion( symbol, sheet, screen, textItem->GetText() );
testAssertion( symbol, sheet, screen, textItem->GetText(),
textItem->GetPosition() );
}
else if( child->Type() == SCH_TEXTBOX_T )
{
@ -304,7 +321,8 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
screen->Append( marker );
}
testAssertion( symbol, sheet, screen, textboxItem->GetText() );
testAssertion( symbol, sheet, screen, textboxItem->GetText(),
textboxItem->GetPosition() );
}
} );
}
@ -322,7 +340,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
screen->Append( marker );
}
testAssertion( &field, sheet, screen, field.GetText() );
testAssertion( &field, sheet, screen, field.GetText(), field.GetPosition() );
}
}
else if( item->Type() == SCH_SHEET_T )
@ -341,7 +359,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
screen->Append( marker );
}
testAssertion( &field, sheet, screen, field.GetText() );
testAssertion( &field, sheet, screen, field.GetText(), field.GetPosition() );
}
SCH_SHEET_PATH subSheetPath = sheet;
@ -372,7 +390,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
screen->Append( marker );
}
testAssertion( text, sheet, screen, text->GetText() );
testAssertion( text, sheet, screen, text->GetText(), text->GetPosition() );
}
else if( SCH_TEXTBOX* textBox = dynamic_cast<SCH_TEXTBOX*>( item ) )
{
@ -386,7 +404,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
screen->Append( marker );
}
testAssertion( textBox, sheet, screen, textBox->GetText() );
testAssertion( textBox, sheet, screen, textBox->GetText(), textBox->GetPosition() );
}
}
@ -394,7 +412,11 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
{
if( DS_DRAW_ITEM_TEXT* text = dynamic_cast<DS_DRAW_ITEM_TEXT*>( item ) )
{
if( text->GetShownText( true ).Matches( wxS( "*${*}*" ) ) )
if( testAssertion( nullptr, sheet, screen, text->GetText(), text->GetPosition() ) )
{
// Don't run unresolved test
}
else if( text->GetShownText( true ).Matches( wxS( "*${*}*" ) ) )
{
std::shared_ptr<ERC_ITEM> erc = ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
erc->SetErrorMessage( _( "Unresolved text variable in drawing sheet" ) );

View File

@ -88,10 +88,14 @@ KICOMMON_API const wxString ExpandEnvVarSubstitutions( const wxString& aString,
/**
* Expand '${var-name}' templates in text.
*/
KICOMMON_API wxString ExpandTextVars( const wxString& aSource,
const std::function<bool( wxString* )>* aResolver );
#define FOR_ERC_DRC 1
KICOMMON_API wxString ExpandTextVars( const wxString& aSource, const PROJECT* aProject );
KICOMMON_API wxString ExpandTextVars( const wxString& aSource,
const std::function<bool( wxString* )>* aResolver,
int aFlags = 0 );
KICOMMON_API wxString ExpandTextVars( const wxString& aSource, const PROJECT* aProject,
int aFlags = 0 );
/**
* Returns any variables unexpanded, e.g. ${VAR} -> VAR

View File

@ -400,7 +400,7 @@ private:
class DS_DRAW_ITEM_LIST
{
public:
DS_DRAW_ITEM_LIST( const EDA_IU_SCALE& aIuScale ) :
DS_DRAW_ITEM_LIST( const EDA_IU_SCALE& aIuScale, int aFlags = 0 ) :
m_iuScale( aIuScale )
{
m_idx = 0;
@ -411,6 +411,7 @@ public:
m_titleBlock = nullptr;
m_project = nullptr;
m_isFirstPage = true;
m_flags = aFlags;
m_properties = nullptr;
}
@ -578,6 +579,7 @@ protected:
wxString m_pageNumber; ///< The actual page number displayed in the title block.
wxString m_sheetLayer; // for text variable references
const PROJECT* m_project; // for project-based text variable references
int m_flags;
const std::map<wxString, wxString>* m_properties; // for text variable references
};

View File

@ -116,7 +116,7 @@ public:
}
static void GetContextualTextVars( wxArrayString* aVars );
bool TextVarResolver( wxString* aToken, const PROJECT* aProject ) const;
bool TextVarResolver( wxString* aToken, const PROJECT* aProject, int aFlags = 0 ) const;
/**
* Output the object to \a aFormatter in s-expression form.

View File

@ -280,44 +280,6 @@ void DRC_TEST_PROVIDER_MISC::testAssertions()
} );
}
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 ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_GENERIC_WARNING );
drcItem->SetItems( item );
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;
};
@ -339,6 +301,55 @@ void DRC_TEST_PROVIDER_MISC::testTextVars()
PCB_DIMENSION_T
};
auto testAssertion =
[&]( BOARD_ITEM* item, const wxString& text, const VECTOR2I& pos, int layer )
{
static wxRegEx warningExpr( wxS( "^\\$\\{DRC_WARNING\\s*([^}]*)\\}(.*)$" ) );
static wxRegEx errorExpr( wxS( "^\\$\\{DRC_ERROR\\s*([^}]*)\\}(.*)$" ) );
if( warningExpr.Matches( text ) )
{
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_GENERIC_WARNING ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_GENERIC_WARNING );
wxString drcText = warningExpr.GetMatch( text, 1 );
if( item )
drcItem->SetItems( item );
else
drcText += _( " (in drawing sheet)" );
drcItem->SetErrorMessage( drcText );
reportViolation( drcItem, pos, layer );
}
return true;
}
if( errorExpr.Matches( text ) )
{
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_GENERIC_ERROR ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_GENERIC_ERROR );
wxString drcText = errorExpr.GetMatch( text, 1 );
if( item )
drcItem->SetItems( item );
else
drcText += _( " (in drawing sheet)" );
drcItem->SetErrorMessage( drcText );
reportViolation( drcItem, pos, layer );
}
return true;
}
return false;
};
forEachGeometryItem( itemTypes, LSET::AllLayersMask(),
[&]( BOARD_ITEM* item ) -> bool
{
@ -367,13 +378,15 @@ void DRC_TEST_PROVIDER_MISC::testTextVars()
reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
}
testAssertion( item, textItem->GetText(), item->GetPosition(), item->GetLayer() );
}
return true;
} );
DS_PROXY_VIEW_ITEM* drawingSheet = m_drcEngine->GetDrawingSheet();
DS_DRAW_ITEM_LIST drawItems( pcbIUScale );
DS_DRAW_ITEM_LIST drawItems( pcbIUScale, FOR_ERC_DRC );
if( !drawingSheet || m_drcEngine->IsErrorLimitExceeded( DRCE_UNRESOLVED_VARIABLE ) )
return;
@ -394,14 +407,19 @@ void DRC_TEST_PROVIDER_MISC::testTextVars()
if( m_drcEngine->IsCancelled() )
return;
DS_DRAW_ITEM_TEXT* text = dynamic_cast<DS_DRAW_ITEM_TEXT*>( item );
if( text && text->GetShownText( true ).Matches( wxT( "*${*}*" ) ) )
if( DS_DRAW_ITEM_TEXT* text = dynamic_cast<DS_DRAW_ITEM_TEXT*>( item ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
drcItem->SetItems( drawingSheet );
if( testAssertion( nullptr, text->GetText(), text->GetPosition(), LAYER_DRAWINGSHEET ) )
{
// Don't run unresolved test
}
else if( text->GetShownText( true ).Matches( wxT( "*${*}*" ) ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
drcItem->SetItems( drawingSheet );
reportViolation( drcItem, text->GetPosition(), LAYER_DRAWINGSHEET );
reportViolation( drcItem, text->GetPosition(), LAYER_DRAWINGSHEET );
}
}
}
}