Skip to content

Commit c897c04

Browse files
authored
Library Data: Add support for optional smart pointer element 'unique' (cppcheck-opensource#4132)
1 parent 22aeeb1 commit c897c04

7 files changed

Lines changed: 155 additions & 13 deletions

File tree

gui/cppchecklibrarydata.cpp

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ static CppcheckLibraryData::Container loadContainer(QXmlStreamReader &xmlReader)
6161
if (elementName == "type") {
6262
container.type.templateParameter = xmlReader.attributes().value("templateParameter").toString();
6363
container.type.string = xmlReader.attributes().value("string").toString();
64-
} else if (elementName == "size" || elementName == "access" || elementName == "other") {
64+
} else if (elementName == "size" || elementName == "access" || elementName == "other" || elementName == "rangeItemRecordType") {
6565
const QString indexOperator = xmlReader.attributes().value("indexOperator").toString();
6666
if (elementName == "access" && indexOperator == "array-like")
6767
container.access_arrayLike = true;
@@ -82,7 +82,12 @@ static CppcheckLibraryData::Container loadContainer(QXmlStreamReader &xmlReader)
8282
container.sizeFunctions.append(function);
8383
else if (elementName == "access")
8484
container.accessFunctions.append(function);
85-
else
85+
else if (elementName == "rangeItemRecordType") {
86+
struct CppcheckLibraryData::Container::RangeItemRecordType rangeItemRecordType;
87+
rangeItemRecordType.name = xmlReader.attributes().value("name").toString();
88+
rangeItemRecordType.templateParameter = xmlReader.attributes().value("templateParameter").toString();
89+
container.rangeItemRecordTypeList.append(rangeItemRecordType);
90+
} else
8691
container.otherFunctions.append(function);
8792
}
8893
} else {
@@ -105,9 +110,23 @@ static QString loadUndefine(const QXmlStreamReader &xmlReader)
105110
return xmlReader.attributes().value("name").toString();
106111
}
107112

108-
static QString loadSmartPointer(const QXmlStreamReader &xmlReader)
113+
static CppcheckLibraryData::SmartPointer loadSmartPointer(QXmlStreamReader &xmlReader)
109114
{
110-
return xmlReader.attributes().value("class-name").toString();
115+
CppcheckLibraryData::SmartPointer smartPointer;
116+
smartPointer.name = xmlReader.attributes().value("class-name").toString();
117+
QXmlStreamReader::TokenType type;
118+
while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
119+
xmlReader.name().toString() != "smart-pointer") {
120+
if (type != QXmlStreamReader::StartElement)
121+
continue;
122+
const QString elementName = xmlReader.name().toString();
123+
if (elementName == "unique") {
124+
smartPointer.unique = true;
125+
} else {
126+
unhandledElement(xmlReader);
127+
}
128+
}
129+
return smartPointer;
111130
}
112131

113132
static CppcheckLibraryData::TypeChecks loadTypeChecks(QXmlStreamReader &xmlReader)
@@ -210,6 +229,20 @@ static CppcheckLibraryData::Function loadFunction(QXmlStreamReader &xmlReader, c
210229
function.warn.reason = xmlReader.attributes().value("reason").toString();
211230
function.warn.alternatives = xmlReader.attributes().value("alternatives").toString();
212231
function.warn.msg = xmlReader.readElementText();
232+
} else if (elementName == "not-overlapping-data") {
233+
const QStringList attributeList {"ptr1-arg", "ptr2-arg", "size-arg", "strlen-arg"};
234+
for (const QString &attr : attributeList) {
235+
if (xmlReader.attributes().hasAttribute(attr)) {
236+
function.notOverlappingDataArgs[attr] = xmlReader.attributes().value(attr).toString();
237+
}
238+
}
239+
} else if (elementName == "container") {
240+
const QStringList attributeList {"action", "yields"};
241+
for (const QString &attr : attributeList) {
242+
if (xmlReader.attributes().hasAttribute(attr)) {
243+
function.containerAttributes[attr] = xmlReader.attributes().value(attr).toString();
244+
}
245+
}
213246
} else {
214247
unhandledElement(xmlReader);
215248
}
@@ -493,6 +526,20 @@ static void writeContainerFunctions(QXmlStreamWriter &xmlWriter, const QString &
493526
xmlWriter.writeEndElement();
494527
}
495528

