summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmake/QtTargetHelpers.cmake2
-rw-r--r--src/tools/tracepointgen/parser.cpp325
-rw-r--r--src/tools/tracepointgen/parser.h11
-rw-r--r--src/tools/tracepointgen/tracepointgen.cpp5
4 files changed, 335 insertions, 8 deletions
diff --git a/cmake/QtTargetHelpers.cmake b/cmake/QtTargetHelpers.cmake
index a98e940885..80dfff7cc1 100644
--- a/cmake/QtTargetHelpers.cmake
+++ b/cmake/QtTargetHelpers.cmake
@@ -800,7 +800,7 @@ function(qt_internal_generate_tracepoints name provider)
endif()
add_custom_command(OUTPUT "${tracepoints_path}"
- COMMAND ${tracepointgen} ${provider_name} "${tracepoints_path}" ${absolute_file_paths}
+ COMMAND ${tracepointgen} ${provider_name} "${tracepoints_path}" "I$<JOIN:$<TARGET_PROPERTY:${name},INCLUDE_DIRECTORIES>,;>" ${absolute_file_paths}
DEPENDS ${absolute_file_paths}
VERBATIM)
add_custom_target(${name}_${provider_name}_tracepoints_file DEPENDS "${tracepoints_path}")
diff --git a/src/tools/tracepointgen/parser.cpp b/src/tools/tracepointgen/parser.cpp
index 940e609b44..bc5d4f3f2f 100644
--- a/src/tools/tracepointgen/parser.cpp
+++ b/src/tools/tracepointgen/parser.cpp
@@ -5,7 +5,7 @@
#include "parser.h"
#include <qtextstream.h>
#include <qregularexpression.h>
-
+#include <qfileinfo.h>
static void removeOffsetRange(qsizetype begin, qsizetype end, QList<LineNumber> &offsets)
{
@@ -78,6 +78,30 @@ static void simplifyData(QString &data, QList<LineNumber> &offsets)
}
}
+static void simplifyData(QString &data)
+{
+ qsizetype offset = data.indexOf(QStringLiteral("//"));
+ while (offset >= 0) {
+ qsizetype endOfLine = data.indexOf(QLatin1Char('\n'), offset);
+ if (endOfLine == -1)
+ endOfLine = data.length();
+ data.remove(offset, endOfLine - offset);
+ offset = data.indexOf(QStringLiteral("//"), offset);
+ }
+ offset = data.indexOf(QStringLiteral("/*"));
+ while (offset >= 0) {
+ qsizetype endOfComment = data.indexOf(QStringLiteral("*/"), offset);
+ if (endOfComment == -1)
+ break;
+ data.remove(offset, endOfComment - offset + 2);
+ offset = data.indexOf(QStringLiteral("/*"), offset);
+ }
+ offset = 0;
+ qsizetype end = 0;
+ while (findSpaceRange(data, offset, end))
+ data.remove(offset, end - offset);
+}
+
static QString preprocessMetadata(const QString &in)
{
DEBUGPRINTF(printf("in: %s\n", qPrintable(in)));
@@ -210,7 +234,135 @@ void Parser::parsePrefix(const QString &data, qsizetype offset)
m_prefixes.push_back(preprocessMetadata(prefix));
}
-void Parser::parseMetadata(const QString &data, qsizetype offset)
+QStringList Parser::findEnumValues(const QString &name, const QStringList &includes)
+{
+ QStringList split = name.split(QStringLiteral("::"));
+ QString enumName = split.last();
+ DEBUGPRINTF(printf("searching for %s\n", qPrintable(name)));
+ QStringList ret;
+ for (auto filename : includes) {
+ QFile input(filename);
+ if (!input.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ DEBUGPRINTF(printf("Cannot open '%s' for reading: %s\n",
+ qPrintable(filename), qPrintable(input.errorString())));
+ return ret;
+ }
+ QString data;
+ QTextStream stream(&input);
+ while (!stream.atEnd()) {
+ QString line = stream.readLine().trimmed();
+ data += line + QLatin1Char('\n');
+ }
+ simplifyData(data);
+
+ int pos = 0;
+ bool valid = true;
+ for (int i = 0; i < split.size() - 1; i++) {
+ QRegularExpression macro(QStringLiteral("(struct|class|namespace) +([A-Za-z0-9_]*)? +([A-Za-z0-9]*;?)"));
+ QRegularExpressionMatchIterator m = macro.globalMatch(data);
+ bool found = false;
+ while (m.hasNext() && !found) {
+ QRegularExpressionMatch match = m.next();
+ QString n = match.captured(2);
+ if (!n.endsWith(QLatin1Char(';')) && n == split[i] && match.capturedStart(2) > pos) {
+ pos = match.capturedStart(2);
+ found = true;
+ break;
+ }
+ if (match.hasCaptured(3)) {
+ n = match.captured(3);
+ if (!n.endsWith(QLatin1Char(';')) && n == split[i] && match.capturedStart(3) > pos) {
+ pos = match.capturedStart(3);
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ valid = false;
+ break;
+ }
+ }
+
+ if (valid) {
+ QRegularExpression macro(QStringLiteral("enum +([A-Za-z0-9_]*)"));
+ QRegularExpressionMatchIterator m = macro.globalMatch(data);
+ while (m.hasNext()) {
+ QRegularExpressionMatch match = m.next();
+
+ if (match.capturedStart() < pos)
+ continue;
+
+ QString n = match.captured(1);
+
+ if (n == enumName) {
+ DEBUGPRINTF(printf("Found enum: %s\n", qPrintable(n)));
+ int begin = data.indexOf(QLatin1Char('{'), match.capturedEnd());
+ int end = data.indexOf(QLatin1Char('}'), begin);
+ QString block = data.mid(begin + 1, end - begin - 1);
+ QStringList enums = block.split(QLatin1Char('\n'));
+ for (auto e : enums) {
+ const auto trimmed = e.trimmed();
+ if (!trimmed.isEmpty() && !trimmed.startsWith(QLatin1Char('#')))
+ ret << trimmed;
+ }
+
+ break;
+ }
+ }
+ return ret;
+ }
+ }
+ return ret;
+}
+
+struct EnumNameValue
+{
+ QString name;
+ QString valueStr;
+ int value;
+};
+
+static QList<EnumNameValue> enumsToValues(const QStringList &values)
+{
+ int cur = 0;
+ QList<EnumNameValue> ret;
+ for (auto value : values) {
+ EnumNameValue r;
+ if (value.contains(QLatin1Char('='))) {
+ size_t offset = value.indexOf(QLatin1Char('='));
+ r.name = value.left(offset).trimmed();
+ QString val = value.right(value.length() - offset - 1).trimmed();
+ if (val.endsWith(QLatin1Char(',')))
+ val = val.left(val.length() - 1);
+ bool valid = false;
+ int integer = val.toInt(&valid);
+ if (!valid)
+ integer = val.toInt(&valid, 16);
+ if (valid) {
+ cur = r.value = integer;
+ ret << r;
+ } else {
+ auto iter = std::find_if(ret.begin(), ret.end(), [&val](const EnumNameValue &elem){
+ return elem.name == val;
+ });
+ if (iter != ret.end()) {
+ cur = r.value = iter->value;
+ ret << r;
+ } else {
+ DEBUGPRINTF(printf("Invalid value: %s %s\n", qPrintable(r.name), qPrintable(value)));
+ }
+ }
+ } else {
+ r.name = value;
+ r.value = cur++;
+ ret << r;
+ }
+ }
+ return ret;
+}
+
+void Parser::parseMetadata(const QString &data, qsizetype offset, const QStringList &includes)
{
qsizetype beginOfProvider = data.indexOf(QLatin1Char('('), offset);
qsizetype endOfProvider = data.indexOf(QLatin1Char(','), beginOfProvider);
@@ -224,8 +376,152 @@ void Parser::parseMetadata(const QString &data, qsizetype offset)
DEBUGPRINTF(printf("tracepointgen: metadata: %s", qPrintable(metadata)));
- if (!m_metadata.contains(metadata))
- m_metadata.push_back(preprocessMetadata(metadata));
+ QString preprocessed = preprocessMetadata(metadata);
+
+ DEBUGPRINTF2(printf("preprocessed %s\n", qPrintable(preprocessed)));
+
+ QRegularExpression macro(QStringLiteral("([A-Z]*) ?{ ?([A-Za-z0-9=_,. ]*) ?} ?([A-Za-z0-9_:]*) ?;"));
+ QRegularExpressionMatchIterator i = macro.globalMatch(preprocessed);
+ qsizetype prev = 0;
+ while (i.hasNext()) {
+ QRegularExpressionMatch match = i.next();
+ const QString values = match.captured(2).trimmed();
+ int cur = match.capturedStart();
+ if (cur > prev)
+ m_metadata.append(preprocessed.mid(prev, cur - prev));
+
+ prev = match.capturedEnd() + 1;
+ DEBUGPRINTF2(printf("values: %s\n", qPrintable(values)));
+ if (values.isEmpty() || values.startsWith(QStringLiteral("AUTO"))) {
+
+ QStringList ranges;
+ if (values.contains(QStringLiteral("RANGE"))) {
+ QRegularExpression rangeMacro(QStringLiteral("RANGE +([A-Za-z0-9_]*) +... +([A-Za-z0-9_]*)"));
+ QRegularExpressionMatchIterator r = rangeMacro.globalMatch(values);
+ while (r.hasNext()) {
+ QRegularExpressionMatch rm = r.next();
+ ranges << rm.captured(1);
+ ranges << rm.captured(2);
+ DEBUGPRINTF2(printf("range: %s ... %s\n", qPrintable(rm.captured(1)), qPrintable(rm.captured(2))));
+ }
+ }
+
+ const auto enumOrFlag = match.captured(1);
+ const auto name = match.captured(3);
+ const bool flags = enumOrFlag == QStringLiteral("FLAGS");
+
+ QStringList values = findEnumValues(name, includes);
+ if (values.isEmpty()) {
+ if (flags && name.endsWith(QLatin1Char('s')))
+ values = findEnumValues(name.left(name.length() - 1), includes);
+ if (values.isEmpty()) {
+ DEBUGPRINTF(printf("Unable to find values for %s\n", qPrintable(name)));
+ }
+ }
+ if (!values.isEmpty()) {
+ auto moreValues = enumsToValues(values);
+ if (ranges.size()) {
+ for (int i = 0; i < ranges.size() / 2; i++) {
+ for (auto &v : moreValues) {
+ if (v.name == ranges[2 * i]) {
+ QString rangeEnd = ranges[2 * i + 1];
+ auto iter = std::find_if(moreValues.begin(), moreValues.end(), [&rangeEnd](const EnumNameValue &elem){
+ return elem.name == rangeEnd;
+ });
+ if (iter != moreValues.end())
+ v.valueStr = QStringLiteral("RANGE(%1, %2 ... %3)").arg(v.name).arg(v.value).arg(iter->value);
+ }
+ }
+ }
+ }
+ std::sort(moreValues.begin(), moreValues.end(), [](const EnumNameValue &a, const EnumNameValue &b) {
+ return a.value < b.value;
+ });
+ values.clear();
+ int prevValue = moreValues.first().value;
+ for (auto v : moreValues) {
+ QString a;
+ if (v.valueStr.isNull()) {
+ if (v.value == prevValue + 1 && !flags)
+ a = v.name;
+ else
+ a = QStringLiteral("%1 = %2").arg(v.name).arg(v.value);
+ prevValue = v.value;
+ } else {
+ a = v.valueStr;
+ }
+ values << a;
+ }
+
+ metadata = QStringLiteral("%1 {\n %2 \n} %3;").arg(enumOrFlag).arg(values.join(QStringLiteral(",\n"))).arg(name);
+ if (!m_metadata.contains(metadata))
+ m_metadata.append(metadata);
+ }
+ } else {
+ if (!m_metadata.contains(match.captured()))
+ m_metadata.append(match.captured());
+ }
+ }
+ if (prev < preprocessed.length())
+ m_metadata.append(preprocessed.mid(prev, preprocessed.length() - prev));
+}
+
+QString Parser::resolveInclude(const QString &filename)
+{
+ QFileInfo info(filename);
+ if (info.exists())
+ return info.absoluteFilePath();
+ for (const QString &sp : std::as_const(m_includeDirs)) {
+ info = QFileInfo(sp + QLatin1Char('/') + filename);
+ if (info.exists())
+ return info.absoluteFilePath();
+ }
+ return {};
+}
+
+void Parser::addIncludesRecursive(const QString &filename, QList<QString> &includes)
+{
+ QFileInfo info(filename);
+ DEBUGPRINTF(printf("check include: %s\n", qPrintable(filename)));
+ QFile input(filename);
+ if (!input.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ DEBUGPRINTF(printf("Cannot open '%s' for reading: %s\n",
+ qPrintable(filename), qPrintable(input.errorString())));
+ return;
+ }
+ QString data;
+ QTextStream stream(&input);
+ while (!stream.atEnd()) {
+ QString line = stream.readLine().trimmed();
+ data += line + QLatin1Char(QLatin1Char('\n'));
+ }
+
+ QRegularExpression includeMacro(QStringLiteral("#include [\"<]([A-Za-z0-9_./]*.h)[\">]"));
+ QRegularExpressionMatchIterator i = includeMacro.globalMatch(data);
+ while (i.hasNext()) {
+ QRegularExpressionMatch match = i.next();
+ QString filename = match.captured(1);
+
+ QString rinc = filename;
+ if (filename.startsWith(QStringLiteral("../"))) {
+ QFileInfo info2(info.absolutePath() + QLatin1Char('/') + filename);
+ if (!info2.exists()) {
+ DEBUGPRINTF(printf("unable to find %s\n", qPrintable(filename)));
+ continue;
+ }
+ rinc = info2.absoluteFilePath();
+ filename = info2.fileName();
+ }
+
+ // only search possible qt headers
+ if (filename.startsWith(QLatin1Char('q'), Qt::CaseInsensitive)) {
+ QString resolved = resolveInclude(rinc);
+ if (!resolved.isEmpty() && !includes.contains(resolved)) {
+ includes.push_back(resolved);
+ addIncludesRecursive(resolved, includes);
+ }
+ }
+ }
}
void Parser::parse(QIODevice &input, const QString &name)
@@ -243,8 +539,25 @@ void Parser::parse(QIODevice &input, const QString &name)
simplifyData(data, m_offsets);
+ QStringList includes;
+
+ QRegularExpression includeMacro(QStringLiteral("#include [\"<]([A-Za-z0-9_./]*.h)[\">]"));
+ QRegularExpressionMatchIterator i = includeMacro.globalMatch(data);
+ while (i.hasNext()) {
+ QRegularExpressionMatch match = i.next();
+ const QString filename = match.captured(1);
+ // only search possible qt headers
+ if (filename.startsWith(QLatin1Char('q'), Qt::CaseInsensitive)) {
+ const QString resolved = resolveInclude(filename);
+ if (!resolved.isEmpty() && !includes.contains(resolved)) {
+ includes.push_back(resolved);
+ addIncludesRecursive(resolved, includes);
+ }
+ }
+ }
+
QRegularExpression traceMacro(QStringLiteral("Q_TRACE_([A-Z_]*)"));
- QRegularExpressionMatchIterator i = traceMacro.globalMatch(data);
+ i = traceMacro.globalMatch(data);
while (i.hasNext()) {
QRegularExpressionMatch match = i.next();
@@ -258,7 +571,7 @@ void Parser::parse(QIODevice &input, const QString &name)
else if (macroType == QStringLiteral("PREFIX"))
parsePrefix(data, match.capturedEnd());
else if (macroType == QStringLiteral("METADATA"))
- parseMetadata(data, match.capturedEnd());
+ parseMetadata(data, match.capturedEnd(), includes);
}
for (auto &func : m_functions) {
diff --git a/src/tools/tracepointgen/parser.h b/src/tools/tracepointgen/parser.h
index bc46a4d933..1978e3aa6a 100644
--- a/src/tools/tracepointgen/parser.h
+++ b/src/tools/tracepointgen/parser.h
@@ -42,11 +42,19 @@ struct Parser
}
+ void addIncludeDirs(const QStringList &list)
+ {
+ m_includeDirs.append(list);
+ }
+ QString resolveInclude(const QString &filename);
+ void addIncludesRecursive(const QString &filename, QStringList &includes);
+ QStringList findEnumValues(const QString &name, const QStringList &includes);
+
void parseParamReplace(const QString &data, qsizetype offset, const QString &name);
void parseInstrument(const QString &data, qsizetype offset);
void parsePoint(const QString &data, qsizetype offset);
void parsePrefix(const QString &data, qsizetype offset);
- void parseMetadata(const QString &data, qsizetype offset);
+ void parseMetadata(const QString &data, qsizetype offset, const QStringList &includes);
int lineNumber(qsizetype offset) const;
void parse(QIODevice &input, const QString &name);
@@ -62,6 +70,7 @@ struct Parser
QList<QString> m_prefixes;
QList<QString> m_metadata;
QList<LineNumber> m_offsets;
+ QList<QString> m_includeDirs;
QString m_provider;
};
diff --git a/src/tools/tracepointgen/tracepointgen.cpp b/src/tools/tracepointgen/tracepointgen.cpp
index cdf2f1fd2f..873b9cbfca 100644
--- a/src/tools/tracepointgen/tracepointgen.cpp
+++ b/src/tools/tracepointgen/tracepointgen.cpp
@@ -39,6 +39,11 @@ int main(int argc, char *argv[])
Parser parser(provider);
for (const QString &inputFile : inputFiles) {
+ if (inputFile.startsWith(QLatin1Char('I'))) {
+ QStringList includeDirs = inputFile.right(inputFile.length() - 1).split(QLatin1Char(';'));
+ parser.addIncludeDirs(includeDirs);
+ continue;
+ }
QFile in(inputFile);
if (!in.open(QIODevice::ReadOnly | QIODevice::Text)) {
panic("Cannot open '%s' for reading: %s\n",