Add missing support for "type-checks" and "smart-pointer" configuration. (#3039)

This commit is contained in:
Mathias Schmid 2021-01-18 19:10:53 +01:00 committed by GitHub
parent fde5994cc3
commit ab7d728831
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 384 additions and 1 deletions

View File

@ -94,6 +94,11 @@ jobs:
qmake qmake
make -j$(nproc) make -j$(nproc)
./test-projectfile ./test-projectfile
popd
pushd gui/test/cppchecklibrarydata
qmake
make -j$(nproc)
./test-cppchecklibrarydata
- name: Generate Qt help file on ubuntu - name: Generate Qt help file on ubuntu
if: contains(matrix.os, 'ubuntu') if: contains(matrix.os, 'ubuntu')

View File

@ -106,6 +106,28 @@ static QString loadUndefine(const QXmlStreamReader &xmlReader)
return xmlReader.attributes().value("name").toString(); return xmlReader.attributes().value("name").toString();
} }
static QString loadSmartPointer(const QXmlStreamReader &xmlReader)
{
return xmlReader.attributes().value("class-name").toString();
}
static CppcheckLibraryData::TypeChecks loadTypeChecks(QXmlStreamReader &xmlReader)
{
CppcheckLibraryData::TypeChecks typeChecks;
QXmlStreamReader::TokenType type;
while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
xmlReader.name().toString() != "type-checks") {
if (type != QXmlStreamReader::StartElement)
continue;
const QString elementName = xmlReader.name().toString();
if (elementName == "suppress" || elementName == "check") {
QPair<QString, QString> entry(elementName, xmlReader.readElementText());
typeChecks.append(entry);
}
}
return typeChecks;
}
static CppcheckLibraryData::Function::Arg loadFunctionArg(QXmlStreamReader &xmlReader) static CppcheckLibraryData::Function::Arg loadFunctionArg(QXmlStreamReader &xmlReader)
{ {
CppcheckLibraryData::Function::Arg arg; CppcheckLibraryData::Function::Arg arg;
@ -279,6 +301,10 @@ QString CppcheckLibraryData::open(QIODevice &file)
memoryresource.append(loadMemoryResource(xmlReader)); memoryresource.append(loadMemoryResource(xmlReader));
else if (elementName == "podtype") else if (elementName == "podtype")
podtypes.append(loadPodType(xmlReader)); podtypes.append(loadPodType(xmlReader));
else if (elementName == "smart-pointer")
smartPointers.append(loadSmartPointer(xmlReader));
else if (elementName == "type-checks")
typeChecks.append(loadTypeChecks(xmlReader));
else else
unhandledElement(xmlReader); unhandledElement(xmlReader);
} catch (std::runtime_error &e) { } catch (std::runtime_error &e) {
@ -501,6 +527,24 @@ static void writeMemoryResource(QXmlStreamWriter &xmlWriter, const CppcheckLibra
xmlWriter.writeEndElement(); xmlWriter.writeEndElement();
} }
static void writeTypeChecks(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::TypeChecks &typeChecks)
{
QPair<QString, QString> check;
xmlWriter.writeStartElement("type-checks");
if (!typeChecks.isEmpty()) {
xmlWriter.writeStartElement("unusedvar");
}
foreach (check, typeChecks) {
xmlWriter.writeStartElement(check.first);
xmlWriter.writeCharacters(check.second);
xmlWriter.writeEndElement();
}
if (!typeChecks.isEmpty()) {
xmlWriter.writeEndElement();
}
xmlWriter.writeEndElement();
}
QString CppcheckLibraryData::toString() const QString CppcheckLibraryData::toString() const
{ {
QString outputString; QString outputString;
@ -548,6 +592,16 @@ QString CppcheckLibraryData::toString() const
xmlWriter.writeEndElement(); xmlWriter.writeEndElement();
} }
foreach (const TypeChecks check, typeChecks) {
writeTypeChecks(xmlWriter, check);
}
foreach (const QString &smartPtr, smartPointers) {
xmlWriter.writeStartElement("smart-pointer");
xmlWriter.writeAttribute("class-name", smartPtr);
xmlWriter.writeEndElement();
}
xmlWriter.writeEndElement(); xmlWriter.writeEndElement();
return outputString; return outputString;

View File

@ -171,6 +171,8 @@ public:
QString sign; QString sign;
}; };
using TypeChecks = QList<QPair<QString, QString>>;
void clear() { void clear() {
containers.clear(); containers.clear();
defines.clear(); defines.clear();
@ -178,9 +180,10 @@ public:
functions.clear(); functions.clear();
memoryresource.clear(); memoryresource.clear();
podtypes.clear(); podtypes.clear();
smartPointers.clear();
typeChecks.clear();
} }
void swap(CppcheckLibraryData &other) { void swap(CppcheckLibraryData &other) {
containers.swap(other.containers); containers.swap(other.containers);
defines.swap(other.defines); defines.swap(other.defines);
@ -188,6 +191,8 @@ public:
functions.swap(other.functions); functions.swap(other.functions);
memoryresource.swap(other.memoryresource); memoryresource.swap(other.memoryresource);
podtypes.swap(other.podtypes); podtypes.swap(other.podtypes);
smartPointers.swap(other.smartPointers);
typeChecks.swap(other.typeChecks);
} }
QString open(QIODevice &file); QString open(QIODevice &file);
@ -198,7 +203,9 @@ public:
QList<struct Function> functions; QList<struct Function> functions;
QList<struct MemoryResource> memoryresource; QList<struct MemoryResource> memoryresource;
QList<struct PodType> podtypes; QList<struct PodType> podtypes;
QList<TypeChecks> typeChecks;
QStringList undefines; QStringList undefines;
QStringList smartPointers;
}; };
#endif // CPPCHECKLIBRARYDATA_H #endif // CPPCHECKLIBRARYDATA_H

