From 7126375646d1c9a985eaa43e51dc13831c12606f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 17 Sep 2023 19:26:18 +0200 Subject: [PATCH] WIP --- src/db/db/db.pro | 2 + src/db/db/dbLayoutToNetlist.cc | 15 ++++++ src/db/db/dbLayoutToNetlist.h | 32 +++++++++++- src/db/db/dbLayoutToNetlistFormatDefs.cc | 14 +++++- src/db/db/dbLayoutToNetlistFormatDefs.h | 21 +++++++- src/db/db/dbLayoutToNetlistReader.cc | 53 ++++++++++++++++++++ src/db/db/dbLayoutToNetlistReader.h | 21 ++++---- src/db/db/dbLayoutToNetlistWriter.cc | 34 +++++++++++++ src/db/db/dbLayoutToNetlistWriter.h | 4 ++ src/db/db/dbLayoutVsSchematicFormatDefs.cc | 10 +--- src/db/db/dbLayoutVsSchematicFormatDefs.h | 20 +++----- src/db/db/dbLayoutVsSchematicReader.cc | 38 +++------------ src/db/db/dbLayoutVsSchematicReader.h | 5 +- src/db/db/dbLayoutVsSchematicWriter.cc | 54 ++++++++------------ src/db/db/dbLog.cc | 31 ++++++++++++ src/db/db/dbLog.h | 57 ++++++++++++++++++++++ src/db/db/dbNetlistCompare.cc | 10 ++-- src/db/db/dbNetlistCompare.h | 13 +---- src/db/db/dbNetlistCompareCore.cc | 14 +++--- src/db/db/dbNetlistCrossReference.h | 9 ---- src/db/db/dbNetlistDeviceExtractor.h | 8 +++ src/db/db/gsiDeclDbNetlistCompare.cc | 16 +++--- src/layui/layui/layNetlistBrowserPage.cc | 4 +- src/layui/layui/layNetlistLogModel.cc | 15 +++--- 24 files changed, 347 insertions(+), 153 deletions(-) create mode 100644 src/db/db/dbLog.cc create mode 100644 src/db/db/dbLog.h diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 6914e12fa..ac7f6ec76 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -50,6 +50,7 @@ SOURCES = \ dbLibraryManager.cc \ dbLibraryProxy.cc \ dbLoadLayoutOptions.cc \ + dbLog.cc \ dbManager.cc \ dbMatrix.cc \ dbMemStatistics.cc \ @@ -271,6 +272,7 @@ HEADERS = \ dbLibraryManager.h \ dbLibraryProxy.h \ dbLoadLayoutOptions.h \ + dbLog.h \ dbManager.h \ dbMatrix.h \ dbMemStatistics.h \ diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 83395e612..19d31468b 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -33,6 +33,7 @@ #include "dbLayoutToNetlistFormatDefs.h" #include "dbLayoutVsSchematicFormatDefs.h" #include "dbShapeProcessor.h" +#include "dbLog.h" #include "tlGlobPattern.h" namespace db @@ -238,8 +239,16 @@ void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, co if (m_netlist_extracted) { throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted"))); } + ensure_netlist (); + + extractor.clear_errors (); extractor.extract (dss (), m_layout_index, layers, *mp_netlist, m_net_clusters, m_device_scaling); + + // transfer errors to log entries + for (auto e = extractor.begin_errors (); e != extractor.end_errors (); ++e) { + m_log_entries.push_back (db::LogEntryData (db::Error, e->to_string ())); + } } void LayoutToNetlist::reset_extracted () @@ -249,6 +258,8 @@ void LayoutToNetlist::reset_extracted () m_net_clusters.clear (); mp_netlist.reset (0); + m_log_entries.clear (); + m_netlist_extracted = false; } @@ -362,6 +373,7 @@ void LayoutToNetlist::extract_netlist () db::NetlistExtractor netex; +#if 0 // @@@ remove this plus corresponding code inside NetlistExtractor ... netex.set_joined_net_names (m_joined_net_names); std::map > jp_per_cell; @@ -397,10 +409,13 @@ void LayoutToNetlist::extract_netlist () for (std::map > >::const_iterator i = jn_per_cell.begin (); i != jn_per_cell.end (); ++i) { netex.set_joined_nets (i->first, i->second); } + #endif netex.set_include_floating_subcircuits (m_include_floating_subcircuits); netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters); + // @@@ join_nets (); + if (tl::verbosity () >= 41) { MemStatisticsCollector m (false); mem_stat (&m, db::MemStatistics::None, 0); diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index e6bb022af..e159e46e4 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -28,6 +28,7 @@ #include "dbNetlistExtractor.h" #include "dbNetlistDeviceExtractor.h" #include "dbLayoutToNetlistEnums.h" +#include "dbLog.h" #include "tlGlobPattern.h" namespace db @@ -78,6 +79,7 @@ class DB_PUBLIC LayoutToNetlist { public: typedef std::map::const_iterator layer_iterator; + typedef std::vector log_entries_type; /** * @brief The constructor @@ -190,6 +192,33 @@ public: m_filename = filename; } + /** + * @brief Gets the log entries + * @@@ TODO: provide GSI interface + */ + const log_entries_type &log_entries () const + { + return m_log_entries; + } + + /** + * @brief Clears the log entries + * @@@ TODO: provide GSI interface + */ + void clear_log_entries () + { + m_log_entries.clear (); + } + + /** + * @brief Adds a log entry + * @@@ TODO: provide GSI interface + */ + void log_entry (const db::LogEntryData &log_entry) + { + m_log_entries.push_back (log_entry); + } + /** * @brief Sets the number of threads to use for operations which support multiple threads */ @@ -388,7 +417,7 @@ public: * @brief Resets the extracted netlist * * This method will invalidate the netlist and extraction. It is called automatically when - * cone of the connect methods is called. + * one of the connect methods is called. */ void reset_extracted (); @@ -930,6 +959,7 @@ private: std::string m_name; std::string m_original_file; std::string m_filename; + log_entries_type m_log_entries; db::RecursiveShapeIterator m_iter; std::unique_ptr mp_internal_dss; tl::weak_ptr mp_dss; diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.cc b/src/db/db/dbLayoutToNetlistFormatDefs.cc index 133a4cbd3..c317ac857 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.cc +++ b/src/db/db/dbLayoutToNetlistFormatDefs.cc @@ -56,8 +56,13 @@ namespace l2n_std_format DB_PUBLIC std::string LongKeys::mirror_key ("mirror"); DB_PUBLIC std::string LongKeys::scale_key ("scale"); DB_PUBLIC std::string LongKeys::pin_key ("pin"); + DB_PUBLIC std::string LongKeys::message_key ("message"); - // A, B, C, D, E, F, G, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y + DB_PUBLIC std::string LongKeys::info_severity_key ("info"); + DB_PUBLIC std::string LongKeys::warning_severity_key ("warning"); + DB_PUBLIC std::string LongKeys::error_severity_key ("error"); + + // A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y DB_PUBLIC std::string ShortKeys::version_key ("V"); DB_PUBLIC std::string ShortKeys::description_key ("B"); DB_PUBLIC std::string ShortKeys::top_key ("W"); @@ -82,6 +87,13 @@ namespace l2n_std_format DB_PUBLIC std::string ShortKeys::mirror_key ("M"); DB_PUBLIC std::string ShortKeys::scale_key ("S"); DB_PUBLIC std::string ShortKeys::pin_key ("P"); + DB_PUBLIC std::string ShortKeys::message_key ("H"); + + // I, W, E + + DB_PUBLIC std::string ShortKeys::info_severity_key ("I"); + DB_PUBLIC std::string ShortKeys::warning_severity_key ("W"); + DB_PUBLIC std::string ShortKeys::error_severity_key ("E"); } } diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index b0818ff47..ea09112ff 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -47,7 +47,7 @@ namespace db * (circuits before subcircuits, nets before use ...) * * Main body: - * [version|description|unit|top|layer|connect|global|circuit|class|device|any]* + * [version|description|unit|top|layer|connect|global|circuit|class|device|message-entry|any]* * * [version]: * version() - file format version [short key: V] @@ -181,6 +181,17 @@ namespace db * mirror - if specified, the instance is mirrored before rotation [short key: M] * scale() - magnification (default is 1) [short key: S] * + * [message-entry]: + * message([severity] [message|any]*) - message entry [short key: H] + * + * [message]: + * description() - error description [short key: B] + * + * [severity]: + * info | - [short key: I] + * warning | - [short key: W] + * error - [short key: E] + * * [any]: * * | * | @@ -220,8 +231,12 @@ namespace l2n_std_format static std::string mirror_key; static std::string scale_key; static std::string pin_key; + static std::string message_key; static std::string indent1; static std::string indent2; + static std::string info_severity_key; + static std::string warning_severity_key; + static std::string error_severity_key; }; struct DB_PUBLIC LongKeys @@ -253,8 +268,12 @@ namespace l2n_std_format static std::string mirror_key; static std::string scale_key; static std::string pin_key; + static std::string message_key; static std::string indent1; static std::string indent2; + static std::string info_severity_key; + static std::string warning_severity_key; + static std::string error_severity_key; }; template struct DB_PUBLIC keys; diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index 033a8fb79..0b980ebbb 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -184,6 +184,52 @@ void LayoutToNetlistStandardReader::skip_element () } } +bool LayoutToNetlistStandardReader::read_message (std::string &msg) +{ + if (test (skeys::description_key) || test (lkeys::description_key)) { + Brace br (this); + read_word_or_quoted (msg); + br.done (); + return true; + } else { + return false; + } +} + +bool LayoutToNetlistStandardReader::read_severity (db::Severity &severity) +{ + if (test (skeys::info_severity_key) || test (lkeys::info_severity_key)) { + severity = db::Info; + return true; + } else if (test (skeys::warning_severity_key) || test (lkeys::warning_severity_key)) { + severity = db::Warning; + return true; + } else if (test (skeys::error_severity_key) || test (lkeys::error_severity_key)) { + severity = db::Error; + return true; + } else { + return false; + } +} + +void LayoutToNetlistStandardReader::read_message_entry (db::LogEntryData &data) +{ + data.severity = db::NoSeverity; + data.msg.clear (); + + Brace br (this); + while (br) { + if (read_severity (data.severity)) { + // continue + } else if (read_message (data.msg)) { + // continue + } else { + skip_element (); + } + } + br.done (); +} + void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) { tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + m_path); @@ -359,6 +405,13 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo } br.done (); + } else if (l2n && (test (skeys::message_key) || test (lkeys::message_key))) { + + db::LogEntryData data; + read_message_entry (data); + + l2n->log_entry (data); + } else if (l2n && (test (skeys::global_key) || test (lkeys::global_key))) { Brace br (this); diff --git a/src/db/db/dbLayoutToNetlistReader.h b/src/db/db/dbLayoutToNetlistReader.h index 46c917d3f..367e5c4e6 100644 --- a/src/db/db/dbLayoutToNetlistReader.h +++ b/src/db/db/dbLayoutToNetlistReader.h @@ -109,6 +109,8 @@ protected: void read_netlist (Netlist *netlist, db::LayoutToNetlist *l2n, Brace *nested = 0, std::map *map_per_circuit = 0); static size_t terminal_id (const db::DeviceClass *device_class, const std::string &tname); static std::pair device_model_by_name (db::Netlist *netlist, const std::string &dmname); + bool read_message (std::string &msg); + bool read_severity (Severity &severity); const std::string &path () const { @@ -140,6 +142,15 @@ protected: void skip (); void skip_element (); +private: + tl::TextInputStream m_stream; + std::string m_path; + std::string m_line; + double m_dbu; + tl::Extractor m_ex; + db::Point m_ref; + tl::AbsoluteProgress m_progress; + void read_net (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, ObjectMap &map); void read_pin (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, ObjectMap &map); void read_device (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, ObjectMap &map, std::map > &connections); @@ -151,15 +162,7 @@ protected: db::Box read_rect (); void read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster &lc, db::Cell &cell); db::Point read_point (); - -private: - tl::TextInputStream m_stream; - std::string m_path; - std::string m_line; - double m_dbu; - tl::Extractor m_ex; - db::Point m_ref; - tl::AbsoluteProgress m_progress; + void read_message_entry (db::LogEntryData &data); }; } diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index 1713ee504..86e254a2f 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -142,6 +142,30 @@ std_writer_impl::std_writer_impl (tl::OutputStream &stream, double dbu, co m_progress.set_unit (1024 * 1024); } +template +std::string std_writer_impl::message_to_s (const std::string &msg) +{ + if (msg.empty ()) { + return std::string (); + } else { + return Keys::description_key + "(" + tl::to_word_or_quoted_string (msg) + ")"; + } +} + +template +std::string std_writer_impl::severity_to_s (const db::Severity severity) +{ + if (severity == db::Info) { + return Keys::info_severity_key; + } else if (severity == db::Warning) { + return Keys::warning_severity_key; + } else if (severity == db::Error) { + return Keys::error_severity_key; + } else { + return std::string (); + } +} + static std::string name_for_layer (const db::LayoutToNetlist *l2n, unsigned int l) { std::string n = l2n->name (l); @@ -318,6 +342,16 @@ void std_writer_impl::write (bool nested, TokenizedOutput &stream, std::ma } + if (! mp_l2n->log_entries ().empty ()) { + if (! Keys::is_short ()) { + stream << endl << "# Log entries" << endl; + } + for (auto l = mp_l2n->log_entries ().begin (); l != mp_l2n->log_entries ().end (); ++l) { + TokenizedOutput (stream, Keys::message_key) << severity_to_s (l->severity) << message_to_s (l->msg); + m_progress.set (mp_stream->pos ()); + } + } + } if (mp_netlist->begin_device_classes () != mp_netlist->end_device_classes () && ! Keys::is_short ()) { diff --git a/src/db/db/dbLayoutToNetlistWriter.h b/src/db/db/dbLayoutToNetlistWriter.h index 8032e2651..25c175f9f 100644 --- a/src/db/db/dbLayoutToNetlistWriter.h +++ b/src/db/db/dbLayoutToNetlistWriter.h @@ -28,6 +28,7 @@ #include "dbTrans.h" #include "dbPolygon.h" #include "dbHierNetworkProcessor.h" +#include "dbLog.h" #include "tlStream.h" #include "tlProgress.h" @@ -92,6 +93,9 @@ protected: return *mp_stream; } + std::string severity_to_s (const db::Severity severity); + std::string message_to_s (const std::string &msg); + private: tl::OutputStream *mp_stream; db::Point m_ref; diff --git a/src/db/db/dbLayoutVsSchematicFormatDefs.cc b/src/db/db/dbLayoutVsSchematicFormatDefs.cc index 62de797d0..12f88601e 100644 --- a/src/db/db/dbLayoutVsSchematicFormatDefs.cc +++ b/src/db/db/dbLayoutVsSchematicFormatDefs.cc @@ -43,11 +43,7 @@ namespace lvs_std_format DB_PUBLIC std::string LongKeys::warning_key ("warning"); DB_PUBLIC std::string LongKeys::skipped_key ("skipped"); - DB_PUBLIC std::string LongKeys::info_severity_key ("info"); - DB_PUBLIC std::string LongKeys::warning_severity_key ("warning"); - DB_PUBLIC std::string LongKeys::error_severity_key ("error"); - - // E, H, I, J, L, M, S, W, X, Z, 0, 1 + // H, J, L, M, S, X, Z, 0, 1 DB_PUBLIC std::string ShortKeys::reference_key ("H"); DB_PUBLIC std::string ShortKeys::layout_key ("J"); @@ -60,10 +56,6 @@ namespace lvs_std_format DB_PUBLIC std::string ShortKeys::nomatch_key ("X"); DB_PUBLIC std::string ShortKeys::warning_key ("W"); DB_PUBLIC std::string ShortKeys::skipped_key ("S"); - - DB_PUBLIC std::string ShortKeys::info_severity_key ("I"); - DB_PUBLIC std::string ShortKeys::warning_severity_key ("W"); - DB_PUBLIC std::string ShortKeys::error_severity_key ("E"); } } diff --git a/src/db/db/dbLayoutVsSchematicFormatDefs.h b/src/db/db/dbLayoutVsSchematicFormatDefs.h index 9703a70b8..80abceaac 100644 --- a/src/db/db/dbLayoutVsSchematicFormatDefs.h +++ b/src/db/db/dbLayoutVsSchematicFormatDefs.h @@ -67,7 +67,7 @@ namespace db * Content is the Netlist dump (reduced version of LayoutToNetlist) * * [xrefs]: - * xref([xref|any]*) - cross-reference part [short key: Z] + * xref([xref|log|any]*) - cross-reference part [short key: Z] * * [xref]: * circuit([non] [non] [status|message|log|circuit-xrefs|any]*) @@ -82,11 +82,6 @@ namespace db * [log-entry]: * entry([severity] [message|any]*) - log entry [short key: M] * - * [severity]: - * info | - [short key: I] - * warning | - [short key: W] - * error - [short key: E] - * * [circuit-xrefs]: * xref([xref-pin|xref-device|xref-circuit|xref-net|any]*) * - circuit cross-reference part [short key: Z] @@ -113,6 +108,11 @@ namespace db * [message]: * description() - error description [short key: B] * + * [severity]: + * info | - [short key: I] + * warning | - [short key: W] + * error - [short key: E] + * * [status]: * mismatch | - [short key: 0] * match | - [short key: 1] @@ -145,10 +145,6 @@ namespace lvs_std_format static std::string nomatch_key; static std::string warning_key; static std::string skipped_key; - - static std::string info_severity_key; - static std::string warning_severity_key; - static std::string error_severity_key; }; struct DB_PUBLIC LongKeys @@ -166,10 +162,6 @@ namespace lvs_std_format static std::string nomatch_key; static std::string warning_key; static std::string skipped_key; - - static std::string info_severity_key; - static std::string warning_severity_key; - static std::string error_severity_key; }; template struct DB_PUBLIC keys; diff --git a/src/db/db/dbLayoutVsSchematicReader.cc b/src/db/db/dbLayoutVsSchematicReader.cc index 42f76e27f..1101d1d56 100644 --- a/src/db/db/dbLayoutVsSchematicReader.cc +++ b/src/db/db/dbLayoutVsSchematicReader.cc @@ -116,18 +116,6 @@ void LayoutVsSchematicStandardReader::read_netlist (db::LayoutVsSchematic *lvs) } } -bool LayoutVsSchematicStandardReader::read_message (std::string &msg) -{ - if (test (skeys::description_key) || test (lkeys::description_key)) { - Brace br (this); - read_word_or_quoted (msg); - br.done (); - return true; - } else { - return false; - } -} - bool LayoutVsSchematicStandardReader::read_status (db::NetlistCrossReference::Status &status) { if (test (skeys::match_key) || test (lkeys::match_key)) { @@ -150,25 +138,9 @@ bool LayoutVsSchematicStandardReader::read_status (db::NetlistCrossReference::St } } -bool LayoutVsSchematicStandardReader::read_severity (db::NetlistCrossReference::Severity &severity) -{ - if (test (skeys::info_severity_key) || test (lkeys::info_severity_key)) { - severity = db::NetlistCrossReference::Info; - return true; - } else if (test (skeys::warning_severity_key) || test (lkeys::warning_severity_key)) { - severity = db::NetlistCrossReference::Warning; - return true; - } else if (test (skeys::error_severity_key) || test (lkeys::error_severity_key)) { - severity = db::NetlistCrossReference::Error; - return true; - } else { - return false; - } -} - void LayoutVsSchematicStandardReader::read_log_entry (db::NetlistCrossReference *xref) { - db::NetlistCrossReference::Severity severity = db::NetlistCrossReference::NoSeverity; + db::Severity severity = db::NoSeverity; std::string msg; Brace br (this); @@ -186,7 +158,7 @@ void LayoutVsSchematicStandardReader::read_log_entry (db::NetlistCrossReference xref->log_entry (severity, msg); } -void LayoutVsSchematicStandardReader::read_logs_for_circuits (db::NetlistCrossReference *xref) +void LayoutVsSchematicStandardReader::read_logs (db::NetlistCrossReference *xref) { Brace br (this); while (br) { @@ -194,7 +166,7 @@ void LayoutVsSchematicStandardReader::read_logs_for_circuits (db::NetlistCrossRe if (test (skeys::log_entry_key) || test (lkeys::log_entry_key)) { read_log_entry (xref); } else if (at_end ()) { - throw tl::Exception (tl::to_string (tr ("Unexpected end of file inside circuit definition (net, pin, device or circuit expected)"))); + throw tl::Exception (tl::to_string (tr ("Unexpected end of file inside log section (entry expected)"))); } else { skip_element (); } @@ -269,7 +241,7 @@ void LayoutVsSchematicStandardReader::read_xref (db::NetlistCrossReference *xref } else if (test (skeys::xref_key) || test (lkeys::xref_key)) { read_xrefs_for_circuits (xref, circuit_a, circuit_b); } else if (test (skeys::log_key) || test (lkeys::log_key)) { - read_logs_for_circuits (xref); + read_logs (xref); } else if (at_end ()) { throw tl::Exception (tl::to_string (tr ("Unexpected end of file inside circuit definition (status keyword of xrefs expected)"))); } else { @@ -282,6 +254,8 @@ void LayoutVsSchematicStandardReader::read_xref (db::NetlistCrossReference *xref br.done (); + } else if (test (skeys::log_key) || test (lkeys::log_key)) { + read_logs (xref); } else { skip_element (); } diff --git a/src/db/db/dbLayoutVsSchematicReader.h b/src/db/db/dbLayoutVsSchematicReader.h index 08aa9e5a1..7e0e98c36 100644 --- a/src/db/db/dbLayoutVsSchematicReader.h +++ b/src/db/db/dbLayoutVsSchematicReader.h @@ -28,6 +28,7 @@ #include "dbCell.h" #include "dbLayoutVsSchematic.h" #include "dbLayoutToNetlistReader.h" +#include "dbLog.h" #include "tlStream.h" namespace db { @@ -78,10 +79,8 @@ private: void read_netlist (db::LayoutVsSchematic *lvs); bool read_status (db::NetlistCrossReference::Status &status); - bool read_message (std::string &msg); void read_log_entry (db::NetlistCrossReference *xref); - void read_logs_for_circuits (db::NetlistCrossReference *xref); - bool read_severity (db::NetlistCrossReference::Severity &severity); + void read_logs (db::NetlistCrossReference *xref); void read_xref (db::NetlistCrossReference *xref); void read_xrefs_for_circuits (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b); void read_net_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b); diff --git a/src/db/db/dbLayoutVsSchematicWriter.cc b/src/db/db/dbLayoutVsSchematicWriter.cc index 9b1085102..9060c5a99 100644 --- a/src/db/db/dbLayoutVsSchematicWriter.cc +++ b/src/db/db/dbLayoutVsSchematicWriter.cc @@ -72,8 +72,6 @@ private: } std::string status_to_s (const db::NetlistCrossReference::Status status); - std::string severity_to_s (const db::NetlistCrossReference::Severity severity); - std::string message_to_s (const std::string &msg); void write (TokenizedOutput &stream, const db::NetlistCrossReference *xref); std::map > m_net2id_per_circuit_a, m_net2id_per_circuit_b; @@ -178,16 +176,6 @@ static std::string pin_id_to_s (const db::Pin *pin, const std::map -std::string std_writer_impl::message_to_s (const std::string &msg) -{ - if (msg.empty ()) { - return std::string (); - } else { - return Keys::description_key + "(" + tl::to_word_or_quoted_string (msg) + ")"; - } -} - template std::string std_writer_impl::status_to_s (const db::NetlistCrossReference::Status status) { @@ -206,30 +194,28 @@ std::string std_writer_impl::status_to_s (const db::NetlistCrossReference: } } -template -std::string std_writer_impl::severity_to_s (const db::NetlistCrossReference::Severity severity) -{ - if (severity == db::NetlistCrossReference::Info) { - return Keys::info_severity_key; - } else if (severity == db::NetlistCrossReference::Warning) { - return Keys::warning_severity_key; - } else if (severity == db::NetlistCrossReference::Error) { - return Keys::error_severity_key; - } else { - return std::string (); - } -} - template void std_writer_impl::write (TokenizedOutput &stream, const db::NetlistCrossReference *xref) { - for (db::NetlistCrossReference::circuits_iterator c = xref->begin_circuits (); c != xref->end_circuits (); ++c) { + if (! xref->other_log_entries ().empty ()) { + + TokenizedOutput o (stream, Keys::log_key); + o << endl; + + for (auto l = xref->other_log_entries ().begin (); l != xref->other_log_entries ().end (); ++l) { + TokenizedOutput (o, Keys::log_entry_key, true) << this->severity_to_s (l->severity) << this->message_to_s (l->msg); + o << endl; + } + + } + + for (auto c = xref->begin_circuits (); c != xref->end_circuits (); ++c) { const db::NetlistCrossReference::PerCircuitData *pcd = xref->per_circuit_data_for (*c); tl_assert (pcd != 0); TokenizedOutput out (stream, Keys::circuit_key); - out << name_to_s (c->first) << name_to_s (c->second) << status_to_s (pcd->status) << message_to_s (pcd->msg); + out << name_to_s (c->first) << name_to_s (c->second) << status_to_s (pcd->status) << this->message_to_s (pcd->msg); out << endl; if (! pcd->log_entries.empty ()) { @@ -237,8 +223,8 @@ void std_writer_impl::write (TokenizedOutput &stream, const db::NetlistCro TokenizedOutput o (out, Keys::log_key); o << endl; - for (db::NetlistCrossReference::PerCircuitData::log_entries_const_iterator l = pcd->log_entries.begin (); l != pcd->log_entries.end (); ++l) { - TokenizedOutput (o, Keys::log_entry_key, true) << severity_to_s (l->severity) << message_to_s (l->msg); + for (auto l = pcd->log_entries.begin (); l != pcd->log_entries.end (); ++l) { + TokenizedOutput (o, Keys::log_entry_key, true) << this->severity_to_s (l->severity) << this->message_to_s (l->msg); o << endl; } @@ -249,7 +235,7 @@ void std_writer_impl::write (TokenizedOutput &stream, const db::NetlistCro o << endl; for (db::NetlistCrossReference::PerCircuitData::net_pairs_const_iterator n = pcd->nets.begin (); n != pcd->nets.end (); ++n) { - TokenizedOutput (o, Keys::net_key) << net_id_to_s (n->pair.first, m_net2id_per_circuit_a [c->first]) << net_id_to_s (n->pair.second, m_net2id_per_circuit_b [c->second]) << status_to_s (n->status) << message_to_s (n->msg); + TokenizedOutput (o, Keys::net_key) << net_id_to_s (n->pair.first, m_net2id_per_circuit_a [c->first]) << net_id_to_s (n->pair.second, m_net2id_per_circuit_b [c->second]) << status_to_s (n->status) << this->message_to_s (n->msg); } std::map pin2index_a, pin2index_b; @@ -257,15 +243,15 @@ void std_writer_impl::write (TokenizedOutput &stream, const db::NetlistCro build_pin_index_map (c->second, pin2index_b); for (db::NetlistCrossReference::PerCircuitData::pin_pairs_const_iterator n = pcd->pins.begin (); n != pcd->pins.end (); ++n) { - TokenizedOutput (o, Keys::pin_key) << pin_id_to_s (n->pair.first, pin2index_a) << pin_id_to_s (n->pair.second, pin2index_b) << status_to_s (n->status) << message_to_s (n->msg); + TokenizedOutput (o, Keys::pin_key) << pin_id_to_s (n->pair.first, pin2index_a) << pin_id_to_s (n->pair.second, pin2index_b) << status_to_s (n->status) << this->message_to_s (n->msg); } for (db::NetlistCrossReference::PerCircuitData::device_pairs_const_iterator n = pcd->devices.begin (); n != pcd->devices.end (); ++n) { - TokenizedOutput (o, Keys::device_key) << ion_to_s (n->pair.first) << ion_to_s (n->pair.second) << status_to_s (n->status) << message_to_s (n->msg); + TokenizedOutput (o, Keys::device_key) << ion_to_s (n->pair.first) << ion_to_s (n->pair.second) << status_to_s (n->status) << this->message_to_s (n->msg); } for (db::NetlistCrossReference::PerCircuitData::subcircuit_pairs_const_iterator n = pcd->subcircuits.begin (); n != pcd->subcircuits.end (); ++n) { - TokenizedOutput (o, Keys::circuit_key) << ion_to_s (n->pair.first) << ion_to_s (n->pair.second) << status_to_s (n->status) << message_to_s (n->msg); + TokenizedOutput (o, Keys::circuit_key) << ion_to_s (n->pair.first) << ion_to_s (n->pair.second) << status_to_s (n->status) << this->message_to_s (n->msg); } } diff --git a/src/db/db/dbLog.cc b/src/db/db/dbLog.cc new file mode 100644 index 000000000..b777f6c94 --- /dev/null +++ b/src/db/db/dbLog.cc @@ -0,0 +1,31 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2023 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "dbCommon.h" +#include "dbLog.h" + +namespace db +{ + + // .. nothing yet .. + +} diff --git a/src/db/db/dbLog.h b/src/db/db/dbLog.h new file mode 100644 index 000000000..d9aea2650 --- /dev/null +++ b/src/db/db/dbLog.h @@ -0,0 +1,57 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2023 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef _HDR_dbLog +#define _HDR_dbLog + +#include "dbCommon.h" + +#include + +namespace db +{ + +/** + * @brief An enum describing the severity for a log entry + */ +enum Severity { + NoSeverity = 0, // unspecific + Info = 1, // information only + Warning = 2, // a warning + Error = 3 // an error +}; + +/** + * @brief A class representing one log entry + */ +struct LogEntryData +{ + LogEntryData (Severity s, const std::string &m) : severity (s), msg (m) { } + LogEntryData () : severity (NoSeverity) { } + + Severity severity; + std::string msg; +}; + +} + +#endif diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 0a1f2e60c..e628dcfb0 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -385,7 +385,7 @@ NetlistComparer::compare_impl (const db::Netlist *a, const db::Netlist *b) const std::string msg = generate_subcircuits_not_verified_warning (ca, verified_circuits_a, cb, verified_circuits_b); if (m_with_log) { - mp_logger->log_entry (db::NetlistCompareLogger::Error, msg); + mp_logger->log_entry (db::Error, msg); } mp_logger->circuit_skipped (ca, cb, msg); @@ -899,7 +899,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, if (mp_logger) { if (p->second && ! exact_match) { if (m_with_log) { - mp_logger->log_entry (db::NetlistCompareLogger::Error, + mp_logger->log_entry (db::Error, tl::sprintf (tl::to_string (tr ("Nets %s are paired explicitly, but are not identical topologically")), nets2string (p->first))); } mp_logger->net_mismatch (p->first.first, p->first.second); @@ -1145,12 +1145,12 @@ static void analyze_pin_mismatch (const db::Pin *pin1, const db::Circuit *c1, const db::Pin *pin2, const db::Circuit * /*c2*/, db::NetlistCompareLogger *logger) { if (! pin1) { - logger->log_entry (db::NetlistCompareLogger::Error, tl::sprintf (tl::to_string (tr ("No equivalent pin %s from reference netlist found in netlist.\nThis is an indication that a physical connection is not made to the subcircuit.")), pin2->expanded_name ())); + logger->log_entry (db::Error, tl::sprintf (tl::to_string (tr ("No equivalent pin %s from reference netlist found in netlist.\nThis is an indication that a physical connection is not made to the subcircuit.")), pin2->expanded_name ())); } if (! pin2) { - logger->log_entry (db::NetlistCompareLogger::Error, tl::sprintf (tl::to_string (tr ("No equivalent pin %s from netlist found in reference netlist.\nThis is an indication that additional physical connections are made to the subcircuit cell.")), pin1->expanded_name ())); + logger->log_entry (db::Error, tl::sprintf (tl::to_string (tr ("No equivalent pin %s from netlist found in reference netlist.\nThis is an indication that additional physical connections are made to the subcircuit cell.")), pin1->expanded_name ())); // attempt to identify pins which are creating invalid connections for (auto p = c1->begin_parents (); p != c1->end_parents (); ++p) { @@ -1159,7 +1159,7 @@ analyze_pin_mismatch (const db::Pin *pin1, const db::Circuit *c1, const db::Pin if (sc.circuit_ref () == c1) { const db::Net *net = sc.net_for_pin (pin1->id ()); if (net && (net->subcircuit_pin_count () > 1 || net->terminal_count () > 0 || net->pin_count () > 0)) { - logger->log_entry (db::NetlistCompareLogger::Info, tl::sprintf (tl::to_string (tr ("Potential invalid connection in circuit %s, subcircuit cell reference at %s")), p->name (), sc.trans ().to_string ())); + logger->log_entry (db::Info, tl::sprintf (tl::to_string (tr ("Potential invalid connection in circuit %s, subcircuit cell reference at %s")), p->name (), sc.trans ().to_string ())); } } } diff --git a/src/db/db/dbNetlistCompare.h b/src/db/db/dbNetlistCompare.h index e5e2cfa7d..9c775982f 100644 --- a/src/db/db/dbNetlistCompare.h +++ b/src/db/db/dbNetlistCompare.h @@ -25,6 +25,7 @@ #include "dbCommon.h" #include "dbNetlist.h" +#include "dbLog.h" #include #include @@ -50,16 +51,6 @@ public: NetlistCompareLogger () { } virtual ~NetlistCompareLogger () { } - /** - * @brief An enum describing the severity for the log_entry function - */ - enum Severity { - NoSeverity = 0, // unspecific - Info = 1, // information only - Warning = 2, // a warning - Error = 3 // an error - }; - /** * @brief Begin logging for netlist a and b */ @@ -101,7 +92,7 @@ public: /** * @brief Receives log entries for the current circuit pair */ - virtual void log_entry (Severity /*level*/, const std::string & /*msg*/) { } + virtual void log_entry (db::Severity /*level*/, const std::string & /*msg*/) { } /** * @brief Nets a and b match exactly diff --git a/src/db/db/dbNetlistCompareCore.cc b/src/db/db/dbNetlistCompareCore.cc index 3d9e1907f..e4e61deea 100644 --- a/src/db/db/dbNetlistCompareCore.cc +++ b/src/db/db/dbNetlistCompareCore.cc @@ -1052,7 +1052,7 @@ NetlistCompareCore::derive_node_identities_from_ambiguity_group (const NodeRange if (ambiguous) { if (logger) { if (with_log) { - logger->log_entry (db::NetlistCompareLogger::Warning, + logger->log_entry (db::Warning, tl::sprintf (tl::to_string (tr ("Matching nets %s from an ambiguous group of nets")), nets2string (p->first->net (), p->second->net ()))); } logger->match_ambiguous_nets (p->first->net (), p->second->net ()); @@ -1116,7 +1116,7 @@ NetlistCompareCore::derive_node_identities_from_ambiguity_group (const NodeRange } if (logger && with_log && was_ambiguous) { - logger->log_entry (db::NetlistCompareLogger::Info, + logger->log_entry (db::Info, tl::sprintf (tl::to_string (tr ("Matching nets %s following an ambiguous match")), nets2string (n->net (), n_other->net ()))); } @@ -1397,7 +1397,7 @@ analyze_nodes_for_close_matches (const std::multimaplog_entry (db::NetlistCompareLogger::Info, tl::sprintf (msg, + logger->log_entry (db::Info, tl::sprintf (msg, i->second->net ()->expanded_name (), j->second->net ()->expanded_name (), int (fuzz))); @@ -1417,7 +1417,7 @@ analyze_nodes_for_close_matches (const std::multimapsecond, *j->second, *k->second, g2); double fuzz_factor = double (fuzz) / i->first; if (fuzz_factor < max_fuzz_factor) { - logger->log_entry (db::NetlistCompareLogger::Info, tl::sprintf (msg, + logger->log_entry (db::Info, tl::sprintf (msg, (layout2ref ? i : j)->second->net ()->expanded_name (), (layout2ref ? j : k)->second->net ()->expanded_name (), (layout2ref ? k : i)->second->net ()->expanded_name (), @@ -1493,7 +1493,7 @@ NetlistCompareCore::analyze_failed_matches () const } for (auto i = singular1.begin (); i != singular1.end (); ++i) { - logger->log_entry (db::NetlistCompareLogger::Error, tl::sprintf (tl::to_string (tr ("Net %s is not matching any net from reference netlist")), (*i)->net ()->expanded_name ())); + logger->log_entry (db::Error, tl::sprintf (tl::to_string (tr ("Net %s is not matching any net from reference netlist")), (*i)->net ()->expanded_name ())); } // attempt some analysis for close matches (including shorts / opens) @@ -1552,7 +1552,7 @@ NetlistCompareCore::derive_node_identities_from_node_set (std::vector::max() && depth > max_depth) { if (with_log) { - logger->log_entry (db::NetlistCompareLogger::Warning, tl::sprintf (tl::to_string (tr ("Maximum depth exhausted (max depth is %d)")), int (max_depth))); + logger->log_entry (db::Warning, tl::sprintf (tl::to_string (tr ("Maximum depth exhausted (max depth is %d)")), int (max_depth))); } if (db::NetlistCompareGlobalOptions::options ()->debug_netcompare) { tl::info << indent_s << "max. depth exhausted (" << depth << ">" << max_depth << ")"; @@ -1670,7 +1670,7 @@ NetlistCompareCore::derive_node_identities_from_node_set (std::vector::max () && double (std::max (nr->num1, nr->num2)) * double (n_branch) > double (max_n_branch)) { if (with_log) { - logger->log_entry (db::NetlistCompareLogger::Warning, tl::sprintf (tl::to_string (tr ("Maximum complexity exhausted (max complexity is %s, needs at least %s)")), tl::to_string (max_n_branch), tl::to_string (std::max (nr->num1, nr->num2) * n_branch))); + logger->log_entry (db::Warning, tl::sprintf (tl::to_string (tr ("Maximum complexity exhausted (max complexity is %s, needs at least %s)")), tl::to_string (max_n_branch), tl::to_string (std::max (nr->num1, nr->num2) * n_branch))); } if (db::NetlistCompareGlobalOptions::options ()->debug_netcompare) { tl::info << indent_s << "max. complexity exhausted (" << std::max (nr->num1, nr->num2) << "*" << n_branch << ">" << max_n_branch << ") - mismatch."; diff --git a/src/db/db/dbNetlistCrossReference.h b/src/db/db/dbNetlistCrossReference.h index 71d32f7ca..aec52a8ed 100644 --- a/src/db/db/dbNetlistCrossReference.h +++ b/src/db/db/dbNetlistCrossReference.h @@ -105,15 +105,6 @@ public: std::string msg; }; - struct LogEntryData - { - LogEntryData (Severity s, const std::string &m) : severity (s), msg (m) { } - LogEntryData () : severity (NoSeverity) { } - - Severity severity; - std::string msg; - }; - struct PerCircuitData { PerCircuitData () : status (None) { } diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h index e1710c603..f80ca09ee 100644 --- a/src/db/db/dbNetlistDeviceExtractor.h +++ b/src/db/db/dbNetlistDeviceExtractor.h @@ -265,6 +265,14 @@ public: */ void extract (DeepShapeStore &dss, unsigned int layout_index, const input_layers &layers, Netlist &netlist, hier_clusters_type &clusters, double device_scaling = 1.0); + /** + * @brief Clears the errors + */ + void clear_errors () + { + m_errors.clear (); + } + /** * @brief Gets the error iterator, begin */ diff --git a/src/db/db/gsiDeclDbNetlistCompare.cc b/src/db/db/gsiDeclDbNetlistCompare.cc index c8f1fe6a4..ed61e975a 100644 --- a/src/db/db/gsiDeclDbNetlistCompare.cc +++ b/src/db/db/gsiDeclDbNetlistCompare.cc @@ -137,16 +137,16 @@ public: db::NetlistCompareLogger::circuit_mismatch (a, b, msg); } - virtual void log_entry (db::NetlistCompareLogger::Severity severity, const std::string &msg) + virtual void log_entry (db::Severity severity, const std::string &msg) { if (cb_log_entry.can_issue ()) { - cb_log_entry.issue (&GenericNetlistCompareLogger::log_entry, severity, msg); + cb_log_entry.issue (&GenericNetlistCompareLogger::log_entry, severity, msg); } else { db::NetlistCompareLogger::log_entry (severity, msg); } } - void log_entry_fb (db::NetlistCompareLogger::Severity severity, const std::string &msg) + void log_entry_fb (db::Severity severity, const std::string &msg) { db::NetlistCompareLogger::log_entry (severity, msg); } @@ -657,17 +657,17 @@ Class decl_dbNetlistComparer ("db", "NetlistComparer", "This class has been introduced in version 0.26." ); -gsi::EnumIn decl_CompareLoggerSeverity ("db", "Severity", - gsi::enum_const ("NoSeverity", db::NetlistCompareLogger::NoSeverity, +gsi::EnumIn decl_CompareLoggerSeverity ("db", "Severity", + gsi::enum_const ("NoSeverity", db::NoSeverity, "@brief Unspecific severity\n" ) + - gsi::enum_const ("Info", db::NetlistCompareLogger::Info, + gsi::enum_const ("Info", db::Info, "@brief Information only\n" ) + - gsi::enum_const ("Warning", db::NetlistCompareLogger::Warning, + gsi::enum_const ("Warning", db::Warning, "@brief A warning\n" ) + - gsi::enum_const ("Error", db::NetlistCompareLogger::Error, + gsi::enum_const ("Error", db::Error, "@brief An error\n" ), "@brief This class represents the log severity level for \\GenericNetlistCompareLogger#log_entry.\n" diff --git a/src/layui/layui/layNetlistBrowserPage.cc b/src/layui/layui/layNetlistBrowserPage.cc index faf4d4000..a967d9b73 100644 --- a/src/layui/layui/layNetlistBrowserPage.cc +++ b/src/layui/layui/layNetlistBrowserPage.cc @@ -1132,9 +1132,9 @@ NetlistBrowserPage::setup_trees () db::LayoutToNetlist *l2ndb = mp_database.get (); db::LayoutVsSchematic *lvsdb = dynamic_cast (l2ndb); - if (lvsdb && lvsdb->cross_ref ()) { + if ((lvsdb && lvsdb->cross_ref ()) || (l2ndb && ! l2ndb->log_entries ().empty ())) { - NetlistLogModel *new_model = new NetlistLogModel (log_view, lvsdb->cross_ref ()); + NetlistLogModel *new_model = new NetlistLogModel (log_view, lvsdb->cross_ref () /*@@@, l2ndb*/); delete log_view->model (); log_view->setModel (new_model); diff --git a/src/layui/layui/layNetlistLogModel.cc b/src/layui/layui/layNetlistLogModel.cc index aed4ac6f4..021c24b9a 100644 --- a/src/layui/layui/layNetlistLogModel.cc +++ b/src/layui/layui/layNetlistLogModel.cc @@ -137,6 +137,7 @@ NetlistLogModel::rowCount (const QModelIndex &parent) const } else if (parent.parent ().isValid ()) { return 0; } else if (parent.row () >= 0 && parent.row () < int (m_circuits.size ())) { + // @@@ that would crash for "other entries"! return int (m_circuits [parent.row ()].second->size ()); } else { return 0; @@ -152,7 +153,7 @@ NetlistLogModel::columnCount (const QModelIndex & /*parent*/) const QVariant NetlistLogModel::data (const QModelIndex &index, int role) const { - const db::NetlistCrossReference::LogEntryData *le = 0; + const db::LogEntryData *le = 0; if (index.parent ().isValid ()) { const circuit_entry *ce = (const circuit_entry *) index.internalPointer (); if (ce) { @@ -164,11 +165,11 @@ NetlistLogModel::data (const QModelIndex &index, int role) const if (! le) { // ignore - } else if (le->severity == db::NetlistCrossReference::Error) { + } else if (le->severity == db::Error) { return QIcon (QString::fromUtf8 (":/error_16px.png")); - } else if (le->severity == db::NetlistCrossReference::Warning) { + } else if (le->severity == db::Warning) { return QIcon (QString::fromUtf8 (":/warn_16px.png")); - } else if (le->severity == db::NetlistCrossReference::Info) { + } else if (le->severity == db::Info) { return QIcon (QString::fromUtf8 (":/info_16px.png")); } @@ -192,7 +193,7 @@ NetlistLogModel::data (const QModelIndex &index, int role) const } else if (role == Qt::FontRole) { if (index.parent ().isValid ()) { - if (le && le->severity == db::NetlistCrossReference::Error) { + if (le && le->severity == db::Error) { QFont f; f.setBold (true); return QVariant (f); @@ -208,9 +209,9 @@ NetlistLogModel::data (const QModelIndex &index, int role) const if (index.parent ().isValid ()) { if (!le) { // ignore - } else if (le->severity == db::NetlistCrossReference::Error) { + } else if (le->severity == db::Error) { return QColor (255, 0, 0); - } else if (le->severity == db::NetlistCrossReference::Warning) { + } else if (le->severity == db::Warning) { return QColor (0, 0, 255); } }