Library Data: Add support for optional smart pointer element 'unique' (#4132)

This commit is contained in:
Mathias Schmid 2022-07-04 22:23:20 +02:00 committed by GitHub
parent 22aeeb1788
commit c897c0474b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 155 additions and 13 deletions

View File

@ -61,7 +61,7 @@ static CppcheckLibraryData::Container loadContainer(QXmlStreamReader &xmlReader)
if (elementName == "type") { if (elementName == "type") {
container.type.templateParameter = xmlReader.attributes().value("templateParameter").toString(); container.type.templateParameter = xmlReader.attributes().value("templateParameter").toString();
container.type.string = xmlReader.attributes().value("string").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(); const QString indexOperator = xmlReader.attributes().value("indexOperator").toString();
if (elementName == "access" && indexOperator == "array-like") if (elementName == "access" && indexOperator == "array-like")
container.access_arrayLike = true; container.access_arrayLike = true;
@ -82,7 +82,12 @@ static CppcheckLibraryData::Container loadContainer(QXmlStreamReader &xmlReader)
container.sizeFunctions.append(function); container.sizeFunctions.append(function);
else if (elementName == "access") else if (elementName == "access")
container.accessFunctions.append(function); 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); container.otherFunctions.append(function);
} }
} else { } else {
@ -105,9 +110,23 @@ static QString loadUndefine(const QXmlStreamReader &xmlReader)
return xmlReader.attributes().value("name").toString(); 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) 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.reason = xmlReader.attributes().value("reason").toString();
function.warn.alternatives = xmlReader.attributes().value("alternatives").toString(); function.warn.alternatives = xmlReader.attributes().value("alternatives").toString();
function.warn.msg = xmlReader.readElementText(); 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 { } else {
unhandledElement(xmlReader); unhandledElement(xmlReader);
} }
@ -493,6 +526,20 @@ static void writeContainerFunctions(QXmlStreamWriter &xmlWriter, const QString &
xmlWriter.writeEndElement(); xmlWriter.writeEndElement();
} }
static void writeContainerRangeItemRecords(QXmlStreamWriter &xmlWriter, const QList<struct CppcheckLibraryData::Container::RangeItemRecordType> &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) static void writeContainer(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Container &container)
{ {
xmlWriter.writeStartElement("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, "size", container.size_templateParameter, container.sizeFunctions);
writeContainerFunctions(xmlWriter, "access", container.access_arrayLike?1:-1, container.accessFunctions); writeContainerFunctions(xmlWriter, "access", container.access_arrayLike?1:-1, container.accessFunctions);
writeContainerFunctions(xmlWriter, "other", -1, container.otherFunctions); writeContainerFunctions(xmlWriter, "other", -1, container.otherFunctions);
writeContainerRangeItemRecords(xmlWriter, container.rangeItemRecordTypeList);
xmlWriter.writeEndElement(); xmlWriter.writeEndElement();
} }
@ -632,7 +680,20 @@ static void writeFunction(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData
xmlWriter.writeEndElement(); 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(); xmlWriter.writeEndElement();
} }
@ -835,9 +896,12 @@ QString CppcheckLibraryData::toString() const
writeTypeChecks(xmlWriter, check); writeTypeChecks(xmlWriter, check);
} }
for (const QString &smartPtr : smartPointers) { for (const SmartPointer &smartPtr : smartPointers) {
xmlWriter.writeStartElement("smart-pointer"); xmlWriter.writeStartElement("smart-pointer");
xmlWriter.writeAttribute("class-name", smartPtr); xmlWriter.writeAttribute("class-name", smartPtr.name);
if (smartPtr.unique) {
xmlWriter.writeEmptyElement("unique");
}
xmlWriter.writeEndElement(); xmlWriter.writeEndElement();
} }

View File

