Fix library data reflection (#3107)

This commit is contained in:
Mathias Schmid 2021-02-03 12:52:52 +01:00 committed by GitHub
parent 0ecac8e23b
commit 7658aa86bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 232 additions and 0 deletions

View File

@ -294,6 +294,33 @@ static CppcheckLibraryData::PlatformType loadPlatformType(QXmlStreamReader &xmlR
return platformType;
}
static CppcheckLibraryData::Reflection loadReflection(QXmlStreamReader &xmlReader)
{
CppcheckLibraryData::Reflection reflection;
QXmlStreamReader::TokenType type;
while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
xmlReader.name().toString() != "reflection") {
if (type != QXmlStreamReader::StartElement)
continue;
const QString elementName = xmlReader.name().toString();
if (elementName == "call") {
CppcheckLibraryData::Reflection::Call call;
if (xmlReader.attributes().hasAttribute("arg")) {
call.arg = xmlReader.attributes().value("arg").toInt();
} else {
mandatoryAttibuteMissing(xmlReader, "arg");
}
call.name = xmlReader.readElementText();
reflection.calls.append(call);
} else {
unhandledElement(xmlReader);
}
}
return reflection;
}
QString CppcheckLibraryData::open(QIODevice &file)
{
clear();
@ -330,6 +357,8 @@ QString CppcheckLibraryData::open(QIODevice &file)
typeChecks.append(loadTypeChecks(xmlReader));
else if (elementName == "platformtype")
platformTypes.append(loadPlatformType(xmlReader));
else if (elementName == "reflection")
reflections.append(loadReflection(xmlReader));
else
unhandledElement(xmlReader);
} catch (std::runtime_error &e) {
@ -589,6 +618,18 @@ static void writePlatformType(QXmlStreamWriter &xmlWriter, const CppcheckLibrary
xmlWriter.writeEndElement();
}
static void writeReflection (QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Reflection &refl)
{
xmlWriter.writeStartElement("reflection");
foreach (const CppcheckLibraryData::Reflection::Call &call, refl.calls) {
xmlWriter.writeStartElement("call");
xmlWriter.writeAttribute("arg", QString("%1").arg(call.arg));
xmlWriter.writeCharacters(call.name);
xmlWriter.writeEndElement();
}
xmlWriter.writeEndElement();
}
QString CppcheckLibraryData::toString() const
{
QString outputString;
@ -650,6 +691,10 @@ QString CppcheckLibraryData::toString() const
writePlatformType(xmlWriter, pt);
}
foreach (const Reflection &refl, reflections) {
writeReflection(xmlWriter, refl);
}
xmlWriter.writeEndElement();
return outputString;

View File

@ -180,6 +180,19 @@ public:
using TypeChecks = QList<QPair<QString, QString>>;
struct Reflection {
struct Call {
Call() :
arg {-1} // -1: Mandatory "arg" attribute not available
{}
int arg;
QString name;
};
QList<struct Call> calls;
};
void clear() {
containers.clear();
defines.clear();
@ -190,6 +203,7 @@ public:
smartPointers.clear();
typeChecks.clear();
platformTypes.clear();
reflections.clear();
}
void swap(CppcheckLibraryData &other) {
@ -202,6 +216,7 @@ public:
smartPointers.swap(other.smartPointers);
typeChecks.swap(other.typeChecks);
platformTypes.swap(other.platformTypes);
reflections.swap(other.reflections);
}
QString open(QIODevice &file);
@ -216,6 +231,7 @@ public:
QList<struct PlatformType> platformTypes;
QStringList undefines;
QStringList smartPointers;
QList<struct Reflection> reflections;
};
#endif // CPPCHECKLIBRARYDATA_H

View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<def format="2">
<container id="stdStack" startPattern="std :: stack &lt;" inherits="stdContainer">
<!-- error: invalid element acess -->
<acess>
<function name="push" action="push"/>
<function name="pop" action="pop"/>
<function name="top" yields="item"/>
</access>
</container>
</def>

View File

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<def format="2">
<define name="INT8_MIN" value="-128"/>
<define/>
</def>

View File

@ -0,0 +1,6 @@
<?xml version="1.0"?>
<def format="2">
<reflection>
<call>invokeMethod</call>
</reflection>
</def>

View File

@ -0,0 +1,7 @@
<?xml version="1.0"?>
<def format="2">
<reflection>
<!-- error: invalid element calls -->
<calls arg="2">invokeMethod</call>
</reflection>
</def>

View File

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<def format="2">
<reflection>
<call arg="2">invokeMethod</call>
<call arg="1">callFunction</call>
</reflection>
<reflection/>
</def>

View File

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<def format="2">
<undefine name="INT8_MIN"/>
<undefine/>
</def>

View File

@ -10,5 +10,11 @@
<file>files/platform_type_unhandled_element.cfg</file>
<file>files/memory_resource_unhandled_element.cfg</file>
<file>files/memory_resource_valid.cfg</file>
<file>files/define_valid.cfg</file>
<file>files/undefine_valid.cfg</file>
<file>files/container_unhandled_element.cfg</file>
<file>files/reflection_unhandled_element.cfg</file>
<file>files/reflection_valid.cfg</file>
<file>files/reflection_mandatory_attribute_missing.cfg</file>
</qresource>
</RCC>

View File

