KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_incremental_netlister.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20
23
24#include <connection_graph.h>
25#include <schematic.h>
26#include <sch_sheet.h>
27#include <sch_screen.h>
28#include <sch_symbol.h>
29#include <sch_pin.h>
30#include <lib_symbol.h>
32#include <locale_io.h>
33
35{
38
40 std::unique_ptr<SCHEMATIC> m_schematic;
41};
42
44{
46
47 // Check for Errors when using global labels
48 std::vector<wxString> tests = {// "incremental_test",
49 // "issue10430",
50 // "issue10926_1",
51 // "issue11926",
52 // "issue12505",
53 // "issue12814",
54 // "issue13112",
55 // "issue13162",
56 // "issue13212",
57 // "issue13431",
58 // "issue13591",
59 // "issue16223",
60 // "issue6588",
61 "issue7203"};//,
62 // "issue9367"};
63
64 for( const wxString& test : tests )
65 {
66 KI_TEST::LoadSchematic( m_settingsManager, test, m_schematic );
67
68 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
69
70 for( const SCH_SHEET_PATH& path : sheets )
71 {
72 for( size_t ii = 0; ii < path.size(); ++ii )
73 {
74 const SCH_SHEET* sheet = path.GetSheet( ii );
75 const SCH_SCREEN* screen = sheet->GetScreen();
76 std::vector<SCH_ITEM*> items;
77
78 for( SCH_ITEM* item : screen->Items() )
79 {
80 if( !item->IsConnectable() )
81 {
82 continue;
83 }
84
85 if( item->Type() == SCH_SYMBOL_T )
86 {
87 for( SCH_PIN* pin : static_cast<SCH_SYMBOL*>( item )->GetPins() )
88 {
89 items.push_back( pin );
90 }
91 }
92 else
93 {
94 items.push_back( item );
95 }
96 }
97
98 for( SCH_ITEM* item : items )
99 {
100 const std::vector<SCH_ITEM*>& conn_items = item->ConnectedItems( path );
101 SCH_CONNECTION* conn = item->Connection();
102 wxString netname = conn ? conn->GetNetName().ToStdString() : wxString( "NoNet" );
103 int subgraph = conn ? conn->SubgraphCode() : -1;
104
105 BOOST_TEST_MESSAGE( test.ToStdString()
106 << ": Item " << item->GetFriendlyName().ToStdString()
107 << " in net " << netname.ToStdString() << " subgraph " << subgraph
108 << " has " << conn_items.size() << " connections" );
109
110 if( !conn )
111 continue;
112
113 if( !item->IsConnectable() )
114 continue;
115
116 std::vector<SCH_ITEM*> prev_items = item->ConnectedItems( path );
117 std::sort( prev_items.begin(), prev_items.end() );
118 alg::remove_duplicates( prev_items );
119
120 std::set<std::pair<SCH_SHEET_PATH, SCH_ITEM*>> all_items =
121 m_schematic->ConnectionGraph()->ExtractAffectedItems( { item } );
122 all_items.insert( { path, item } );
123 BOOST_TEST_MESSAGE( test.ToStdString()
124 << ": Item " << item->GetFriendlyName().ToStdString()
125 << " in net " << netname.ToStdString()
126 << " has " << all_items.size() << " affected items" );
127
128 CONNECTION_GRAPH new_graph( m_schematic.get() );
129
130 new_graph.SetLastCodes( m_schematic->ConnectionGraph() );
131
132 for( auto&[ apath, aitem ] : all_items )
133 {
134 wxCHECK2( aitem, continue );
135 aitem->SetConnectivityDirty();
136 }
137
138 new_graph.Recalculate( sheets, false );
139 m_schematic->ConnectionGraph()->Merge( new_graph );
140
141 std::vector<SCH_ITEM*> curr_items = item->ConnectedItems( path );
142 std::sort( curr_items.begin(), curr_items.end() );
143 alg::remove_duplicates( curr_items );
144
145 BOOST_CHECK_MESSAGE( prev_items == curr_items,
146 test.ToStdString()
147 << ": Item " << item->GetFriendlyName().ToStdString()
148 << " in net " << netname.ToStdString()
149 << " changed from " << prev_items.size() << " to " << curr_items.size()
150 << " Location:" << item->GetPosition().x << "," << item->GetPosition().y );
151 }
152
153 }
154 }
155 }
156}
157
158
159// Reproducer for Sentry KICAD-4SJ / KICAD-10HY. A pin on a shared (multi-instantiated) sheet is
160// registered in one subgraph per sheet path, but the connection graph's item-to-subgraph map only
161// remembers one of them. When SCH_SYMBOL::UpdatePins() frees the pin after a library update that
162// dropped it, ~SCH_ITEM only cleans the mapped subgraph and the other instance keeps a dangling
163// driver, which a later recalculation hands to CONNECTION_SUBGRAPH::ResolveDrivers().
164BOOST_FIXTURE_TEST_CASE( SharedSheetUpdatePinsNoDanglingDriver, CONNECTIVITY_TEST_FIXTURE )
165{
167
168 KI_TEST::LoadSchematic( m_settingsManager, wxS( "netlists/complex_hierarchy_shared/complex_hierarchy" ),
169 m_schematic );
170
171 CONNECTION_GRAPH* graph = m_schematic->ConnectionGraph();
172 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
173
174 std::map<SCH_SCREEN*, int> instanceCount;
175
176 for( const SCH_SHEET_PATH& path : sheets )
177 instanceCount[path.LastScreen()]++;
178
179 // Count how many retained subgraphs still reference an item. Pointer identity only; the
180 // pointer may be freed by the time this runs.
181 auto countRefs =
182 [&]( SCH_ITEM* aItem ) -> int
183 {
184 int refs = 0;
185
186 for( const auto& [key, subgraphs] : graph->GetNetMap() )
187 {
188 for( CONNECTION_SUBGRAPH* sg : subgraphs )
189 {
190 if( sg->GetItems().count( aItem ) )
191 refs++;
192 }
193 }
194
195 return refs;
196 };
197
198 // Find a pin on a shared screen that the initial full rebuild registered once per sheet path
199 SCH_SYMBOL* symbol = nullptr;
200 SCH_PIN* victim = nullptr;
201
202 for( auto& [screen, count] : instanceCount )
203 {
204 if( count < 2 )
205 continue;
206
207 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
208 {
209 SCH_SYMBOL* candidate = static_cast<SCH_SYMBOL*>( item );
210
211 if( !candidate->GetLibSymbolRef() || candidate->GetPins().size() < 2 )
212 continue;
213
214 for( SCH_PIN* pin : candidate->GetPins() )
215 {
216 if( countRefs( pin ) >= 2 )
217 {
218 symbol = candidate;
219 victim = pin;
220 break;
221 }
222 }
223
224 if( symbol )
225 break;
226 }
227
228 if( symbol )
229 break;
230 }
231
232 BOOST_REQUIRE_MESSAGE( symbol && victim, "No shared-sheet pin registered on multiple paths" );
233
234 wxString pinNumber = victim->GetNumber();
235 std::vector<SCH_PIN*> doomedPins = symbol->GetPinsByNumber( pinNumber );
236
237 BOOST_REQUIRE( !doomedPins.empty() );
238
239 std::vector<SCH_ITEM*> danglingCandidates( doomedPins.begin(), doomedPins.end() );
240
241 // Update the symbol from a library version that no longer has this pin. This mirrors
242 // Update Symbol from Library; SetLibSymbol() -> UpdatePins() frees the surplus SCH_PINs.
243 std::unique_ptr<LIB_SYMBOL> updated = symbol->GetLibSymbolRef()->Flatten();
244
245 for( SCH_PIN* libPin : updated->GetPinsByNumber( pinNumber ) )
246 updated->RemoveDrawItem( libPin );
247
248 symbol->SetLibSymbol( updated.release() );
249
250 BOOST_REQUIRE( symbol->GetPinsByNumber( pinNumber ).empty() );
251
252 // The freed pins must be gone from every retained subgraph, or the next incremental
253 // recalculation will dereference them from a thread pool worker
254 for( SCH_ITEM* freedPin : danglingCandidates )
255 {
256 BOOST_CHECK_MESSAGE( countRefs( freedPin ) == 0,
257 "Freed pin " << pinNumber.ToStdString()
258 << " still referenced by a retained subgraph" );
259 }
260}
Calculate the connectivity of a schematic and generates netlists.
const NET_MAP & GetNetMap() const
void Recalculate(const SCH_SHEET_LIST &aSheetList, bool aUnconditional=false, std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr)
Update the connection graph for the given list of sheets.
void SetLastCodes(const CONNECTION_GRAPH *aOther)
A subgraph is a set of items that are electrically connected on a single sheet.
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
wxString GetNetName() const
int SubgraphCode() const
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:162
const wxString & GetNumber() const
Definition sch_pin.h:130
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:115
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:44
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:139
Schematic symbol object.
Definition sch_symbol.h:69
std::vector< const SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
std::vector< SCH_PIN * > GetPinsByNumber(const wxString &aNumber) const
Find all symbol pins with the given number.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:177
void SetLibSymbol(LIB_SYMBOL *aLibSymbol)
Set this schematic symbol library symbol reference to aLibSymbol.
void LoadSchematic(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< SCHEMATIC > &aSchematic)
void remove_duplicates(_Container &__c)
Deletes all duplicate values from __c.
Definition kicad_algo.h:157
std::vector< FAB_LAYER_COLOR > dummy
std::unique_ptr< SCHEMATIC > m_schematic
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_FIXTURE_TEST_CASE(RemoveAddItems, CONNECTIVITY_TEST_FIXTURE)
std::string path
KIBIS_PIN * pin
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
@ SCH_SYMBOL_T
Definition typeinfo.h:169