From 5df58f2031735f596179320c932152d07905984f Mon Sep 17 00:00:00 2001 From: matzeschmid Date: Tue, 24 May 2022 16:17:58 +0200 Subject: [PATCH 1/5] Add support for optional smart pointer element 'unique' to avoid library data load failure. --- gui/cppchecklibrarydata.cpp | 25 ++++++++++++++++--- gui/cppchecklibrarydata.h | 11 +++++++- .../files/smartptr_valid.cfg | 4 ++- .../testcppchecklibrarydata.cpp | 14 ++++++++--- 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/gui/cppchecklibrarydata.cpp b/gui/cppchecklibrarydata.cpp index a8f2aaf9a04..4304004194e 100644 --- a/gui/cppchecklibrarydata.cpp +++ b/gui/cppchecklibrarydata.cpp @@ -105,9 +105,23 @@ static QString loadUndefine(const QXmlStreamReader &xmlReader) return xmlReader.attributes().value("name").toString(); } -static QString loadSmartPointer(const QXmlStreamReader &xmlReader) +static CppcheckLibraryData::SmartPointer loadSmartPointer(QXmlStreamReader &xmlReader) { - return xmlReader.attributes().value("class-name").toString(); + CppcheckLibraryData::SmartPointer smartPointer; + smartPointer.name = xmlReader.attributes().value("class-name").toString(); + QXmlStreamReader::TokenType type; + while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement || + xmlReader.name().toString() != "smart-pointer") { + if (type != QXmlStreamReader::StartElement) + continue; + const QString elementName = xmlReader.name().toString(); + if (elementName == "unique") { + smartPointer.unique = true; + } else { + unhandledElement(xmlReader); + } + } + return smartPointer; } static CppcheckLibraryData::TypeChecks loadTypeChecks(QXmlStreamReader &xmlReader) @@ -835,9 +849,12 @@ QString CppcheckLibraryData::toString() const writeTypeChecks(xmlWriter, check); } - for (const QString &smartPtr : smartPointers) { + for (const SmartPointer &smartPtr : smartPointers) { xmlWriter.writeStartElement("smart-pointer"); - xmlWriter.writeAttribute("class-name", smartPtr); + xmlWriter.writeAttribute("class-name", smartPtr.name); + if (smartPtr.unique) { + xmlWriter.writeEmptyElement("unique"); + } xmlWriter.writeEndElement(); } diff --git a/gui/cppchecklibrarydata.h b/gui/cppchecklibrarydata.h index ff688d9c22a..e4d895ecf81 100644 --- a/gui/cppchecklibrarydata.h +++ b/gui/cppchecklibrarydata.h @@ -219,6 +219,15 @@ class CppcheckLibraryData { QList exporter; }; + struct SmartPointer { + SmartPointer() : + unique {false} + {} + + QString name; + bool unique; + }; + void clear() { containers.clear(); defines.clear(); @@ -258,7 +267,7 @@ class CppcheckLibraryData { QList typeChecks; QList platformTypes; QStringList undefines; - QStringList smartPointers; + QList smartPointers; QList reflections; QList markups; }; diff --git a/gui/test/cppchecklibrarydata/files/smartptr_valid.cfg b/gui/test/cppchecklibrarydata/files/smartptr_valid.cfg index 1ae007ac6ec..e0b9245cb03 100644 --- a/gui/test/cppchecklibrarydata/files/smartptr_valid.cfg +++ b/gui/test/cppchecklibrarydata/files/smartptr_valid.cfg @@ -1,6 +1,8 @@ - + + + \ No newline at end of file diff --git a/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp b/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp index 9732608705c..fd825291323 100644 --- a/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp +++ b/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp @@ -182,9 +182,12 @@ void TestCppcheckLibraryData::smartPointerValid() // Do size and content checks against swapped data. QCOMPARE(libraryData.smartPointers.size(), 3); - QCOMPARE(libraryData.smartPointers[0], QString("wxObjectDataPtr")); - QCOMPARE(libraryData.smartPointers[1], QString("wxScopedArray")); - QCOMPARE(libraryData.smartPointers[2], QString("wxScopedPtr")); + QCOMPARE(libraryData.smartPointers[0].name, QString("wxObjectDataPtr")); + QCOMPARE(libraryData.smartPointers[0].unique, false); + QCOMPARE(libraryData.smartPointers[1].name, QString("wxScopedArray")); + QCOMPARE(libraryData.smartPointers[1].unique, true); + QCOMPARE(libraryData.smartPointers[2].name, QString("wxScopedPtr")); + QCOMPARE(libraryData.smartPointers[2].unique, false); // Save library data to file saveCfgFile(TempCfgFile, libraryData); @@ -199,7 +202,10 @@ void TestCppcheckLibraryData::smartPointerValid() // Verify no data got lost or modified QCOMPARE(libraryData.smartPointers.size(), fileLibraryData.smartPointers.size()); QCOMPARE(libraryData.smartPointers.size(), 3); - QCOMPARE(libraryData.smartPointers, fileLibraryData.smartPointers); + for (int idx=0; idx < libraryData.smartPointers.size(); idx++) { + QCOMPARE(libraryData.smartPointers[idx].name, fileLibraryData.smartPointers[idx].name); + QCOMPARE(libraryData.smartPointers[idx].unique, fileLibraryData.smartPointers[idx].unique); + } } void TestCppcheckLibraryData::platformTypeValid() From db434a5ab7912e321a43cf8fcbf16ea51d0e53fa Mon Sep 17 00:00:00 2001 From: matzeschmid Date: Mon, 4 Jul 2022 15:37:45 +0200 Subject: [PATCH 2/5] Add support for "function" sub-elements "container" and "not-overlapping-data". Add support for "container" sub-element "rangeItemRecordType". --- gui/cppchecklibrarydata.cpp | 37 ++++++++++++++++++++++++++++++++++--- gui/cppchecklibrarydata.h | 10 ++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/gui/cppchecklibrarydata.cpp b/gui/cppchecklibrarydata.cpp index 4304004194e..aaa0e481bbe 100644 --- a/gui/cppchecklibrarydata.cpp +++ b/gui/cppchecklibrarydata.cpp @@ -61,7 +61,7 @@ static CppcheckLibraryData::Container loadContainer(QXmlStreamReader &xmlReader) if (elementName == "type") { container.type.templateParameter = xmlReader.attributes().value("templateParameter").toString(); container.type.string = xmlReader.attributes().value("string").toString(); - } else if (elementName == "size" || elementName == "access" || elementName == "other") { + } else if (elementName == "size" || elementName == "access" || elementName == "other" || elementName == "rangeItemRecordType") { const QString indexOperator = xmlReader.attributes().value("indexOperator").toString(); if (elementName == "access" && indexOperator == "array-like") container.access_arrayLike = true; @@ -82,7 +82,11 @@ static CppcheckLibraryData::Container loadContainer(QXmlStreamReader &xmlReader) container.sizeFunctions.append(function); else if (elementName == "access") container.accessFunctions.append(function); - else + else if (elementName == "rangeItemRecordType") { + struct CppcheckLibraryData::Container::RangeItemRecordType rangeItemRecordType; + rangeItemRecordType.name = xmlReader.attributes().value("name").toString(); + rangeItemRecordType.templateParameter = xmlReader.attributes().value("templateParameter").toString(); + } else container.otherFunctions.append(function); } } else { @@ -224,6 +228,20 @@ static CppcheckLibraryData::Function loadFunction(QXmlStreamReader &xmlReader, c function.warn.reason = xmlReader.attributes().value("reason").toString(); function.warn.alternatives = xmlReader.attributes().value("alternatives").toString(); function.warn.msg = xmlReader.readElementText(); + } else if (elementName == "not-overlapping-data") { + const QStringList attributeList {"ptr1-arg", "ptr2-arg", "size-arg", "strlen-arg"}; + for (const QString &attr : attributeList) { + if (xmlReader.attributes().hasAttribute(attr)) { + function.notOverlappingDataArgs[attr] = xmlReader.attributes().value(attr).toString(); + } + } + } else if (elementName == "container") { + const QStringList attributeList {"action", "yields"}; + for (const QString &attr : attributeList) { + if (xmlReader.attributes().hasAttribute(attr)) { + function.containerAttributes[attr] = xmlReader.attributes().value(attr).toString(); + } + } } else { unhandledElement(xmlReader); } @@ -646,7 +664,20 @@ static void writeFunction(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData xmlWriter.writeEndElement(); } - + if (!function.notOverlappingDataArgs.isEmpty()) { + xmlWriter.writeStartElement("not-overlapping-data"); + foreach (const QString value, function.notOverlappingDataArgs) { + xmlWriter.writeAttribute(function.notOverlappingDataArgs.key(value), value); + } + xmlWriter.writeEndElement(); + } + if (!function.containerAttributes.isEmpty()) { + xmlWriter.writeStartElement("container"); + foreach (const QString value, function.containerAttributes) { + xmlWriter.writeAttribute(function.containerAttributes.key(value), value); + } + xmlWriter.writeEndElement(); + } xmlWriter.writeEndElement(); } diff --git a/gui/cppchecklibrarydata.h b/gui/cppchecklibrarydata.h index e4d895ecf81..19e9bf4bb8a 100644 --- a/gui/cppchecklibrarydata.h +++ b/gui/cppchecklibrarydata.h @@ -22,6 +22,7 @@ #include #include #include +#include class QIODevice; @@ -47,6 +48,11 @@ class CppcheckLibraryData { QString string; } type; + struct RangeItemRecordType { + QString name; + QString templateParameter; + }; + struct Function { QString name; QString yields; @@ -55,6 +61,7 @@ class CppcheckLibraryData { QList accessFunctions; QList otherFunctions; QList sizeFunctions; + QList rangeItemRecordTypeList; }; struct Define { @@ -130,6 +137,9 @@ class CppcheckLibraryData { msg.isEmpty(); } } warn; + + QMap notOverlappingDataArgs; + QMap containerAttributes; }; struct MemoryResource { From 98066cecb3f1701c344cc7e6b9f03987215dd175 Mon Sep 17 00:00:00 2001 From: matzeschmid Date: Mon, 4 Jul 2022 16:45:03 +0200 Subject: [PATCH 3/5] Add missing write function for "rangeItemRecordType" elements. Add missing append for read "rangeItemRecordType" elements. --- gui/cppchecklibrarydata.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/gui/cppchecklibrarydata.cpp b/gui/cppchecklibrarydata.cpp index aaa0e481bbe..7c6bf86363f 100644 --- a/gui/cppchecklibrarydata.cpp +++ b/gui/cppchecklibrarydata.cpp @@ -86,6 +86,7 @@ static CppcheckLibraryData::Container loadContainer(QXmlStreamReader &xmlReader) struct CppcheckLibraryData::Container::RangeItemRecordType rangeItemRecordType; rangeItemRecordType.name = xmlReader.attributes().value("name").toString(); rangeItemRecordType.templateParameter = xmlReader.attributes().value("templateParameter").toString(); + container.rangeItemRecordTypeList.append(rangeItemRecordType); } else container.otherFunctions.append(function); } @@ -525,6 +526,20 @@ static void writeContainerFunctions(QXmlStreamWriter &xmlWriter, const QString & xmlWriter.writeEndElement(); } +static void writeContainerRangeItemRecords(QXmlStreamWriter &xmlWriter, const QList &rangeItemRecords) +{ + if (rangeItemRecords.isEmpty()) + return; + xmlWriter.writeStartElement("rangeItemRecordType"); + for (const CppcheckLibraryData::Container::RangeItemRecordType &item : rangeItemRecords) { + xmlWriter.writeStartElement("member"); + xmlWriter.writeAttribute("name", item.name); + xmlWriter.writeAttribute("templateParameter", item.templateParameter); + xmlWriter.writeEndElement(); + } + xmlWriter.writeEndElement(); +} + static void writeContainer(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Container &container) { xmlWriter.writeStartElement("container"); @@ -551,6 +566,7 @@ static void writeContainer(QXmlStreamWriter &xmlWriter, const CppcheckLibraryDat writeContainerFunctions(xmlWriter, "size", container.size_templateParameter, container.sizeFunctions); writeContainerFunctions(xmlWriter, "access", container.access_arrayLike?1:-1, container.accessFunctions); writeContainerFunctions(xmlWriter, "other", -1, container.otherFunctions); + writeContainerRangeItemRecords(xmlWriter, container.rangeItemRecordTypeList); xmlWriter.writeEndElement(); } From 4de94cadbabb3e10ba359ef2433b221ebd83600b Mon Sep 17 00:00:00 2001 From: matzeschmid Date: Mon, 4 Jul 2022 17:35:58 +0200 Subject: [PATCH 4/5] Add initial container element test. --- .../files/container_valid.cfg | 9 +++++ gui/test/cppchecklibrarydata/resources.qrc | 1 + .../testcppchecklibrarydata.cpp | 40 +++++++++++++++++++ .../testcppchecklibrarydata.h | 1 + 4 files changed, 51 insertions(+) create mode 100644 gui/test/cppchecklibrarydata/files/container_valid.cfg diff --git a/gui/test/cppchecklibrarydata/files/container_valid.cfg b/gui/test/cppchecklibrarydata/files/container_valid.cfg new file mode 100644 index 00000000000..494821c9f77 --- /dev/null +++ b/gui/test/cppchecklibrarydata/files/container_valid.cfg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/gui/test/cppchecklibrarydata/resources.qrc b/gui/test/cppchecklibrarydata/resources.qrc index c6394211ec3..57625f3b22b 100644 --- a/gui/test/cppchecklibrarydata/resources.qrc +++ b/gui/test/cppchecklibrarydata/resources.qrc @@ -19,5 +19,6 @@ files/markup_mandatory_attribute_missing.cfg files/markup_valid.cfg files/markup_unhandled_element.cfg + files/container_valid.cfg diff --git a/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp b/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp index fd825291323..261913a713b 100644 --- a/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp +++ b/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp @@ -549,6 +549,46 @@ void TestCppcheckLibraryData::markupValid() } } +void TestCppcheckLibraryData::containerValid() +{ + // Load library data from file + loadCfgFile(":/files/container_valid.cfg", fileLibraryData, result); + QCOMPARE(result.isNull(), true); + + // Swap library data read from file to other object + libraryData.swap(fileLibraryData); + + // Do size and content checks against swapped data. + QCOMPARE(libraryData.containers.size(), 1); + + QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList.size(), 2); + QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[0].name, "first"); + QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[0].templateParameter, "0"); + QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[1].name, "second"); + QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[1].templateParameter, "1"); + + // Save library data to file + saveCfgFile(TempCfgFile, libraryData); + + fileLibraryData.clear(); + QCOMPARE(fileLibraryData.containers.size(), 0); + + // Reload library data from file + loadCfgFile(TempCfgFile, fileLibraryData, result, true); + QCOMPARE(result.isNull(), true); + + // Verify no data got lost or modified + QCOMPARE(libraryData.containers.size(), fileLibraryData.containers.size()); + for (int idx=0; idx < libraryData.containers.size(); idx++) { + CppcheckLibraryData::Container lhs = libraryData.containers[idx]; + CppcheckLibraryData::Container rhs = fileLibraryData.containers[idx]; + for (int num=0; num < lhs.rangeItemRecordTypeList.size(); num++) { + QCOMPARE(lhs.rangeItemRecordTypeList[num].name, rhs.rangeItemRecordTypeList[num].name); + QCOMPARE(lhs.rangeItemRecordTypeList[num].templateParameter, rhs.rangeItemRecordTypeList[num].templateParameter); + } + } +} + void TestCppcheckLibraryData::loadCfgFile(QString filename, CppcheckLibraryData &data, QString &res, bool removeFile) { QFile file(filename); diff --git a/gui/test/cppchecklibrarydata/testcppchecklibrarydata.h b/gui/test/cppchecklibrarydata/testcppchecklibrarydata.h index 64cd1d28c4d..12a9efd5a0b 100644 --- a/gui/test/cppchecklibrarydata/testcppchecklibrarydata.h +++ b/gui/test/cppchecklibrarydata/testcppchecklibrarydata.h @@ -39,6 +39,7 @@ private slots: void undefineValid(); void reflectionValid(); void markupValid(); + void containerValid(); private: void loadCfgFile(QString filename, CppcheckLibraryData &data, QString &res, bool removeFile = false); From 6ca32ff4e44d4b1fb2bb021347628ec452d7e284 Mon Sep 17 00:00:00 2001 From: matzeschmid Date: Mon, 4 Jul 2022 17:59:45 +0200 Subject: [PATCH 5/5] Fix build check error in container test. --- gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp b/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp index 261913a713b..df8d0c471bc 100644 --- a/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp +++ b/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp @@ -562,10 +562,10 @@ void TestCppcheckLibraryData::containerValid() QCOMPARE(libraryData.containers.size(), 1); QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList.size(), 2); - QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[0].name, "first"); - QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[0].templateParameter, "0"); - QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[1].name, "second"); - QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[1].templateParameter, "1"); + QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[0].name, QString("first")); + QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[0].templateParameter, QString("0")); + QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[1].name, QString("second")); + QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[1].templateParameter, QString("1")); // Save library data to file saveCfgFile(TempCfgFile, libraryData);