diff --git a/gui/cppchecklibrarydata.cpp b/gui/cppchecklibrarydata.cpp index f0514012c..2a4a0af7b 100644 --- a/gui/cppchecklibrarydata.cpp +++ b/gui/cppchecklibrarydata.cpp @@ -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; diff --git a/gui/cppchecklibrarydata.h b/gui/cppchecklibrarydata.h index af1f25efa..9dee77acb 100644 --- a/gui/cppchecklibrarydata.h +++ b/gui/cppchecklibrarydata.h @@ -180,6 +180,19 @@ public: using TypeChecks = QList>; + struct Reflection { + struct Call { + Call() : + arg {-1} // -1: Mandatory "arg" attribute not available + {} + + int arg; + QString name; + }; + + QList 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 platformTypes; QStringList undefines; QStringList smartPointers; + QList reflections; }; #endif // CPPCHECKLIBRARYDATA_H diff --git a/gui/test/cppchecklibrarydata/files/container_unhandled_element.cfg b/gui/test/cppchecklibrarydata/files/container_unhandled_element.cfg new file mode 100644 index 000000000..3d142fea1 --- /dev/null +++ b/gui/test/cppchecklibrarydata/files/container_unhandled_element.cfg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/gui/test/cppchecklibrarydata/files/define_valid.cfg b/gui/test/cppchecklibrarydata/files/define_valid.cfg new file mode 100644 index 000000000..c0cfda810 --- /dev/null +++ b/gui/test/cppchecklibrarydata/files/define_valid.cfg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/gui/test/cppchecklibrarydata/files/reflection_mandatory_attribute_missing.cfg b/gui/test/cppchecklibrarydata/files/reflection_mandatory_attribute_missing.cfg new file mode 100644 index 000000000..fd9019a48 --- /dev/null +++ b/gui/test/cppchecklibrarydata/files/reflection_mandatory_attribute_missing.cfg @@ -0,0 +1,6 @@ + + + + invokeMethod + + \ No newline at end of file diff --git a/gui/test/cppchecklibrarydata/files/reflection_unhandled_element.cfg b/gui/test/cppchecklibrarydata/files/reflection_unhandled_element.cfg new file mode 100644 index 000000000..6827f83c9 --- /dev/null +++ b/gui/test/cppchecklibrarydata/files/reflection_unhandled_element.cfg @@ -0,0 +1,7 @@ + + + + + invokeMethod + + diff --git a/gui/test/cppchecklibrarydata/files/reflection_valid.cfg b/gui/test/cppchecklibrarydata/files/reflection_valid.cfg new file mode 100644 index 000000000..1eca6368f --- /dev/null +++ b/gui/test/cppchecklibrarydata/files/reflection_valid.cfg @@ -0,0 +1,8 @@ + + + + invokeMethod + callFunction + + + diff --git a/gui/test/cppchecklibrarydata/files/undefine_valid.cfg b/gui/test/cppchecklibrarydata/files/undefine_valid.cfg new file mode 100644 index 000000000..62fb7f04d --- /dev/null +++ b/gui/test/cppchecklibrarydata/files/undefine_valid.cfg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/gui/test/cppchecklibrarydata/resources.qrc b/gui/test/cppchecklibrarydata/resources.qrc index e38997e1e..64119adb4 100644 --- a/gui/test/cppchecklibrarydata/resources.qrc +++ b/gui/test/cppchecklibrarydata/resources.qrc @@ -10,5 +10,11 @@ files/platform_type_unhandled_element.cfg files/memory_resource_unhandled_element.cfg files/memory_resource_valid.cfg + files/define_valid.cfg + files/undefine_valid.cfg + files/container_unhandled_element.cfg + files/reflection_unhandled_element.cfg + files/reflection_valid.cfg + files/reflection_mandatory_attribute_missing.cfg diff --git a/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp b/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp index e9f37d602..8f34679aa 100644 --- a/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp +++ b/gui/test/cppchecklibrarydata/testcppchecklibrarydata.cpp @@ -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); diff --git a/gui/test/cppchecklibrarydata/testcppchecklibrarydata.h b/gui/test/cppchecklibrarydata/testcppchecklibrarydata.h index 7a00c7011..7448dae26 100644 --- a/gui/test/cppchecklibrarydata/testcppchecklibrarydata.h +++ b/gui/test/cppchecklibrarydata/testcppchecklibrarydata.h @@ -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);