View File

@ -0,0 +1,23 @@
TEMPLATE = app
TARGET = test-cppchecklibrarydata
DEPENDPATH += .
INCLUDEPATH += .
OBJECTS_DIR = ../build
MOC_DIR = ../build
QT -= gui
QT += core
CONFIG += console
include(../common.pri)
DEFINES += SRCDIR=\\\"$$PWD\\\"
SOURCES += testcppchecklibrarydata.cpp \
../../cppchecklibrarydata.cpp
HEADERS += testcppchecklibrarydata.h \
../../cppchecklibrarydata.h \
RESOURCES += \
resources.qrc

View File

@ -0,0 +1,4 @@
<?xml version="1.0"?>
<def format="2">
<podtype sign="u" size="4" stdtype="uint32_t"/>
</def>

View File

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<def format="2">
<podtype name="bool"/>
<podtype name="ulong" sign="u" size="4" stdtype="uint32_t"/>
</def>

View File

@ -0,0 +1,6 @@
<?xml version="1.0"?>
<def format="2">
<smart-pointer class-name="wxObjectDataPtr"/>
<smart-pointer class-name="wxScopedArray"/>
<smart-pointer class-name="wxScopedPtr"/>
</def>

View File

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<def format="2">
<type-checks>
<unusedvar>
<suppress>std::insert_iterator</suppress>
<check>std::pair</check>
</unusedvar>
</type-checks>
<type-checks/>
<type-checks>
<unusedvar>
<check>std::tuple</check>
</unusedvar>
</type-checks>
</def>

View File

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<def format="2">
<!-- error: typo which should trigger unhandled element handler -->
<podtyp sign="u" size="4" stdtype="uint32_t"/>
</def>

View File

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<def format="2">
<!-- error: redefinition of size attribute -->
<podtype name="ulong" sign="u" size="4" size="4"/>
</def>

View File