529+
static void writeContainerRangeItemRecords(QXmlStreamWriter &xmlWriter, const QList<struct CppcheckLibraryData::Container::RangeItemRecordType> &rangeItemRecords)
530+
{
531+
if (rangeItemRecords.isEmpty())
532+
return;
533+
xmlWriter.writeStartElement("rangeItemRecordType");
534+
for (const CppcheckLibraryData::Container::RangeItemRecordType &item : rangeItemRecords) {
535+
xmlWriter.writeStartElement("member");
536+
xmlWriter.writeAttribute("name", item.name);
537+
xmlWriter.writeAttribute("templateParameter", item.templateParameter);
538+
xmlWriter.writeEndElement();
539+
}
540+
xmlWriter.writeEndElement();
541+
}
542+
496543
static void writeContainer(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Container &container)
497544
{
498545
xmlWriter.writeStartElement("container");
@@ -519,6 +566,7 @@ static void writeContainer(QXmlStreamWriter &xmlWriter, const CppcheckLibraryDat
519566
writeContainerFunctions(xmlWriter, "size", container.size_templateParameter, container.sizeFunctions);
520567
writeContainerFunctions(xmlWriter, "access", container.access_arrayLike?1:-1, container.accessFunctions);
521568
writeContainerFunctions(xmlWriter, "other", -1, container.otherFunctions);
569+
writeContainerRangeItemRecords(xmlWriter, container.rangeItemRecordTypeList);
522570
xmlWriter.writeEndElement();
523571
}
524572

@@ -632,7 +680,20 @@ static void writeFunction(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData
632680

633681
xmlWriter.writeEndElement();
634682
}
635-
683+
if (!function.notOverlappingDataArgs.isEmpty()) {
684+
xmlWriter.writeStartElement("not-overlapping-data");
685+
foreach (const QString value, function.notOverlappingDataArgs) {
686+
xmlWriter.writeAttribute(function.notOverlappingDataArgs.key(value), value);
687+
}
688+
xmlWriter.writeEndElement();
689+
}
690+
if (!function.containerAttributes.isEmpty()) {
691+
xmlWriter.writeStartElement("container");
692+
foreach (const QString value, function.containerAttributes) {
693+
xmlWriter.writeAttribute(function.containerAttributes.key(value), value);
694+
}
695+
xmlWriter.writeEndElement();
696+
}
636697
xmlWriter.writeEndElement();
637698
}
638699

@@ -835,9 +896,12 @@ QString CppcheckLibraryData::toString() const
835896
writeTypeChecks(xmlWriter, check);
836897
}
837898

