Fix library data markup (#3118)
This commit is contained in:
parent
f48e195c31
commit
25fa7c55d8
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include <QXmlStreamReader>
|
||||
#include <QXmlStreamWriter>
|
||||
#include <QVariant>
|
||||
|
||||
const unsigned int CppcheckLibraryData::Function::Arg::ANY = ~0U;
|
||||
const unsigned int CppcheckLibraryData::Function::Arg::VARIADIC = ~1U;
|
||||
|
@ -321,6 +322,108 @@ static CppcheckLibraryData::Reflection loadReflection(QXmlStreamReader &xmlReade
|
|||
return reflection;
|
||||
}
|
||||
|
||||
static CppcheckLibraryData::Markup loadMarkup(QXmlStreamReader &xmlReader)
|
||||
{
|
||||
CppcheckLibraryData::Markup markup;
|
||||
|
||||
QXmlStreamReader::TokenType type;
|
||||
if (xmlReader.attributes().hasAttribute("ext")) {
|
||||
markup.ext = xmlReader.attributes().value("ext").toString();
|
||||
}
|
||||
else {
|
||||
mandatoryAttibuteMissing(xmlReader, "ext");
|
||||
}
|
||||
if (xmlReader.attributes().hasAttribute("aftercode")) {
|
||||
markup.afterCode = (xmlReader.attributes().value("aftercode") == "true") ? true : false;
|
||||
}
|
||||
else {
|
||||
mandatoryAttibuteMissing(xmlReader, "aftercode");
|
||||
}
|
||||
if (xmlReader.attributes().hasAttribute("reporterrors")) {
|
||||
markup.reportErrors = (xmlReader.attributes().value("reporterrors") == "true") ? true : false;
|
||||
}
|
||||
else {
|
||||
mandatoryAttibuteMissing(xmlReader, "reporterrors");
|
||||
}
|
||||
|
||||
while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
|
||||
xmlReader.name().toString() != "markup") {
|
||||
if (type != QXmlStreamReader::StartElement)
|
||||
continue;
|
||||
const QString elementName = xmlReader.name().toString();
|
||||
if (elementName == "keywords") {
|
||||
while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
|
||||
xmlReader.name().toString() != "keywords") {
|
||||
if (type != QXmlStreamReader::StartElement)
|
||||
continue;
|
||||
if (xmlReader.name().toString() == "keyword") {
|
||||
markup.keywords.append(xmlReader.attributes().value("name").toString());
|
||||
}
|
||||
else {
|
||||
unhandledElement(xmlReader);
|
||||
}
|
||||
}
|
||||
} else if (elementName == "codeblocks") {
|
||||
CppcheckLibraryData::Markup::CodeBlocks codeBlock;
|
||||
|
||||
while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
|
||||
xmlReader.name().toString() != "codeblocks") {
|
||||
if (type != QXmlStreamReader::StartElement)
|
||||
continue;
|
||||
if (xmlReader.name().toString() == "block") {
|
||||
codeBlock.blocks.append(xmlReader.attributes().value("name").toString());
|
||||
}
|
||||
else if (xmlReader.name().toString() == "structure") {
|
||||
codeBlock.offset = xmlReader.attributes().value("offset").toInt();
|
||||
codeBlock.start = xmlReader.attributes().value("start").toString();
|
||||
codeBlock.end = xmlReader.attributes().value("end").toString();
|
||||
}
|
||||
else {
|
||||
unhandledElement(xmlReader);
|
||||
}
|
||||
}
|
||||
markup.codeBlocks.append(codeBlock);
|
||||
} else if (elementName == "exported") {
|
||||
CppcheckLibraryData::Markup::Exporter exporter;
|
||||
|
||||
while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
|
||||
xmlReader.name().toString() != "exported") {
|
||||
if (type != QXmlStreamReader::StartElement)
|
||||
continue;
|
||||
if (xmlReader.name().toString() == "exporter") {
|
||||
exporter.prefix = xmlReader.attributes().value("prefix").toString();
|
||||
}
|
||||
else if (xmlReader.name().toString() == "prefix") {
|
||||
exporter.prefixList.append(xmlReader.readElementText());
|
||||
}
|
||||
else if (xmlReader.name().toString() == "suffix") {
|
||||
exporter.suffixList.append(xmlReader.readElementText());
|
||||
}
|
||||
else {
|
||||
unhandledElement(xmlReader);
|
||||
}
|
||||
}
|
||||
markup.exporter.append(exporter);
|
||||
} else if (elementName == "imported") {
|
||||
while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
|
||||
xmlReader.name().toString() != "imported") {
|
||||
if (type != QXmlStreamReader::StartElement)
|
||||
continue;
|
||||
if (xmlReader.name().toString() == "importer") {
|
||||
markup.importer.append(xmlReader.readElementText());
|
||||
}
|
||||
else {
|
||||
unhandledElement(xmlReader);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unhandledElement(xmlReader);
|
||||
}
|
||||
}
|
||||
|
||||
return markup;
|
||||
}
|
||||
|
||||
QString CppcheckLibraryData::open(QIODevice &file)
|
||||
{
|
||||
clear();
|
||||
|
@ -359,6 +462,8 @@ QString CppcheckLibraryData::open(QIODevice &file)
|
|||
platformTypes.append(loadPlatformType(xmlReader));
|
||||
else if (elementName == "reflection")
|
||||
reflections.append(loadReflection(xmlReader));
|
||||
else if (elementName == "markup")
|
||||
markups.append(loadMarkup(xmlReader));
|
||||
else
|
||||
unhandledElement(xmlReader);
|
||||
} catch (std::runtime_error &e) {
|
||||
|
@ -630,6 +735,68 @@ static void writeReflection(QXmlStreamWriter &xmlWriter, const CppcheckLibraryDa
|
|||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
static void writeMarkup(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Markup &mup)
|
||||
{
|
||||
xmlWriter.writeStartElement("markup");
|
||||
xmlWriter.writeAttribute("ext", mup.ext);
|
||||
xmlWriter.writeAttribute("aftercode", QVariant(mup.afterCode).toString());
|
||||
xmlWriter.writeAttribute("reporterrors", QVariant(mup.reportErrors).toString());
|
||||
if (!mup.keywords.isEmpty()) {
|
||||
xmlWriter.writeStartElement("keywords");
|
||||
foreach (const QString &keyword, mup.keywords) {
|
||||
xmlWriter.writeStartElement("keyword");
|
||||
xmlWriter.writeAttribute("name", keyword);
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
if (!mup.importer.isEmpty()) {
|
||||
xmlWriter.writeStartElement("imported");
|
||||
foreach (const QString &import, mup.importer) {
|
||||
xmlWriter.writeStartElement("importer");
|
||||
xmlWriter.writeCharacters(import);
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
if (!mup.exporter.isEmpty()) {
|
||||
xmlWriter.writeStartElement("exported");
|
||||
foreach (const CppcheckLibraryData::Markup::Exporter exporter, mup.exporter) {
|
||||
xmlWriter.writeStartElement("exporter");
|
||||
xmlWriter.writeAttribute("prefix", exporter.prefix);
|
||||
foreach (const QString &prefix, exporter.prefixList) {
|
||||
xmlWriter.writeStartElement("prefix");
|
||||
xmlWriter.writeCharacters(prefix);
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
foreach (const QString &suffix, exporter.suffixList) {
|
||||
xmlWriter.writeStartElement("suffix");
|
||||
xmlWriter.writeCharacters(suffix);
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
if (!mup.codeBlocks.isEmpty()) {
|
||||
foreach (const CppcheckLibraryData::Markup::CodeBlocks codeblock, mup.codeBlocks) {
|
||||
xmlWriter.writeStartElement("codeblocks");
|
||||
foreach (const QString &block, codeblock.blocks) {
|
||||
xmlWriter.writeStartElement("block");
|
||||
xmlWriter.writeAttribute("name", block);
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
xmlWriter.writeStartElement("structure");
|
||||
xmlWriter.writeAttribute("offset", QString("%1").arg(codeblock.offset));
|
||||
xmlWriter.writeAttribute("start", codeblock.start);
|
||||
xmlWriter.writeAttribute("end", codeblock.end);
|
||||
xmlWriter.writeEndElement();
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
}
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
QString CppcheckLibraryData::toString() const
|
||||
{
|
||||
QString outputString;
|
||||
|
@ -695,6 +862,10 @@ QString CppcheckLibraryData::toString() const
|
|||
writeReflection(xmlWriter, refl);
|
||||
}
|
||||
|
||||
foreach (const Markup &mup, markups) {
|
||||
writeMarkup(xmlWriter, mup);
|
||||
}
|
||||
|
||||
xmlWriter.writeEndElement();
|
||||
|
||||
return outputString;
|
||||
|
|
|
@ -193,6 +193,33 @@ public:
|
|||
QList<struct Call> calls;
|
||||
};
|
||||
|
||||
struct Markup {
|
||||
struct CodeBlocks {
|
||||
CodeBlocks() :
|
||||
offset {-1}
|
||||
{}
|
||||
|
||||
QStringList blocks;
|
||||
int offset;
|
||||
QString start;
|
||||
QString end;
|
||||
};
|
||||
|
||||
struct Exporter {
|
||||
QString prefix;
|
||||
QStringList prefixList;
|
||||
QStringList suffixList;
|
||||
};
|
||||
|
||||
QString ext;
|
||||
bool afterCode;
|
||||
bool reportErrors;
|
||||
QStringList keywords;
|
||||
QStringList importer;
|
||||
QList<CodeBlocks> codeBlocks;
|
||||
QList<Exporter> exporter;
|
||||
};
|
||||
|
||||
void clear() {
|
||||
containers.clear();
|
||||
defines.clear();
|
||||
|
@ -204,6 +231,7 @@ public:
|
|||
typeChecks.clear();
|
||||
platformTypes.clear();
|
||||
reflections.clear();
|
||||
markups.clear();
|
||||
}
|
||||
|
||||
void swap(CppcheckLibraryData &other) {
|
||||
|
@ -217,6 +245,7 @@ public:
|
|||
typeChecks.swap(other.typeChecks);
|
||||
platformTypes.swap(other.platformTypes);
|
||||
reflections.swap(other.reflections);
|
||||
markups.swap(other.markups);
|
||||
}
|
||||
|
||||
QString open(QIODevice &file);
|
||||
|
@ -232,6 +261,7 @@ public:
|
|||
QStringList undefines;
|
||||
QStringList smartPointers;
|
||||
QList<struct Reflection> reflections;
|
||||
QList<struct Markup> markups;
|
||||
};
|
||||
|
||||
#endif // CPPCHECKLIBRARYDATA_H
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<def format="2">
|
||||
<!-- error: invalid attribute reporterror -->
|
||||
<markup ext=".qml" reporterror="false" aftercode="true">
|
||||
</markup>
|
||||
</def>
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0"?>
|
||||
<def format="2">
|
||||
<!-- Test data from qt.cfg -->
|
||||
<markup ext=".qml" reporterrors="false" aftercode="true">
|
||||
<keywords>
|
||||
<keyword name="if"/>
|
||||
<keyword name="while"/>
|
||||
<keyword name="typeof"/>
|
||||
<keyword name="for"/>
|
||||
</keywords>
|
||||
<codeblocks>
|
||||
<block name="onClicked"/>
|
||||
<block name="onFinished"/>
|
||||
<block name="onTriggered"/>
|
||||
<block name="onPressed"/>
|
||||
<block name="onTouch"/>
|
||||
<structure offset="3" start="{" end="}"/>
|
||||
</codeblocks>
|
||||
<codeblocks>
|
||||
<block name="function"/>
|
||||
<structure offset="2" start="{" end="}"/>
|
||||
</codeblocks>
|
||||
<!-- error: invalid element export -->
|
||||
<export>
|
||||
<exporter prefix="Q_PROPERTY">
|
||||
<suffix>READ</suffix>
|
||||
<prefix>READ</prefix>
|
||||
<prefix>WRITE</prefix>
|
||||
<prefix>NOTIFY</prefix>
|
||||
</exporter>
|
||||
</export>
|
||||
<imported>
|
||||
<importer>connect</importer>
|
||||
</imported>
|
||||
</markup>
|
||||
</def>
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0"?>
|
||||
<def format="2">
|
||||
<!-- Test data from qt.cfg -->
|
||||
<markup ext=".qml" reporterrors="false" aftercode="true">
|
||||
<keywords>
|
||||
<keyword name="if"/>
|
||||
<keyword name="while"/>
|
||||
<keyword name="typeof"/>
|
||||
<keyword name="for"/>
|
||||
</keywords>
|
||||
<codeblocks>
|
||||
<block name="onClicked"/>
|
||||
<block name="onFinished"/>
|
||||
<block name="onTriggered"/>
|
||||
<block name="onPressed"/>
|
||||
<block name="onTouch"/>
|
||||
<structure offset="3" start="{" end="}"/>
|
||||
</codeblocks>
|
||||
<codeblocks>
|
||||
<block name="function"/>
|
||||
<structure offset="2" start="{" end="}"/>
|
||||
</codeblocks>
|
||||
<exported>
|
||||
<exporter prefix="Q_PROPERTY">
|
||||
<suffix>READ</suffix>
|
||||
<prefix>READ</prefix>
|
||||
<prefix>WRITE</prefix>
|
||||
<prefix>NOTIFY</prefix>
|
||||
</exporter>
|
||||
</exported>
|
||||
<imported>
|
||||
<importer>connect</importer>
|
||||
</imported>
|
||||
</markup>
|
||||
</def>
|
|
@ -16,5 +16,8 @@
|
|||
<file>files/reflection_unhandled_element.cfg</file>
|
||||
<file>files/reflection_valid.cfg</file>
|
||||
<file>files/reflection_mandatory_attribute_missing.cfg</file>
|
||||
<file>files/markup_mandatory_attribute_missing.cfg</file>
|
||||
<file>files/markup_valid.cfg</file>
|
||||
<file>files/markup_unhandled_element.cfg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -55,6 +55,10 @@ void TestCppcheckLibraryData::unhandledElement()
|
|||
loadCfgFile(":/files/reflection_unhandled_element.cfg", fileLibraryData, result);
|
||||
QCOMPARE(result.isNull(), false);
|
||||
qDebug() << result;
|
||||
|
||||
loadCfgFile(":/files/markup_unhandled_element.cfg", fileLibraryData, result);
|
||||
QCOMPARE(result.isNull(), false);
|
||||
qDebug() << result;
|
||||
}
|
||||
|
||||
void TestCppcheckLibraryData::mandatoryAttributeMissing()
|
||||
|
@ -66,6 +70,10 @@ void TestCppcheckLibraryData::mandatoryAttributeMissing()
|
|||
loadCfgFile(":/files/reflection_mandatory_attribute_missing.cfg", fileLibraryData, result);
|
||||
QCOMPARE(result.isNull(), false);
|
||||
qDebug() << result;
|
||||
|
||||
loadCfgFile(":/files/markup_mandatory_attribute_missing.cfg", fileLibraryData, result);
|
||||
QCOMPARE(result.isNull(), false);
|
||||
qDebug() << result;
|
||||
}
|
||||
|
||||
void TestCppcheckLibraryData::podtypeValid()
|
||||
|
@ -457,6 +465,81 @@ void TestCppcheckLibraryData::reflectionValid()
|
|||
}
|
||||
}
|
||||
|
||||
void TestCppcheckLibraryData::markupValid()
|
||||
{
|
||||
// Load library data from file
|
||||
loadCfgFile(":/files/markup_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.markups.size(), 1);
|
||||
QCOMPARE(libraryData.markups[0].ext, ".qml");
|
||||
QCOMPARE(libraryData.markups[0].reportErrors, false);
|
||||
QCOMPARE(libraryData.markups[0].afterCode, true);
|
||||
|
||||
QCOMPARE(libraryData.markups[0].keywords.size(), 4);
|
||||
QCOMPARE(libraryData.markups[0].keywords, QStringList( {"if", "while", "typeof", "for"} ));
|
||||
|
||||
QCOMPARE(libraryData.markups[0].importer.size(), 1);
|
||||
QCOMPARE(libraryData.markups[0].importer, QStringList("connect"));
|
||||
|
||||
QCOMPARE(libraryData.markups[0].exporter.size(), 1);
|
||||
QCOMPARE(libraryData.markups[0].exporter[0].prefix, "Q_PROPERTY");
|
||||
QCOMPARE(libraryData.markups[0].exporter[0].suffixList.size(), 1);
|
||||
QCOMPARE(libraryData.markups[0].exporter[0].suffixList, QStringList("READ"));
|
||||
QCOMPARE(libraryData.markups[0].exporter[0].prefixList.size(), 3);
|
||||
QCOMPARE(libraryData.markups[0].exporter[0].prefixList, QStringList( {"READ", "WRITE", "NOTIFY"} ));
|
||||
|
||||
QCOMPARE(libraryData.markups[0].codeBlocks.size(), 2);
|
||||
QCOMPARE(libraryData.markups[0].codeBlocks[0].blocks.size(), 5);
|
||||
QCOMPARE(libraryData.markups[0].codeBlocks[0].blocks, QStringList( {"onClicked", "onFinished", "onTriggered", "onPressed", "onTouch"} ));
|
||||
QCOMPARE(libraryData.markups[0].codeBlocks[0].offset, 3);
|
||||
QCOMPARE(libraryData.markups[0].codeBlocks[0].start, "{");
|
||||
QCOMPARE(libraryData.markups[0].codeBlocks[0].end, "}");
|
||||
QCOMPARE(libraryData.markups[0].codeBlocks[1].blocks.size(), 1);
|
||||
QCOMPARE(libraryData.markups[0].codeBlocks[1].blocks, QStringList("function"));
|
||||
QCOMPARE(libraryData.markups[0].codeBlocks[1].offset, 2);
|
||||
QCOMPARE(libraryData.markups[0].codeBlocks[1].start, "{");
|
||||
QCOMPARE(libraryData.markups[0].codeBlocks[1].end, "}");
|
||||
|
||||
// Save library data to file
|
||||
saveCfgFile(TempCfgFile, libraryData);
|
||||
|
||||
fileLibraryData.clear();
|
||||
QCOMPARE(fileLibraryData.markups.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.markups.size(), fileLibraryData.markups.size());
|
||||
for (int idx=0; idx < libraryData.markups.size(); idx++) {
|
||||
CppcheckLibraryData::Markup lhs = libraryData.markups[idx];
|
||||
CppcheckLibraryData::Markup rhs = fileLibraryData.markups[idx];
|
||||
|
||||
QCOMPARE(lhs.ext, rhs.ext);
|
||||
QCOMPARE(lhs.reportErrors, rhs.reportErrors);
|
||||
QCOMPARE(lhs.afterCode, rhs.afterCode);
|
||||
QCOMPARE(lhs.keywords, rhs.keywords);
|
||||
QCOMPARE(lhs.importer, rhs.importer);
|
||||
for (int num=0; num < lhs.exporter.size(); num++) {
|
||||
QCOMPARE(lhs.exporter[num].prefix, rhs.exporter[num].prefix);
|
||||
QCOMPARE(lhs.exporter[num].suffixList, rhs.exporter[num].suffixList);
|
||||
QCOMPARE(lhs.exporter[num].prefixList, rhs.exporter[num].prefixList);
|
||||
}
|
||||
for (int num=0; num < lhs.codeBlocks.size(); num++) {
|
||||
QCOMPARE(lhs.codeBlocks[num].blocks, rhs.codeBlocks[num].blocks);
|
||||
QCOMPARE(lhs.codeBlocks[num].offset, rhs.codeBlocks[num].offset);
|
||||
QCOMPARE(lhs.codeBlocks[num].start, rhs.codeBlocks[num].start);
|
||||
QCOMPARE(lhs.codeBlocks[num].end, rhs.codeBlocks[num].end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestCppcheckLibraryData::loadCfgFile(QString filename, CppcheckLibraryData &data, QString &result, bool removeFile)
|
||||
{
|
||||
QFile file(filename);
|
||||
|
|
|
@ -37,6 +37,7 @@ private slots:
|
|||
void defineValid();
|
||||
void undefineValid();
|
||||
void reflectionValid();
|
||||
void markupValid();
|
||||
|
||||
private:
|
||||
void loadCfgFile(QString filename, CppcheckLibraryData &data, QString &result, bool removeFile = false);
|
||||
|
|
Loading…
Reference in New Issue