@ -0,0 +1,10 @@
<RCC>
<qresource prefix="/">
<file>files/xml_reader_error.cfg</file>
<file>files/mandatory_attribute_missing.cfg</file>
<file>files/unhandled_element.cfg</file>
<file>files/typechecks_valid.cfg</file>
<file>files/podtype_valid.cfg</file>
<file>files/smartptr_valid.cfg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,199 @@
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2021 Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "testcppchecklibrarydata.h"
const QString TestCppcheckLibraryData::TempCfgFile = "./tmp.cfg";
void TestCppcheckLibraryData::init()
{
result.clear();
libraryData.clear();
fileLibraryData.clear();
}
void TestCppcheckLibraryData::xmlReaderError()
{
loadCfgFile(":/files/xml_reader_error.cfg", fileLibraryData, result);
QCOMPARE(result.isNull(), false);
qDebug() << result;
}
void TestCppcheckLibraryData::unhandledElement()
{
loadCfgFile(":/files/unhandled_element.cfg", fileLibraryData, result);
QCOMPARE(result.isNull(), false);
qDebug() << result;
}
void TestCppcheckLibraryData::mandatoryAttributeMissing()
{
loadCfgFile(":/files/mandatory_attribute_missing.cfg", fileLibraryData, result);
QCOMPARE(result.isNull(), false);
qDebug() << result;
}
void TestCppcheckLibraryData::podtypeValid()
{
// Load library data from file
loadCfgFile(":/files/podtype_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.podtypes.size(), 2);
QCOMPARE(libraryData.podtypes[0].name, "bool");
QCOMPARE(libraryData.podtypes[0].stdtype.isEmpty(), true);
QCOMPARE(libraryData.podtypes[0].sign.isEmpty(), true);
QCOMPARE(libraryData.podtypes[0].size.isEmpty(), true);
QCOMPARE(libraryData.podtypes[1].name, "ulong");
QCOMPARE(libraryData.podtypes[1].stdtype, "uint32_t");
QCOMPARE(libraryData.podtypes[1].sign, "u");
QCOMPARE(libraryData.podtypes[1].size, "4");
// Save library data to file
saveCfgFile(TempCfgFile, libraryData);
fileLibraryData.clear();
QCOMPARE(fileLibraryData.podtypes.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.podtypes.size(), fileLibraryData.podtypes.size());
QCOMPARE(libraryData.podtypes.size(), 2);
for (int i=0; i < libraryData.podtypes.size(); i++) {
QCOMPARE(libraryData.podtypes[i].name, fileLibraryData.podtypes[i].name);
QCOMPARE(libraryData.podtypes[i].stdtype, fileLibraryData.podtypes[i].stdtype);
QCOMPARE(libraryData.podtypes[i].sign, fileLibraryData.podtypes[i].sign);
QCOMPARE(libraryData.podtypes[i].size, fileLibraryData.podtypes[i].size);
}
}
void TestCppcheckLibraryData::typechecksValid()
{
// Load library data from file
loadCfgFile(":/files/typechecks_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.typeChecks.size(), 3);
CppcheckLibraryData::TypeChecks check = libraryData.typeChecks[0];
QCOMPARE(check.size(), 2);
QCOMPARE(check[0].first, "suppress");
QCOMPARE(check[0].second, "std::insert_iterator");
QCOMPARE(check[1].first, "check");
QCOMPARE(check[1].second, "std::pair");
check = libraryData.typeChecks[1];
QCOMPARE(check.isEmpty(), true);
check = libraryData.typeChecks[2];
QCOMPARE(check.size(), 1);
QCOMPARE(check[0].first, "check");
QCOMPARE(check[0].second, "std::tuple");
// Save library data to file
saveCfgFile(TempCfgFile, libraryData);
fileLibraryData.clear();
QCOMPARE(fileLibraryData.typeChecks.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.typeChecks.size(), fileLibraryData.typeChecks.size());
QCOMPARE(libraryData.typeChecks.size(), 3);
for (int idx=0; idx < libraryData.typeChecks.size(); idx++) {
CppcheckLibraryData::TypeChecks lhs = libraryData.typeChecks[idx];
CppcheckLibraryData::TypeChecks rhs = fileLibraryData.typeChecks[idx];
QCOMPARE(lhs.size(), lhs.size());
for (int num=0; num < lhs.size(); num++) {
QCOMPARE(lhs[num].first, rhs[num].first);
QCOMPARE(lhs[num].second, rhs[num].second);
}
}
}
void TestCppcheckLibraryData::smartPointerValid()
{
// Load library data from file
loadCfgFile(":/files/smartptr_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.smartPointers.size(), 3);
QCOMPARE(libraryData.smartPointers[0], "wxObjectDataPtr");
QCOMPARE(libraryData.smartPointers[1], "wxScopedArray");
QCOMPARE(libraryData.smartPointers[2], "wxScopedPtr");
// Save library data to file
saveCfgFile(TempCfgFile, libraryData);
fileLibraryData.clear();
QCOMPARE(fileLibraryData.smartPointers.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.smartPointers.size(), fileLibraryData.smartPointers.size());
QCOMPARE(libraryData.smartPointers.size(), 3);
for (int i=0; i < libraryData.smartPointers.size(); i++) {
QCOMPARE(libraryData.smartPointers[i], fileLibraryData.smartPointers[i]);
}
}
void TestCppcheckLibraryData::loadCfgFile(QString filename, CppcheckLibraryData &data, QString &result, bool removeFile)
{
QFile file(filename);
QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
result = data.open(file);
file.close();
if (removeFile) {
file.remove();
}
}
void TestCppcheckLibraryData::saveCfgFile(QString filename, CppcheckLibraryData &data)
{
QFile file(filename);
QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text));
QTextStream textStream(&file);
textStream << data.toString() << '\n';
file.close();
}
QTEST_MAIN(TestCppcheckLibraryData)

View File

@ -0,0 +1,45 @@
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2021 Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QtTest/QtTest>
#include "cppchecklibrarydata.h"
class TestCppcheckLibraryData: public QObject {
Q_OBJECT
private slots:
void init();
void xmlReaderError();
void unhandledElement();
void mandatoryAttributeMissing();
void podtypeValid();
void typechecksValid();
void smartPointerValid();
private:
void loadCfgFile(QString filename, CppcheckLibraryData &data, QString &result, bool removeFile = false);
void saveCfgFile(QString filename, CppcheckLibraryData &data);
CppcheckLibraryData libraryData;
CppcheckLibraryData fileLibraryData;
QString result;
static const QString TempCfgFile;
};