838-
for (const QString &smartPtr : smartPointers) {
899+
for (const SmartPointer &smartPtr : smartPointers) {
839900
xmlWriter.writeStartElement("smart-pointer");
840-
xmlWriter.writeAttribute("class-name", smartPtr);
901+
xmlWriter.writeAttribute("class-name", smartPtr.name);
902+
if (smartPtr.unique) {
903+
xmlWriter.writeEmptyElement("unique");
904+
}
841905
xmlWriter.writeEndElement();
842906
}
843907

gui/cppchecklibrarydata.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <QList>
2323
#include <QString>
2424
#include <QStringList>
25+
#include <QMap>
2526

2627
class QIODevice;
2728

@@ -47,6 +48,11 @@ class CppcheckLibraryData {
4748
QString string;
4849
} type;
4950

51+
struct RangeItemRecordType {
52+
QString name;
53+
QString templateParameter;
54+
};
55+
5056
struct Function {
5157
QString name;
5258
QString yields;
@@ -55,6 +61,7 @@ class CppcheckLibraryData {
5561
QList<struct Function> accessFunctions;
5662
QList<struct Function> otherFunctions;
5763
QList<struct Function> sizeFunctions;
64+
QList<struct RangeItemRecordType> rangeItemRecordTypeList;
5865
};
5966

6067
struct Define {
@@ -130,6 +137,9 @@ class CppcheckLibraryData {
130137
msg.isEmpty();
131138
}
132139
} warn;
140+
141+
QMap<QString, QString> notOverlappingDataArgs;
142+
QMap<QString, QString> containerAttributes;
133143
};
134144

135145
struct MemoryResource {
@@ -219,6 +229,15 @@ class CppcheckLibraryData {
219229
QList<Exporter> exporter;
220230
};
221231

232+
struct SmartPointer {
233+
SmartPointer() :
234+
unique {false}
235+
{}
236+
237+
QString name;
238+
bool unique;
239+
};
240+
222241
void clear() {
223242
containers.clear();
224243
defines.clear();
@@ -258,7 +277,7 @@ class CppcheckLibraryData {
258277
QList<TypeChecks> typeChecks;
259278
QList<struct PlatformType> platformTypes;
260279
QStringList undefines;
261-
QStringList smartPointers;
280+
QList<struct SmartPointer> smartPointers;
262281
QList<struct Reflection> reflections;
263282
QList<struct Markup> markups;
264283
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0"?>
2+
<def format="2">
3+
<container id="stdMultiMap">
4+
<rangeItemRecordType>
5+
<member name="first" templateParameter="0"/>
6+
<member name="second" templateParameter="1"/>
7+
</rangeItemRecordType>
8+
</container>
9+
</def>
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<?xml version="1.0"?>
22
<def format="2">
33
<smart-pointer class-name="wxObjectDataPtr"/>
4-
<smart-pointer class-name="wxScopedArray"/>
4+
<smart-pointer class-name="wxScopedArray">
5+
<unique/>
6+
</smart-pointer>
57
<smart-pointer class-name="wxScopedPtr"/>
68
</def>

gui/test/cppchecklibrarydata/resources.qrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@
1919
<file>files/markup_mandatory_attribute_missing.cfg</file>
2020
<file>files/markup_valid.cfg</file>
2121
<file>files/markup_unhandled_element.cfg</file>
22+
<file>files/container_valid.cfg</file>
2223
</qresource>
2324
</RCC>

gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,12 @@ void TestCppcheckLibraryData::smartPointerValid()
182182
// Do size and content checks against swapped data.
183183
QCOMPARE(libraryData.smartPointers.size(), 3);
184184

185-
QCOMPARE(libraryData.smartPointers[0], QString("wxObjectDataPtr"));
186-
QCOMPARE(libraryData.smartPointers[1], QString("wxScopedArray"));
187-
QCOMPARE(libraryData.smartPointers[2], QString("wxScopedPtr"));
185+
QCOMPARE(libraryData.smartPointers[0].name, QString("wxObjectDataPtr"));
186+
QCOMPARE(libraryData.smartPointers[0].unique, false);
187+
QCOMPARE(libraryData.smartPointers[1].name, QString("wxScopedArray"));
188+
QCOMPARE(libraryData.smartPointers[1].unique, true);
189+
QCOMPARE(libraryData.smartPointers[2].name, QString("wxScopedPtr"));
190+
QCOMPARE(libraryData.smartPointers[2].unique, false);
188191

189192
// Save library data to file
190193
saveCfgFile(TempCfgFile, libraryData);
@@ -199,7 +202,10 @@ void TestCppcheckLibraryData::smartPointerValid()
199202
// Verify no data got lost or modified
200203
QCOMPARE(libraryData.smartPointers.size(), fileLibraryData.smartPointers.size());
201204
QCOMPARE(libraryData.smartPointers.size(), 3);
202-
QCOMPARE(libraryData.smartPointers, fileLibraryData.smartPointers);
205+
for (int idx=0; idx < libraryData.smartPointers.size(); idx++) {
206+
QCOMPARE(libraryData.smartPointers[idx].name, fileLibraryData.smartPointers[idx].name);
207+
QCOMPARE(libraryData.smartPointers[idx].unique, fileLibraryData.smartPointers[idx].unique);
208+
}
203209
}
204210

205211
void TestCppcheckLibraryData::platformTypeValid()
@@ -543,6 +549,46 @@ void TestCppcheckLibraryData::markupValid()
543549
}
544550
}
545551

552+
void TestCppcheckLibraryData::containerValid()
553+
{
554+
// Load library data from file
555+
loadCfgFile(":/files/container_valid.cfg", fileLibraryData, result);
556+
QCOMPARE(result.isNull(), true);
557+
558+
// Swap library data read from file to other object
559+
libraryData.swap(fileLibraryData);
560+
561+
// Do size and content checks against swapped data.
562+
QCOMPARE(libraryData.containers.size(), 1);
563+
564+
QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList.size(), 2);
565+
QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[0].name, QString("first"));
566+
QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[0].templateParameter, QString("0"));
567+
QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[1].name, QString("second"));
568+
QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[1].templateParameter, QString("1"));
569+
570+
// Save library data to file
571+
saveCfgFile(TempCfgFile, libraryData);
572+
573+
fileLibraryData.clear();
574+
QCOMPARE(fileLibraryData.containers.size(), 0);
575+
576+
// Reload library data from file
577+
loadCfgFile(TempCfgFile, fileLibraryData, result, true);
578+
QCOMPARE(result.isNull(), true);
579+
580+
// Verify no data got lost or modified
581+
QCOMPARE(libraryData.containers.size(), fileLibraryData.containers.size());
582+
for (int idx=0; idx < libraryData.containers.size(); idx++) {
583+
CppcheckLibraryData::Container lhs = libraryData.containers[idx];
584+
CppcheckLibraryData::Container rhs = fileLibraryData.containers[idx];
585+
for (int num=0; num < lhs.rangeItemRecordTypeList.size(); num++) {
586+
QCOMPARE(lhs.rangeItemRecordTypeList[num].name, rhs.rangeItemRecordTypeList[num].name);
587+
QCOMPARE(lhs.rangeItemRecordTypeList[num].templateParameter, rhs.rangeItemRecordTypeList[num].templateParameter);
588+
}
589+
}
590+
}
591+
546592
void TestCppcheckLibraryData::loadCfgFile(QString filename, CppcheckLibraryData &data, QString &res, bool removeFile)
547593
{
548594
QFile file(filename);

gui/test/cppchecklibrarydata/testcppchecklibrarydata.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ private slots:
3939
void undefineValid();
4040
void reflectionValid();
4141
void markupValid();
42+
void containerValid();
4243

4344
private:
4445
void loadCfgFile(QString filename, CppcheckLibraryData &data, QString &res, bool removeFile = false);

0 commit comments

Comments
 (0)