54 qsizetype offset = data.indexOf(QStringLiteral(
"//"));
56 qsizetype endOfLine = data.indexOf(QLatin1Char(
'\n'), offset);
58 endOfLine = data.length();
59 removeOffsetRange(offset, endOfLine, offsets);
60 data.remove(offset, endOfLine - offset);
61 offset = data.indexOf(QStringLiteral(
"//"), offset);
63 offset = data.indexOf(QStringLiteral(
"/*"));
65 qsizetype endOfComment = data.indexOf(QStringLiteral(
"*/"), offset);
66 if (endOfComment == -1)
68 removeOffsetRange(offset, endOfComment + 2, offsets);
69 data.remove(offset, endOfComment - offset + 2);
70 offset = data.indexOf(QStringLiteral(
"/*"), offset);
74 data.replace(QLatin1Char(
'\n'), QLatin1Char(
' '));
75 while (findSpaceRange(data, offset, end)) {
76 removeOffsetRange(offset, end, offsets);
77 data.remove(offset, end - offset);
83 qsizetype offset = data.indexOf(QStringLiteral(
"//"));
85 qsizetype endOfLine = data.indexOf(QLatin1Char(
'\n'), offset);
87 endOfLine = data.length();
88 data.remove(offset, endOfLine - offset);
89 offset = data.indexOf(QStringLiteral(
"//"), offset);
91 offset = data.indexOf(QStringLiteral(
"/*"));
93 qsizetype endOfComment = data.indexOf(QStringLiteral(
"*/"), offset);
94 if (endOfComment == -1)
96 data.remove(offset, endOfComment - offset + 2);
97 offset = data.indexOf(QStringLiteral(
"/*"), offset);
101 while (findSpaceRange(data, offset, end))
102 data.remove(offset, end - offset);
145 qsizetype beginBrace = data.indexOf(QLatin1Char(
'('), offset);
146 qsizetype endBrace = data.indexOf(QLatin1Char(
')'), beginBrace);
147 QString params = data.mid(beginBrace + 1, endBrace - beginBrace -1);
148 int punc = params.indexOf(QLatin1Char(
','));
150 panic(
"Syntax error in Q_TRACE_PARAM_REPLACE at file %s, line %llu", qPrintable(name), lineNumber(offset));
151 rep.in = params.left(punc).simplified();
152 rep.out = params.right(params.length() - punc - 1).simplified();
153 if (rep.in.endsWith(QLatin1Char(
'*')) || rep.out.endsWith(QLatin1Char(
']')))
154 rep.out.append(QLatin1Char(
' '));
155 DEBUGPRINTF(printf(
"tracepointgen: replace: %s with %s\n", qPrintable(rep.in), qPrintable(rep.out)));
156 m_replaces.push_back(rep);
161 qsizetype beginOfProvider = data.indexOf(QLatin1Char(
'('), offset);
162 qsizetype endOfProvider = data.indexOf(QLatin1Char(
')'), beginOfProvider);
164 QString provider = data.mid(beginOfProvider + 1, endOfProvider - beginOfProvider - 1).simplified();
165 if (provider != m_provider)
168 qsizetype classMarker = data.indexOf(QStringLiteral(
"::"), endOfProvider);
169 qsizetype beginOfFunctionMarker = data.indexOf(QLatin1Char(
'{'), classMarker);
170 QString begin = data.mid(endOfProvider + 1, classMarker - endOfProvider - 1);
171 QString end = data.mid(classMarker + 2, beginOfFunctionMarker - classMarker - 2);
172 int spaceIndex = begin.lastIndexOf(QLatin1Char(
' '));
173 if (spaceIndex == -1)
174 func.className = begin;
176 func.className = begin.mid(spaceIndex + 1, begin.length() - spaceIndex - 1);
177 qsizetype braceIndex = end.indexOf(QLatin1Char(
'('));
178 spaceIndex = end.indexOf(QLatin1Char(
' '));
179 if (spaceIndex < braceIndex)
180 func.functionName = end.left(spaceIndex).simplified();
182 func.functionName = end.left(braceIndex).simplified();
184 qsizetype lastBraceIndex = end.lastIndexOf(QLatin1Char(
')'));
185 func.functionParameters = end.mid(braceIndex + 1, lastBraceIndex - braceIndex - 1).simplified();
187 DEBUGPRINTF(printf(
"tracepointgen: %s(%s)\n", qPrintable(func.functionName), qPrintable(func.functionParameters)));
189 m_functions.push_back(func);
192void Parser::
parsePoint(
const QString &data, qsizetype offset)
194 qsizetype beginOfProvider = data.indexOf(QLatin1Char(
'('), offset);
195 qsizetype endOfProvider = data.indexOf(QLatin1Char(
','), beginOfProvider);
197 QString provider = data.mid(beginOfProvider + 1, endOfProvider - beginOfProvider - 1).simplified();
198 if (provider != m_provider)
201 qsizetype endOfPoint = data.indexOf(QLatin1Char(
','), endOfProvider + 1);
202 qsizetype endOfPoint2 = data.indexOf(QLatin1Char(
')'), endOfProvider + 1);
204 if (endOfPoint == -1 || endOfPoint2 < endOfPoint) {
205 endOfPoint = endOfPoint2;
208 point.name = data.mid(endOfProvider + 1, endOfPoint - endOfProvider - 1).simplified();
210 int endOfParams = data.indexOf(QLatin1Char(
')'), endOfPoint);
211 point.parameters = data.mid(endOfPoint + 1, endOfParams - endOfPoint - 1).simplified();
214 DEBUGPRINTF(printf(
"tracepointgen: %s(%s)\n", qPrintable(point.name), qPrintable(point.parameters)));
216 m_points.push_back(point);
221 qsizetype beginOfProvider = data.indexOf(QLatin1Char(
'('), offset);
222 qsizetype endOfProvider = data.indexOf(QLatin1Char(
','), beginOfProvider);
224 QString provider = data.mid(beginOfProvider + 1, endOfProvider - beginOfProvider - 1).simplified();
225 if (provider != m_provider)
228 qsizetype endOfPoint = data.indexOf(QLatin1Char(
')'), endOfProvider + 1);
229 prefix = data.mid(endOfProvider + 1, endOfPoint - endOfProvider - 1).simplified();
231 DEBUGPRINTF(printf(
"tracepointgen: prefix: %s\n", qPrintable(prefix)));
233 if (!m_prefixes.contains(prefix))
234 m_prefixes.push_back(preprocessMetadata(prefix));
239 QStringList split = name.split(QStringLiteral(
"::"));
240 QString enumName = split.last();
241 DEBUGPRINTF(printf(
"searching for %s\n", qPrintable(name)));
243 for (
const QString &filename : includes) {
244 QFile input(filename);
245 if (!input.open(QIODevice::ReadOnly | QIODevice::Text)) {
246 DEBUGPRINTF(printf(
"Cannot open '%s' for reading: %s\n",
247 qPrintable(filename), qPrintable(input.errorString())));
251 QTextStream stream(&input);
252 while (!stream.atEnd()) {
253 QString line = stream.readLine().trimmed();
254 data += line + QLatin1Char(
'\n');
260 for (
int i = 0; i < split.size() - 1; i++) {
261 QRegularExpression macro(QStringLiteral(
"(struct|class|namespace) +([A-Za-z0-9_]*)? +([A-Za-z0-9]*;?)"));
262 QRegularExpressionMatchIterator m = macro.globalMatch(data);
264 while (m.hasNext() && !found) {
265 QRegularExpressionMatch match = m.next();
266 QString n = match.captured(2);
267 if (!n.endsWith(QLatin1Char(
';')) && n == split[i] && match.capturedStart(2) > pos) {
268 pos = match.capturedStart(2);
272 if (match.hasCaptured(3)) {
273 n = match.captured(3);
274 if (!n.endsWith(QLatin1Char(
';')) && n == split[i] && match.capturedStart(3) > pos) {
275 pos = match.capturedStart(3);
288 QRegularExpression macro(QStringLiteral(
"enum +([A-Za-z0-9_]*)"));
289 QRegularExpressionMatchIterator m = macro.globalMatch(data);
290 while (m.hasNext()) {
291 QRegularExpressionMatch match = m.next();
293 if (match.capturedStart() < pos)
296 QString n = match.captured(1);
299 DEBUGPRINTF(printf(
"Found enum: %s\n", qPrintable(n)));
300 int begin = data.indexOf(QLatin1Char(
'{'), match.capturedEnd());
301 int end = data.indexOf(QLatin1Char(
'}'), begin);
302 QString block = data.mid(begin + 1, end - begin - 1);
303 const QStringList enums = block.split(QLatin1Char(
'\n'));
304 for (
const auto &e : enums) {
305 const auto trimmed = e.trimmed();
306 if (!trimmed.isEmpty() && !trimmed.startsWith(QLatin1Char(
'#')))
329 for (
const QString &value : values) {
331 if (value.contains(QLatin1Char(
'='))) {
332 size_t offset = value.indexOf(QLatin1Char(
'='));
333 r.name = value.left(offset).trimmed();
334 QString val = value.right(value.length() - offset - 1).trimmed();
335 if (val.endsWith(QLatin1Char(
',')))
336 val = val.left(val.length() - 1);
338 int integer = val.toInt(&valid);
340 integer = val.toInt(&valid, 16);
342 cur = r.value = integer;
345 auto iter = std::find_if(ret.begin(), ret.end(), [&val](
const EnumNameValue &elem){
346 return elem.name == val;
348 if (iter != ret.end()) {
349 cur = r.value = iter->value;
352 DEBUGPRINTF(printf(
"Invalid value: %s %s\n", qPrintable(r.name), qPrintable(value)));
356 if (value.endsWith(QLatin1Char(
',')))
357 r.name = value.left(value.length() - 1);
367void Parser::
parseMetadata(
const QString &data, qsizetype offset,
const QStringList &includes)
369 qsizetype beginOfProvider = data.indexOf(QLatin1Char(
'('), offset);
370 qsizetype endOfProvider = data.indexOf(QLatin1Char(
','), beginOfProvider);
372 QString provider = data.mid(beginOfProvider + 1, endOfProvider - beginOfProvider - 1).simplified();
373 if (provider != m_provider)
376 qsizetype endOfPoint = data.indexOf(QLatin1Char(
')'), endOfProvider + 1);
377 metadata = data.mid(endOfProvider + 1, endOfPoint - endOfProvider - 1).simplified();
379 DEBUGPRINTF(printf(
"tracepointgen: metadata: %s", qPrintable(metadata)));
381 QString preprocessed = preprocessMetadata(metadata);
383 DEBUGPRINTF2(printf(
"preprocessed %s\n", qPrintable(preprocessed)));
385 QRegularExpression macro(QStringLiteral(
"([A-Z]*) ?{ ?([A-Za-z0-9=_,. ]*) ?} ?([A-Za-z0-9_:]*) ?;"));
386 QRegularExpressionMatchIterator i = macro.globalMatch(preprocessed);
388 while (i.hasNext()) {
389 QRegularExpressionMatch match = i.next();
390 QString values = match.captured(2).trimmed();
391 int cur = match.capturedStart();
393 m_metadata.append(preprocessed.mid(prev, cur - prev));
395 prev = match.capturedEnd() + 1;
396 DEBUGPRINTF2(printf(
"values: %s\n", qPrintable(values)));
397 if (values.isEmpty() || values.startsWith(QStringLiteral(
"AUTO"))) {
398 values.replace(QLatin1Char(
'\n'), QLatin1Char(
' '));
400 if (values.contains(QStringLiteral(
"RANGE"))) {
401 QRegularExpression rangeMacro(QStringLiteral(
"RANGE +([A-Za-z0-9_]*) +... +([A-Za-z0-9_]*)"));
402 QRegularExpressionMatchIterator r = rangeMacro.globalMatch(values);
403 while (r.hasNext()) {
404 QRegularExpressionMatch rm = r.next();
405 ranges << rm.captured(1);
406 ranges << rm.captured(2);
407 DEBUGPRINTF2(printf(
"range: %s ... %s\n", qPrintable(rm.captured(1)), qPrintable(rm.captured(2))));
411 const auto enumOrFlag = match.captured(1);
412 const auto name = match.captured(3);
413 const bool flags = enumOrFlag == QStringLiteral(
"FLAGS");
415 QStringList values = findEnumValues(name, includes);
416 if (values.isEmpty()) {
417 if (flags && name.endsWith(QLatin1Char(
's')))
418 values = findEnumValues(name.left(name.length() - 1), includes);
419 if (values.isEmpty()) {
420 DEBUGPRINTF(printf(
"Unable to find values for %s\n", qPrintable(name)));
423 if (!values.isEmpty()) {
424 auto moreValues = enumsToValues(values);
426 for (
int i = 0; i < ranges.size() / 2; i++) {
427 bool rangeFound =
false;
428 for (
auto &v : moreValues) {
429 if (v.name == ranges[2 * i]) {
431 QString rangeEnd = ranges[2 * i + 1];
432 auto iter = std::find_if(moreValues.begin(), moreValues.end(), [&rangeEnd](
const EnumNameValue &elem){
433 return elem.name == rangeEnd;
435 if (iter != moreValues.end())
436 v.valueStr = QStringLiteral(
"RANGE(%1, %2 ... %3)").arg(v.name).arg(v.value).arg(iter->value);
438 panic(
"Unable to find range end: %s\n", qPrintable(rangeEnd));
442 if (rangeFound ==
false)
443 panic(
"Unable to find range begin: %s\n", qPrintable(ranges[2 * i]));
446 std::sort(moreValues.begin(), moreValues.end(), [](
const EnumNameValue &a,
const EnumNameValue &b) {
447 return a.value < b.value;
450 int prevValue = std::as_const(moreValues).front().value;
451 for (
const auto &v : std::as_const(moreValues)) {
453 if (v.valueStr.isNull()) {
454 if (v.value == prevValue + 1 && !flags)
457 a = QStringLiteral(
"%1 = %2").arg(v.name).arg(v.value);
465 metadata = QStringLiteral(
"%1 {\n %2 \n} %3;").arg(enumOrFlag).arg(values.join(QStringLiteral(
",\n"))).arg(name);
466 if (!m_metadata.contains(metadata))
467 m_metadata.append(metadata);
470 if (!m_metadata.contains(match.captured()))
471 m_metadata.append(match.captured());
474 if (prev < preprocessed.length())
475 m_metadata.append(preprocessed.mid(prev, preprocessed.length() - prev));
491void Parser::addIncludesRecursive(
const QString &filename,
QList<QString> &includes)
494 DEBUGPRINTF(printf(
"check include: %s\n", qPrintable(filename)));
495 QFile input(filename);
496 if (!input.open(QIODevice::ReadOnly | QIODevice::Text)) {
497 DEBUGPRINTF(printf(
"Cannot open '%s' for reading: %s\n",
498 qPrintable(filename), qPrintable(input.errorString())));
503 while (!stream.atEnd()) {
504 QString line = stream.readLine().trimmed();
505 data += line + QLatin1Char(QLatin1Char(
'\n'));
508 QRegularExpression includeMacro(QStringLiteral(
"#include [\"<]([A-Za-z0-9_./-]*.h)[\">]"));
509 QRegularExpressionMatchIterator i = includeMacro.globalMatch(data);
510 while (i.hasNext()) {
511 QRegularExpressionMatch match = i.next();
512 QString filename = match.captured(1);
514 QString rinc = filename;
515 if (filename.startsWith(QStringLiteral(
"../"))) {
516 QFileInfo info2(info.absolutePath() + QLatin1Char(
'/') + filename);
517 if (!info2.exists()) {
518 DEBUGPRINTF(printf(
"unable to find %s\n", qPrintable(filename)));
521 rinc = info2.absoluteFilePath();
522 filename = info2.fileName();
525 if (QFileInfo(filename).baseName().startsWith(QLatin1Char(
'q'), Qt::CaseInsensitive)) {
526 QString resolved = resolveInclude(rinc);
527 if (!resolved.isEmpty() && !includes.contains(resolved)) {
528 includes.push_back(resolved);
529 addIncludesRecursive(resolved, includes);
535void Parser::parse(QIODevice &input,
const QString &name)
541 while (!stream.atEnd()) {
542 QString line = stream.readLine().trimmed();
543 m_offsets.push_back({prev, prev + line.length(), lineNumber++});
544 prev += line.length() + 1;
545 data += line + QLatin1Char(QLatin1Char(
'\n'));
548 simplifyData(data, m_offsets);
550 QStringList includes;
552 QRegularExpression includeMacro(QStringLiteral(
"#include [\"<]([A-Za-z0-9_./-]*.h)[\">]"));
553 QRegularExpressionMatchIterator i = includeMacro.globalMatch(data);
554 while (i.hasNext()) {
555 QRegularExpressionMatch match = i.next();
556 const QString filename = match.captured(1);
558 if (filename.startsWith(QLatin1Char(
'q'), Qt::CaseInsensitive)) {
559 const QString resolved = resolveInclude(filename);
560 if (!resolved.isEmpty() && !includes.contains(resolved)) {
561 includes.push_back(resolved);
562 addIncludesRecursive(resolved, includes);
567 QRegularExpression traceMacro(QStringLiteral(
"Q_TRACE_([A-Z_]*)"));
568 i = traceMacro.globalMatch(data);
569 while (i.hasNext()) {
570 QRegularExpressionMatch match = i.next();
572 QString macroType = match.captured(1);
573 if (macroType == QStringLiteral(
"PARAM_REPLACE"))
574 parseParamReplace(data, match.capturedEnd(), name);
575 else if (macroType == QStringLiteral(
"INSTRUMENT"))
576 parseInstrument(data, match.capturedEnd());
577 else if (macroType == QStringLiteral(
"POINT"))
578 parsePoint(data, match.capturedEnd());
579 else if (macroType == QStringLiteral(
"PREFIX"))
580 parsePrefix(data, match.capturedEnd());
581 else if (macroType == QStringLiteral(
"METADATA"))
582 parseMetadata(data, match.capturedEnd(), includes);
585 for (
auto &func : m_functions) {
586 for (
auto &rep : m_replaces)
587 func.functionParameters.replace(rep.in, rep.out);