@ -47,6 +47,14 @@ void TestCppcheckLibraryData::unhandledElement()
loadCfgFile(":/files/memory_resource_unhandled_element.cfg", fileLibraryData, result);
QCOMPARE(result.isNull(), false);
qDebug() << result;
loadCfgFile(":/files/container_unhandled_element.cfg", fileLibraryData, result);
QCOMPARE(result.isNull(), false);
qDebug() << result;
loadCfgFile(":/files/reflection_unhandled_element.cfg", fileLibraryData, result);
QCOMPARE(result.isNull(), false);
qDebug() << result;
}
void TestCppcheckLibraryData::mandatoryAttributeMissing()
@ -54,6 +62,10 @@ void TestCppcheckLibraryData::mandatoryAttributeMissing()
loadCfgFile(":/files/mandatory_attribute_missing.cfg", fileLibraryData, result);
QCOMPARE(result.isNull(), false);
qDebug() << result;
loadCfgFile(":/files/reflection_mandatory_attribute_missing.cfg", fileLibraryData, result);
QCOMPARE(result.isNull(), false);
qDebug() << result;
}
void TestCppcheckLibraryData::podtypeValid()
@ -337,6 +349,114 @@ void TestCppcheckLibraryData::memoryResourceValid()
}
}
void TestCppcheckLibraryData::defineValid()
{
// Load library data from file
loadCfgFile(":/files/define_valid.cfg", fileLibraryData, result);
QCOMPARE(result.isNull(), true);
// Swap libray data read from file to other object
libraryData.swap(fileLibraryData);
// Do size and content checks against swapped data.
QCOMPARE(libraryData.defines.size(), 2);
QCOMPARE(libraryData.defines[0].name, "INT8_MIN");
QCOMPARE(libraryData.defines[0].value, "-128");
QCOMPARE(libraryData.defines[1].name.isEmpty(), true);
QCOMPARE(libraryData.defines[1].value.isEmpty(), true);
// Save library data to file
saveCfgFile(TempCfgFile, libraryData);
fileLibraryData.clear();
QCOMPARE(fileLibraryData.defines.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.defines.size(), fileLibraryData.defines.size());
QCOMPARE(libraryData.defines.size(), 2);
for (int idx=0; idx < libraryData.defines.size(); idx++) {
QCOMPARE(libraryData.defines[idx].name, fileLibraryData.defines[idx].name);
QCOMPARE(libraryData.defines[idx].value, fileLibraryData.defines[idx].value);
}
}
void TestCppcheckLibraryData::undefineValid()
{
// Load library data from file
loadCfgFile(":/files/undefine_valid.cfg", fileLibraryData, result);
QCOMPARE(result.isNull(), true);
// Swap libray data read from file to other object
libraryData.swap(fileLibraryData);
// Do size and content checks against swapped data.
QCOMPARE(libraryData.undefines.size(), 2);
QCOMPARE(libraryData.undefines[0], "INT8_MIN");
QCOMPARE(libraryData.undefines[1].isEmpty(), true);
// Save library data to file
saveCfgFile(TempCfgFile, libraryData);
fileLibraryData.clear();
QCOMPARE(fileLibraryData.undefines.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.undefines.size(), fileLibraryData.undefines.size());
QCOMPARE(libraryData.undefines.size(), 2);
QCOMPARE(libraryData.undefines, fileLibraryData.undefines);
}
void TestCppcheckLibraryData::reflectionValid()
{
// Load library data from file
loadCfgFile(":/files/reflection_valid.cfg", fileLibraryData, result);
QCOMPARE(result.isNull(), true);
// Swap libray data read from file to other object
libraryData.swap(fileLibraryData);
// Do size and content checks against swapped data.
QCOMPARE(libraryData.reflections.size(), 2);
QCOMPARE(libraryData.reflections[0].calls.size(), 2);
QCOMPARE(libraryData.reflections[0].calls[0].arg, 2);
QCOMPARE(libraryData.reflections[0].calls[0].name, "invokeMethod");
QCOMPARE(libraryData.reflections[0].calls[1].arg, 1);
QCOMPARE(libraryData.reflections[0].calls[1].name, "callFunction");
QCOMPARE(libraryData.reflections[1].calls.isEmpty(), true);
// Save library data to file
saveCfgFile(TempCfgFile, libraryData);
fileLibraryData.clear();
QCOMPARE(fileLibraryData.reflections.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.reflections.size(), fileLibraryData.reflections.size());
QCOMPARE(libraryData.reflections.size(), 2);
for (int idx=0; idx < libraryData.reflections.size(); idx++) {
CppcheckLibraryData::Reflection lhs = libraryData.reflections[idx];
CppcheckLibraryData::Reflection rhs = fileLibraryData.reflections[idx];
QCOMPARE(lhs.calls.size(), rhs.calls.size());
for (int num=0; num < lhs.calls.size(); num++) {
QCOMPARE(lhs.calls[num].arg, rhs.calls[num].arg);
QCOMPARE(lhs.calls[num].name, rhs.calls[num].name);
}
}
}
void TestCppcheckLibraryData::loadCfgFile(QString filename, CppcheckLibraryData &data, QString &result, bool removeFile)
{
QFile file(filename);

View File

@ -34,6 +34,9 @@ private slots:
void smartPointerValid();
void platformTypeValid();
void memoryResourceValid();
void defineValid();
void undefineValid();
void reflectionValid();
private:
void loadCfgFile(QString filename, CppcheckLibraryData &data, QString &result, bool removeFile = false);