This commit is contained in:
parent
ec2a2ad41f
commit
46b9d4ec61
|
@ -112,6 +112,11 @@ bool CppCheckExecutor::parseFromArgs(Settings &settings, int argc, const char* c
|
|||
return false;
|
||||
}
|
||||
|
||||
// Libraries must be loaded before FileLister is executed to ensure markup files will be
|
||||
// listed properly.
|
||||
if (!loadLibraries(settings))
|
||||
return false;
|
||||
|
||||
// Check that all include paths exist
|
||||
{
|
||||
for (std::list<std::string>::iterator iter = settings.includePaths.begin();
|
||||
|
@ -256,9 +261,6 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck)
|
|||
{
|
||||
Settings& settings = cppcheck.settings();
|
||||
|
||||
if (!loadLibraries(settings))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (settings.reportProgress)
|
||||
mLatestProgressOutputTime = std::time(nullptr);
|
||||
|
||||
|
|
|
@ -72,36 +72,38 @@ static std::string stripTemplateParameters(const std::string& funcName) {
|
|||
void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char FileName[], const Settings *settings)
|
||||
{
|
||||
const bool doMarkup = settings->library.markupFile(FileName);
|
||||
const SymbolDatabase* symbolDatabase = tokenizer.getSymbolDatabase();
|
||||
|
||||
// Function declarations..
|
||||
for (const Scope* scope : symbolDatabase->functionScopes) {
|
||||
const Function* func = scope->function;
|
||||
if (!func || !func->token || scope->bodyStart->fileIndex() != 0)
|
||||
continue;
|
||||
if (!doMarkup) {
|
||||
const SymbolDatabase* symbolDatabase = tokenizer.getSymbolDatabase();
|
||||
for (const Scope* scope : symbolDatabase->functionScopes) {
|
||||
const Function* func = scope->function;
|
||||
if (!func || !func->token || scope->bodyStart->fileIndex() != 0)
|
||||
continue;
|
||||
|
||||
// Don't warn about functions that are marked by __attribute__((constructor)) or __attribute__((destructor))
|
||||
if (func->isAttributeConstructor() || func->isAttributeDestructor() || func->type != Function::eFunction || func->isOperator())
|
||||
continue;
|
||||
// Don't warn about functions that are marked by __attribute__((constructor)) or __attribute__((destructor))
|
||||
if (func->isAttributeConstructor() || func->isAttributeDestructor() || func->type != Function::eFunction || func->isOperator())
|
||||
continue;
|
||||
|
||||
if (func->isExtern())
|
||||
continue;
|
||||
if (func->isExtern())
|
||||
continue;
|
||||
|
||||
mFunctionDecl.emplace_back(func);
|
||||
mFunctionDecl.emplace_back(func);
|
||||
|
||||
FunctionUsage &usage = mFunctions[stripTemplateParameters(func->name())];
|
||||
FunctionUsage &usage = mFunctions[stripTemplateParameters(func->name())];
|
||||
|
||||
if (!usage.lineNumber)
|
||||
usage.lineNumber = func->token->linenr();
|
||||
if (!usage.lineNumber)
|
||||
usage.lineNumber = func->token->linenr();
|
||||
|
||||
// No filename set yet..
|
||||
if (usage.filename.empty()) {
|
||||
usage.filename = tokenizer.list.getSourceFilePath();
|
||||
}
|
||||
// Multiple files => filename = "+"
|
||||
else if (usage.filename != tokenizer.list.getSourceFilePath()) {
|
||||
//func.filename = "+";
|
||||
usage.usedOtherFile |= usage.usedSameFile;
|
||||
// No filename set yet..
|
||||
if (usage.filename.empty()) {
|
||||
usage.filename = tokenizer.list.getSourceFilePath();
|
||||
}
|
||||
// Multiple files => filename = "+"
|
||||
else if (usage.filename != tokenizer.list.getSourceFilePath()) {
|
||||
//func.filename = "+";
|
||||
usage.usedOtherFile |= usage.usedSameFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,7 +213,9 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char Fi
|
|||
|
||||
const Token *funcname = nullptr;
|
||||
|
||||
if ((lambdaEndToken || tok->scope()->isExecutable()) && Token::Match(tok, "%name% (")) {
|
||||
if (doMarkup)
|
||||
funcname = Token::Match(tok, "%name% (") ? tok : nullptr;
|
||||
else if ((lambdaEndToken || tok->scope()->isExecutable()) && Token::Match(tok, "%name% (")) {
|
||||
funcname = tok;
|
||||
} else if ((lambdaEndToken || tok->scope()->isExecutable()) && Token::Match(tok, "%name% <") && Token::simpleMatch(tok->linkAt(1), "> (")) {
|
||||
funcname = tok;
|
||||
|
|
|
@ -698,6 +698,13 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
|
|||
return mExitCode;
|
||||
}
|
||||
|
||||
if (mSettings.library.markupFile(filename)) {
|
||||
Tokenizer tokenizer(&mSettings, this, &preprocessor);
|
||||
tokenizer.createTokens(std::move(tokens1));
|
||||
checkUnusedFunctions.getFileInfo(&tokenizer, &mSettings);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (!preprocessor.loadFiles(tokens1, files))
|
||||
return mExitCode;
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Downloaded from here:
|
||||
https://github.com/HamedMasafi/QML-Samples
|
|
@ -0,0 +1,11 @@
|
|||
import QtQuick 2.0
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQml.Models 2.12
|
||||
|
||||
QtObject {
|
||||
property string title
|
||||
property string role
|
||||
property bool fillWidth: false
|
||||
property int size: -1
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import QtQuick 2.0
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQml.Models 2.12
|
||||
|
||||
ItemDelegate {
|
||||
height: 40
|
||||
width: parent.width
|
||||
property bool isHeader: false
|
||||
RowLayout {
|
||||
property var _d: model
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 9
|
||||
|
||||
Repeater {
|
||||
model: root.columns
|
||||
Label {
|
||||
text: parent.parent.isHeader ? modelData.title : parent._d[modelData.role]
|
||||
Layout.fillWidth: modelData.fillWidth
|
||||
Layout.preferredWidth: modelData.size !== '*'
|
||||
? modelData.size : 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
QT += quick
|
||||
|
||||
CONFIG += c++11
|
||||
|
||||
# You can make your code fail to compile if it uses deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
samplemodel.cpp
|
||||
|
||||
RESOURCES += qml.qrc
|
||||
|
||||
# Additional import path used to resolve QML modules in Qt Creator's code model
|
||||
QML_IMPORT_PATH =
|
||||
|
||||
# Additional import path used to resolve QML modules just for Qt Quick Designer
|
||||
QML_DESIGNER_IMPORT_PATH =
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
|
||||
HEADERS += \
|
||||
samplemodel.h
|
|
@ -0,0 +1,30 @@
|
|||
import QtQuick 2.0
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQml.Models 2.12
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property alias model: tableView.model
|
||||
default property list<TableColumn> columns
|
||||
|
||||
TableRow {
|
||||
id: header
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
background: null
|
||||
isHeader: true
|
||||
height: 60
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: tableView
|
||||
clip: true
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: header.height
|
||||
delegate: TableRow {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#include <QtGui/QGuiApplication>
|
||||
#include <QtQml/QQmlApplicationEngine>
|
||||
#include "samplemodel.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#endif
|
||||
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
qmlRegisterType<SampleModel>("Test", 1, 0, "SampleModel");
|
||||
|
||||
const QUrl url(QStringLiteral("qrc:/main.qml"));
|
||||
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
|
||||
&app, [url](QObject *obj, const QUrl &objUrl) {
|
||||
if (!obj && url == objUrl)
|
||||
QCoreApplication::exit(-1);
|
||||
}, Qt::QueuedConnection);
|
||||
engine.load(url);
|
||||
|
||||
return app.exec();
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
import QtQuick 2.12
|
||||
import QtQuick.Window 2.12
|
||||
import Test 1.0
|
||||
import '.' as Here
|
||||
|
||||
Window {
|
||||
width: 640
|
||||
height: 480
|
||||
visible: true
|
||||
title: qsTr("Hello World")
|
||||
|
||||
Component.onCompleted: sampleModel.fillSampleData(50)
|
||||
SampleModel {
|
||||
id: sampleModel
|
||||
}
|
||||
|
||||
Here.TableView {
|
||||
anchors.fill: parent
|
||||
model: sampleModel
|
||||
|
||||
TableColumn {
|
||||
title: qsTr("Id")
|
||||
role: 'id'
|
||||
size: 30
|
||||
}
|
||||
TableColumn {
|
||||
title: qsTr("Name")
|
||||
role: 'name'
|
||||
fillWidth: true
|
||||
}
|
||||
TableColumn {
|
||||
title: qsTr("Grade")
|
||||
role: 'grade'
|
||||
size: 50
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>main.qml</file>
|
||||
<file>TableView.qml</file>
|
||||
<file>TableRow.qml</file>
|
||||
<file>TableColumn.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -0,0 +1,68 @@
|
|||
#include "samplemodel.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QRandomGenerator>
|
||||
|
||||
SampleModel::SampleModel(QObject *parent) : QAbstractListModel(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int SampleModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return _data.size();
|
||||
}
|
||||
|
||||
QVariant SampleModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
if (index.row() < 0 || index.row() > _data.count() - 1)
|
||||
return QVariant();
|
||||
|
||||
auto row = _data.at(index.row());
|
||||
|
||||
switch (role) {
|
||||
case IdRole:
|
||||
return index.row();
|
||||
|
||||
case NameRole:
|
||||
return row.first;
|
||||
|
||||
case GradeRole:
|
||||
return row.second;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> SampleModel::roleNames() const
|
||||
{
|
||||
return {
|
||||
{IdRole, "id"},
|
||||
{NameRole, "name"},
|
||||
{GradeRole, "grade"}
|
||||
};
|
||||
}
|
||||
|
||||
void SampleModel::fillSampleData(int size)
|
||||
{
|
||||
QString abs = "qwertyuiopasdfghjklzxcvbnm";
|
||||
QRandomGenerator r;
|
||||
for (auto i = 0; i < size; i++) {
|
||||
Row row;
|
||||
auto nameLen = r.bounded(3, 8);
|
||||
QString name;
|
||||
for (int c = 0; c < nameLen; ++c)
|
||||
name.append(abs.at(r.bounded(0, abs.size() - 1)));
|
||||
|
||||
row.first = name;
|
||||
row.second = r.bounded(0, 20);
|
||||
_data.append(row);
|
||||
}
|
||||
|
||||
qDebug() << _data.size() << "item(s) added as sample data";
|
||||
beginInsertRows(QModelIndex(), 0, _data.size() - 1);
|
||||
endInsertRows();
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef SAMPLEMODEL_H
|
||||
#define SAMPLEMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
class SampleModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
typedef QPair<QString, int> Row;
|
||||
QList<Row> _data;
|
||||
|
||||
public:
|
||||
enum Role {
|
||||
IdRole = Qt::UserRole + 1,
|
||||
NameRole,
|
||||
GradeRole
|
||||
};
|
||||
|
||||
SampleModel(QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
QHash<int, QByteArray> roleNames() const;
|
||||
|
||||
public slots:
|
||||
void fillSampleData(int size);
|
||||
};
|
||||
|
||||
#endif // SAMPLEMODEL_H
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
# python3 -m pytest test-qml.py
|
||||
|
||||
import os
|
||||
from testutils import cppcheck
|
||||
|
||||
PROJECT_DIR = 'QML-Samples-TableView'
|
||||
|
||||
def test_unused_functions():
|
||||
ret, stdout, stderr = cppcheck(['--library=qt', '--enable=unusedFunction', PROJECT_DIR])
|
||||
# there are unused functions. But fillSampleData is not unused because that is referenced from main.qml
|
||||
assert '[unusedFunction]' in stderr
|
||||
assert 'fillSampleData' not in stderr
|
||||
|
|
@ -189,7 +189,8 @@ private:
|
|||
"file_1.cp1", "file_2.cpp", "file_3.cp1", "file_4.cpp"
|
||||
};
|
||||
|
||||
check(2, 4, 4,
|
||||
// the checks are not executed on the markup files => expected result is 2
|
||||
check(2, 4, 2,
|
||||
"int main()\n"
|
||||
"{\n"
|
||||
" char *a = malloc(10);\n"
|
||||
|
|
|
@ -193,7 +193,8 @@ private:
|
|||
"file_1.cp1", "file_2.cpp", "file_3.cp1", "file_4.cpp"
|
||||
};
|
||||
|
||||
check(4, 4,
|
||||
// checks are not executed on markup files => expected result is 2
|
||||
check(4, 2,
|
||||
"int main()\n"
|
||||
"{\n"
|
||||
" char *a = malloc(10);\n"
|
||||
|
|
|
@ -187,7 +187,8 @@ private:
|
|||
"file_1.cp1", "file_2.cpp", "file_3.cp1", "file_4.cpp"
|
||||
};
|
||||
|
||||
check(2, 4, 4,
|
||||
// checks are not executed on markup files => expected result is 2
|
||||
check(2, 4, 2,
|
||||
"int main()\n"
|
||||
"{\n"
|
||||
" char *a = malloc(10);\n"
|
||||
|
|
Loading…
Reference in New Issue