@ -22,6 +22,7 @@
#include <QList> #include <QList>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include <QMap>
class QIODevice; class QIODevice;
@ -47,6 +48,11 @@ public:
QString string; QString string;
} type; } type;
struct RangeItemRecordType {
QString name;
QString templateParameter;
};
struct Function { struct Function {
QString name; QString name;
QString yields; QString yields;
@ -55,6 +61,7 @@ public:
QList<struct Function> accessFunctions; QList<struct Function> accessFunctions;
QList<struct Function> otherFunctions; QList<struct Function> otherFunctions;
QList<struct Function> sizeFunctions; QList<struct Function> sizeFunctions;
QList<struct RangeItemRecordType> rangeItemRecordTypeList;
}; };
struct Define { struct Define {
@ -130,6 +137,9 @@ public:
msg.isEmpty(); msg.isEmpty();
} }
} warn; } warn;
QMap<QString, QString> notOverlappingDataArgs;
QMap<QString, QString> containerAttributes;
}; };
struct MemoryResource { struct MemoryResource {
@ -219,6 +229,15 @@ public:
QList<Exporter> exporter; QList<Exporter> exporter;
}; };
struct SmartPointer {
SmartPointer() :
unique {false}
{}
QString name;
bool unique;
};
void clear() { void clear() {
containers.clear(); containers.clear();
defines.clear(); defines.clear();
@ -258,7 +277,7 @@ public:
QList<TypeChecks> typeChecks; QList<TypeChecks> typeChecks;
QList<struct PlatformType> platformTypes; QList<struct PlatformType> platformTypes;
QStringList undefines; QStringList undefines;
QStringList smartPointers; QList<struct SmartPointer> smartPointers;
QList<struct Reflection> reflections; QList<struct Reflection> reflections;
QList<struct Markup> markups; QList<struct Markup> markups;
}; };

View File

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<def format="2">
<container id="stdMultiMap">
<rangeItemRecordType>
<member name="first" templateParameter="0"/>
<member name="second" templateParameter="1"/>
</rangeItemRecordType>
</container>
</def>

View File

@ -1,6 +1,8 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<def format="2"> <def format="2">
<smart-pointer class-name="wxObjectDataPtr"/> <smart-pointer class-name="wxObjectDataPtr"/>
<smart-pointer class-name="wxScopedArray"/> <smart-pointer class-name="wxScopedArray">
<unique/>
</smart-pointer>
<smart-pointer class-name="wxScopedPtr"/> <smart-pointer class-name="wxScopedPtr"/>
</def> </def>

View File

@ -19,5 +19,6 @@
<file>files/markup_mandatory_attribute_missing.cfg</file> <file>files/markup_mandatory_attribute_missing.cfg</file>
<file>files/markup_valid.cfg</file> <file>files/markup_valid.cfg</file>
<file>files/markup_unhandled_element.cfg</file> <file>files/markup_unhandled_element.cfg</file>
<file>files/container_valid.cfg</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -182,9 +182,12 @@ void TestCppcheckLibraryData::smartPointerValid()
// Do size and content checks against swapped data. // Do size and content checks against swapped data.
QCOMPARE(libraryData.smartPointers.size(), 3); QCOMPARE(libraryData.smartPointers.size(), 3);
QCOMPARE(libraryData.smartPointers[0], QString("wxObjectDataPtr")); QCOMPARE(libraryData.smartPointers[0].name, QString("wxObjectDataPtr"));
QCOMPARE(libraryData.smartPointers[1], QString("wxScopedArray")); QCOMPARE(libraryData.smartPointers[0].unique, false);
QCOMPARE(libraryData.smartPointers[2], QString("wxScopedPtr")); 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 // Save library data to file
saveCfgFile(TempCfgFile, libraryData); saveCfgFile(TempCfgFile, libraryData);
@ -199,7 +202,10 @@ void TestCppcheckLibraryData::smartPointerValid()
// Verify no data got lost or modified // Verify no data got lost or modified
QCOMPARE(libraryData.smartPointers.size(), fileLibraryData.smartPointers.size()); QCOMPARE(libraryData.smartPointers.size(), fileLibraryData.smartPointers.size());
QCOMPARE(libraryData.smartPointers.size(), 3); 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() 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) void TestCppcheckLibraryData::loadCfgFile(QString filename, CppcheckLibraryData &data, QString &res, bool removeFile)
{ {
QFile file(filename); QFile file(filename);

View File

@ -39,6 +39,7 @@ private slots:
void undefineValid(); void undefineValid();
void reflectionValid(); void reflectionValid();
void markupValid(); void markupValid();
void containerValid();
private: private:
void loadCfgFile(QString filename, CppcheckLibraryData &data, QString &res, bool removeFile = false); void loadCfgFile(QString filename, CppcheckLibraryData &data, QString &res, bool removeFile = false);