Skip to content

Commit 7658aa8

Browse files
authored
Fix library data reflection (cppcheck-opensource#3107)
1 parent 0ecac8e commit 7658aa8

11 files changed

Lines changed: 232 additions & 0 deletions

gui/cppchecklibrarydata.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,33 @@ static CppcheckLibraryData::PlatformType loadPlatformType(QXmlStreamReader &xmlR
294294
return platformType;
295295
}
296296

297+
static CppcheckLibraryData::Reflection loadReflection(QXmlStreamReader &xmlReader)
298+
{
299+
CppcheckLibraryData::Reflection reflection;
300+
301+
QXmlStreamReader::TokenType type;
302+
while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
303+
xmlReader.name().toString() != "reflection") {
304+
if (type != QXmlStreamReader::StartElement)
305+
continue;
306+
const QString elementName = xmlReader.name().toString();
307+
if (elementName == "call") {
308+
CppcheckLibraryData::Reflection::Call call;
309+
if (xmlReader.attributes().hasAttribute("arg")) {
310+
call.arg = xmlReader.attributes().value("arg").toInt();
311+
} else {
312+
mandatoryAttibuteMissing(xmlReader, "arg");
313+
}
314+
call.name = xmlReader.readElementText();
315+
reflection.calls.append(call);
316+
} else {
317+
unhandledElement(xmlReader);
318+
}
319+
}
320+
321+
return reflection;
322+
}
323+
297324
QString CppcheckLibraryData::open(QIODevice &file)
298325
{
299326
clear();
@@ -330,6 +357,8 @@ QString CppcheckLibraryData::open(QIODevice &file)
330357
typeChecks.append(loadTypeChecks(xmlReader));
331358
else if (elementName == "platformtype")
332359
platformTypes.append(loadPlatformType(xmlReader));
360+
else if (elementName == "reflection")
361+
reflections.append(loadReflection(xmlReader));
333362
else
334363
unhandledElement(xmlReader);
335364
} catch (std::runtime_error &e) {
@@ -589,6 +618,18 @@ static void writePlatformType(QXmlStreamWriter &xmlWriter, const CppcheckLibrary
589618
xmlWriter.writeEndElement();
590619
}
591620

621+
static void writeReflection (QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Reflection &refl)
622+
{
623+
xmlWriter.writeStartElement("reflection");
624+
foreach (const CppcheckLibraryData::Reflection::Call &call, refl.calls) {
625+
xmlWriter.writeStartElement("call");
626+
xmlWriter.writeAttribute("arg", QString("%1").arg(call.arg));
627+
xmlWriter.writeCharacters(call.name);
628+
xmlWriter.writeEndElement();
629+
}
630+
xmlWriter.writeEndElement();
631+
}
632+
592633
QString CppcheckLibraryData::toString() const
593634
{
594635
QString outputString;
@@ -650,6 +691,10 @@ QString CppcheckLibraryData::toString() const
650691
writePlatformType(xmlWriter, pt);
651692
}
652693

694+
foreach (const Reflection &refl, reflections) {
695+
writeReflection(xmlWriter, refl);
696+
}
697+
653698
xmlWriter.writeEndElement();
654699

655700
return outputString;

gui/cppchecklibrarydata.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,19 @@ class CppcheckLibraryData {
180180

181181
using TypeChecks = QList<QPair<QString, QString>>;
182182

183+
struct Reflection {
184+
struct Call {
185+
Call() :
186+
arg {-1} // -1: Mandatory "arg" attribute not available
187+
{}
188+
189+
int arg;
190+
QString name;
191+
};
192+
193+
QList<struct Call> calls;
194+
};
195+
183196
void clear() {
184197
containers.clear();
185198
defines.clear();
@@ -190,6 +203,7 @@ class CppcheckLibraryData {
190203
smartPointers.clear();
191204
typeChecks.clear();
192205
platformTypes.clear();
206+
reflections.clear();
193207
}
194208

195209
void swap(CppcheckLibraryData &other) {
@@ -202,6 +216,7 @@ class CppcheckLibraryData {
202216
smartPointers.swap(other.smartPointers);
203217
typeChecks.swap(other.typeChecks);
204218
platformTypes.swap(other.platformTypes);
219+
reflections.swap(other.reflections);
205220
}
206221

207222
QString open(QIODevice &file);
@@ -216,6 +231,7 @@ class CppcheckLibraryData {
216231
QList<struct PlatformType> platformTypes;
217232
QStringList undefines;
218233
QStringList smartPointers;
234+
QList<struct Reflection> reflections;
219235
};
220236

221237
#endif // CPPCHECKLIBRARYDATA_H
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0"?>
2+
<def format="2">
3+
<container id="stdStack" startPattern="std :: stack &lt;" inherits="stdContainer">
4+
<!-- error: invalid element acess -->
5+
<acess>
6+
<function name="push" action="push"/>
7+
<function name="pop" action="pop"/>
8+
<function name="top" yields="item"/>
9+
</access>
10+
</container>
11+
</def>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0"?>
2+
<def format="2">
3+
<define name="INT8_MIN" value="-128"/>
4+
<define/>
5+
</def>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0"?>
2+
<def format="2">
3+
<reflection>
4+
<call>invokeMethod</call>
5+
</reflection>
6+
</def>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0"?>
2+
<def format="2">
3+
<reflection>
4+
<!-- error: invalid element calls -->
5+
<calls arg="2">invokeMethod</call>
6+
</reflection>
7+
</def>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0"?>
2+
<def format="2">
3+
<reflection>
4+
<call arg="2">invokeMethod</call>
5+
<call arg="1">callFunction</call>
6+
</reflection>
7+
<reflection/>
8+
</def>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0"?>
2+
<def format="2">
3+
<undefine name="INT8_MIN"/>
4+
<undefine/>
5+
</def>

gui/test/cppchecklibrarydata/resources.qrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,11 @@
1010
<file>files/platform_type_unhandled_element.cfg</file>
1111
<file>files/memory_resource_unhandled_element.cfg</file>
1212
<file>files/memory_resource_valid.cfg</file>
13+
<file>files/define_valid.cfg</file>
14+
<file>files/undefine_valid.cfg</file>
15+
<file>files/container_unhandled_element.cfg</file>
16+
<file>files/reflection_unhandled_element.cfg</file>
17+
<file>files/reflection_valid.cfg</file>
18+
<file>files/reflection_mandatory_attribute_missing.cfg</file>
1319
</qresource>
1420
</RCC>

gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,25 @@ void TestCppcheckLibraryData::unhandledElement()
4747
loadCfgFile(":/files/memory_resource_unhandled_element.cfg", fileLibraryData, result);
4848
QCOMPARE(result.isNull(), false);
4949
qDebug() << result;
50+
51+
loadCfgFile(":/files/container_unhandled_element.cfg", fileLibraryData, result);
52+
QCOMPARE(result.isNull(), false);
53+
qDebug() << result;
54+
55+
loadCfgFile(":/files/reflection_unhandled_element.cfg", fileLibraryData, result);
56+
QCOMPARE(result.isNull(), false);
57+
qDebug() << result;
5058
}
5159

5260
void TestCppcheckLibraryData::mandatoryAttributeMissing()
5361
{
5462
loadCfgFile(":/files/mandatory_attribute_missing.cfg", fileLibraryData, result);
5563
QCOMPARE(result.isNull(), false);
5664
qDebug() << result;
65+
66+
loadCfgFile(":/files/reflection_mandatory_attribute_missing.cfg", fileLibraryData, result);
67+
QCOMPARE(result.isNull(), false);
68+
qDebug() << result;
5769
}
5870

5971
void TestCppcheckLibraryData::podtypeValid()
@@ -337,6 +349,114 @@ void TestCppcheckLibraryData::memoryResourceValid()
337349
}
338350
}
339351

352+
void TestCppcheckLibraryData::defineValid()
353+
{
354+
// Load library data from file
355+
loadCfgFile(":/files/define_valid.cfg", fileLibraryData, result);
356+
QCOMPARE(result.isNull(), true);
357+
358+
// Swap libray data read from file to other object
359+
libraryData.swap(fileLibraryData);
360+
361+
// Do size and content checks against swapped data.
362+
QCOMPARE(libraryData.defines.size(), 2);
363+
QCOMPARE(libraryData.defines[0].name, "INT8_MIN");
364+
QCOMPARE(libraryData.defines[0].value, "-128");
365+
QCOMPARE(libraryData.defines[1].name.isEmpty(), true);
366+
QCOMPARE(libraryData.defines[1].value.isEmpty(), true);
367+
368+
// Save library data to file
369+
saveCfgFile(TempCfgFile, libraryData);
370+
371+
fileLibraryData.clear();
372+
QCOMPARE(fileLibraryData.defines.size(), 0);
373+
374+
// Reload library data from file
375+
loadCfgFile(TempCfgFile, fileLibraryData, result, true);
376+
QCOMPARE(result.isNull(), true);
377+
378+
// Verify no data got lost or modified
379+
QCOMPARE(libraryData.defines.size(), fileLibraryData.defines.size());
380+
QCOMPARE(libraryData.defines.size(), 2);
381+
for (int idx=0; idx < libraryData.defines.size(); idx++) {
382+
QCOMPARE(libraryData.defines[idx].name, fileLibraryData.defines[idx].name);
383+
QCOMPARE(libraryData.defines[idx].value, fileLibraryData.defines[idx].value);
384+
}
385+
}
386+
387+
void TestCppcheckLibraryData::undefineValid()
388+
{
389+
// Load library data from file
390+
loadCfgFile(":/files/undefine_valid.cfg", fileLibraryData, result);
391+
QCOMPARE(result.isNull(), true);
392+
393+
// Swap libray data read from file to other object
394+
libraryData.swap(fileLibraryData);
395+
396+
// Do size and content checks against swapped data.
397+
QCOMPARE(libraryData.undefines.size(), 2);
398+
QCOMPARE(libraryData.undefines[0], "INT8_MIN");
399+
QCOMPARE(libraryData.undefines[1].isEmpty(), true);
400+
401+
// Save library data to file
402+
saveCfgFile(TempCfgFile, libraryData);
403+
404+
fileLibraryData.clear();
405+
QCOMPARE(fileLibraryData.undefines.size(), 0);
406+
407+
// Reload library data from file
408+
loadCfgFile(TempCfgFile, fileLibraryData, result, true);
409+
QCOMPARE(result.isNull(), true);
410+
411+
// Verify no data got lost or modified
412+
QCOMPARE(libraryData.undefines.size(), fileLibraryData.undefines.size());
413+
QCOMPARE(libraryData.undefines.size(), 2);
414+
QCOMPARE(libraryData.undefines, fileLibraryData.undefines);
415+
}
416+
417+
void TestCppcheckLibraryData::reflectionValid()
418+
{
419+
// Load library data from file
420+
loadCfgFile(":/files/reflection_valid.cfg", fileLibraryData, result);
421+
QCOMPARE(result.isNull(), true);
422+
423+
// Swap libray data read from file to other object
424+
libraryData.swap(fileLibraryData);
425+
426+
// Do size and content checks against swapped data.
427+
QCOMPARE(libraryData.reflections.size(), 2);
428+
QCOMPARE(libraryData.reflections[0].calls.size(), 2);
429+
QCOMPARE(libraryData.reflections[0].calls[0].arg, 2);
430+
QCOMPARE(libraryData.reflections[0].calls[0].name, "invokeMethod");
431+
QCOMPARE(libraryData.reflections[0].calls[1].arg, 1);
432+
QCOMPARE(libraryData.reflections[0].calls[1].name, "callFunction");
433+
QCOMPARE(libraryData.reflections[1].calls.isEmpty(), true);
434+
435+
// Save library data to file
436+
saveCfgFile(TempCfgFile, libraryData);
437+
438+
fileLibraryData.clear();
439+
QCOMPARE(fileLibraryData.reflections.size(), 0);
440+
441+
// Reload library data from file
442+
loadCfgFile(TempCfgFile, fileLibraryData, result, true);
443+
QCOMPARE(result.isNull(), true);
444+
445+
// Verify no data got lost or modified
446+
QCOMPARE(libraryData.reflections.size(), fileLibraryData.reflections.size());
447+
QCOMPARE(libraryData.reflections.size(), 2);
448+
for (int idx=0; idx < libraryData.reflections.size(); idx++) {
449+
CppcheckLibraryData::Reflection lhs = libraryData.reflections[idx];
450+
CppcheckLibraryData::Reflection rhs = fileLibraryData.reflections[idx];
451+
452+
QCOMPARE(lhs.calls.size(), rhs.calls.size());
453+
for (int num=0; num < lhs.calls.size(); num++) {
454+
QCOMPARE(lhs.calls[num].arg, rhs.calls[num].arg);
455+
QCOMPARE(lhs.calls[num].name, rhs.calls[num].name);
456+
}
457+
}
458+
}
459+
340460
void TestCppcheckLibraryData::loadCfgFile(QString filename, CppcheckLibraryData &data, QString &result, bool removeFile)
341461
{
342462
QFile file(filename);

0 commit comments

Comments
 (0)