From c897c0474bcac1c8f96395ac30a973fbec3813f2 Mon Sep 17 00:00:00 2001 From: Mathias Schmid <50880400+matzeschmid@users.noreply.github.com> Date: Mon, 4 Jul 2022 22:23:20 +0200 Subject: [PATCH] Library Data: Add support for optional smart pointer element 'unique' (#4132) --- gui/cppchecklibrarydata.cpp | 78 +++++++++++++++++-- gui/cppchecklibrarydata.h | 21 ++++- .../files/container_valid.cfg | 9 +++ .../files/smartptr_valid.cfg | 4 +- gui/test/cppchecklibrarydata/resources.qrc | 1 + .../testcppchecklibrarydata.cpp | 54 ++++++++++++- .../testcppchecklibrarydata.h | 1 + 7 files changed, 155 insertions(+), 13 deletions(-) create mode 100644 gui/test/cppchecklibrarydata/files/container_valid.cfg diff --git a/gui/cppchecklibrarydata.cpp b/gui/cppchecklibrarydata.cpp index a8f2aaf9a..7c6bf8636 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,12 @@ 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(); + container.rangeItemRecordTypeList.append(rangeItemRecordType); + } else container.otherFunctions.append(function); } } else { @@ -105,9 +110,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) @@ -210,6 +229,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); } @@ -493,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"); @@ -519,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(); } @@ -632,7 +680,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(); } @@ -835,9 +896,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 ff688d9c2..19e9bf4bb 100644 --- a/gui/cppchecklibrarydata.h +++ b/gui/cppchecklibrarydata.h @@ -22,6 +22,7 @@ #include #include #include +#include class QIODevice; @@ -47,6 +48,11 @@ public: QString string; } type; + struct RangeItemRecordType { + QString name; + QString templateParameter; + }; + struct Function { QString name; QString yields; @@ -55,6 +61,7 @@ public: QList accessFunctions; QList otherFunctions; QList sizeFunctions; + QList rangeItemRecordTypeList; }; struct Define { @@ -130,6 +137,9 @@ public: msg.isEmpty(); } } warn; + + QMap notOverlappingDataArgs; + QMap containerAttributes; }; struct MemoryResource { @@ -219,6 +229,15 @@ public: QList exporter; }; + struct SmartPointer { + SmartPointer() : + unique {false} + {} + + QString name; + bool unique; + }; + void clear() { containers.clear(); defines.clear(); @@ -258,7 +277,7 @@ public: QList typeChecks; QList platformTypes; QStringList undefines; - QStringList smartPointers; + QList smartPointers; QList reflections; QList markups; }; diff --git a/gui/test/cppchecklibrarydata/files/container_valid.cfg b/gui/test/cppchecklibrarydata/files/container_valid.cfg new file mode 100644 index 000000000..494821c9f --- /dev/null +++ b/gui/test/cppchecklibrarydata/files/container_valid.cfg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/gui/test/cppchecklibrarydata/files/smartptr_valid.cfg b/gui/test/cppchecklibrarydata/files/smartptr_valid.cfg index 1ae007ac6..e0b9245cb 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/resources.qrc b/gui/test/cppchecklibrarydata/resources.qrc index c6394211e..57625f3b2 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 973260870..df8d0c471 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() @@ -543,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, 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); + + 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 64cd1d28c..12a9efd5a 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);