10#include <QtCore/QBitArray>
11#include <QtCore/QTextStream>
12#include <QtCore/QRegularExpression>
22using namespace Qt::StringLiterals;
26 if (str.m_hash & 0x80000000)
27 str.m_hash = qHash(str.m_str) & 0x7fffffff;
33 return debug << s.value();
38 if (list.m_hash & 0x80000000) {
40 for (
const HashString &qs : list.m_list) {
41 hash ^= qHash(qs) ^ 0x6ad9f526;
42 hash = ((hash << 13) & 0x7fffffff) | (hash >> 18);
51 return debug << lst.m_list;
60 m_ba.resize(nextFileId);
78 void setInput(QTextStream &ts,
const QString &fileName);
83 QSet<QString> &inclusions);
90 IfdefState(
int _bracketDepth,
int _braceDepth,
int _parenDepth) :
91 bracketDepth(_bracketDepth),
92 braceDepth(_braceDepth),
93 parenDepth(_parenDepth),
98 int bracketDepth, bracketDepth1st;
99 int braceDepth, braceDepth1st;
100 int parenDepth, parenDepth1st;
126 Tok_LeftAngleBracket,
127 Tok_RightAngleBracket,
142 std::ostream &yyMsg(
int line = 0);
145 TokenType lookAheadToSemicolonOrLeftBrace();
146 int lookBackFunctionCallStart(
int prefixSize);
147 int lookAheadFunctionCallEnd(
int functionStart);
148 TokenType getToken();
150 void processComment();
152 bool match(TokenType t);
153 bool matchString(QString *s);
154 bool matchEncoding();
155 bool matchStringOrNull(QString *s);
156 bool skipExpression();
158 void recordMessage(
int line,
const QString &context,
const QString &text,
159 const QString &comment,
const QString &extracomment,
const QString &msgid,
161 bool plural,
int startOffset,
int endOffset);
163 void handleTr(QString &prefix,
bool plural);
164 void handleTranslate(
int prefixSize,
bool plural);
165 void handleTrId(
int prefixSize,
bool plural);
166 void handleDeclareTrFunctions();
169 const QStringList &includeStack, QSet<QString> &inclusions);
174 static QString stringifyNamespace(
int start,
const NamespaceList &namespaces);
175 static QString stringifyNamespace(
const NamespaceList &namespaces)
176 {
return stringifyNamespace(1, namespaces); }
177 static QString joinNamespaces(
const QString &one,
const QString &two);
178 typedef bool (CppParser::*VisitNamespaceCallback)(
const Namespace *ns,
void *context)
const;
179 bool visitNamespace(
const NamespaceList &namespaces,
int nsCount,
180 VisitNamespaceCallback callback,
void *context,
182 bool visitNamespace(
const NamespaceList &namespaces,
int nsCount,
183 VisitNamespaceCallback callback,
void *context)
const;
184 bool qualifyOneCallbackOwn(
const Namespace *ns,
void *context)
const;
185 bool qualifyOneCallbackUsing(
const Namespace *ns,
void *context)
const;
188 QSet<HashStringList> *visitedUsings,
bool *foundViaUsing =
nullptr)
const;
191 bool fullyQualify(
const NamespaceList &namespaces,
int nsCnt,
198 const QString &segments,
bool isDeclaration,
200 bool findNamespaceCallback(
const Namespace *ns,
void *context)
const;
203 void truncateNamespaces(
NamespaceList *namespaces,
int lenght);
210 bool yyTrailingSpace;
212 qsizetype yyWordInitialCapacity = 0;
213 QStack<IfdefState> yyIfdefStack;
226 const ushort *yyInPtr;
235 QString prospectiveContext;
250 directInclude =
true;
253 directInclude =
false;
270 return std::cerr << qPrintable(yyFileName) <<
':' << (line ? line : yyLineNo) <<
": ";
276 yyFileName = QString();
277 yySourceEncoding = QStringConverter::Utf8;
282 yyInStr = ts.readAll();
283 yyFileName = fileName;
284 yySourceEncoding = ts.encoding();
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
311 const ushort *uc = yyInPtr;
340 }
else if (c ==
'\n') {
343 }
else if (c !=
' ' && c !=
'\t' && c !=
'#') {
355 const ushort *uc = yyInPtr + 1;
361 return Tok_Semicolon;
363 return Tok_LeftBrace;
378 if (s.endsWith(u'R')) {
380 return s.isEmpty() || isStringLiteralPrefix(s);
411 Q_ASSERT(yyWord.capacity() == yyWordInitialCapacity);
413 while (yyCh != EOF) {
414 yyLineNo = yyCurLineNo;
416 if (yyCh ==
'#' && yyAtNewline) {
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
439 }
while (isspace(yyCh) && yyCh !=
'\n');
450 }
while (!isspace(yyCh));
457 }
while (isspace(yyCh));
468 }
while (yyCh !=
')');
476 }
while (!isspace(yyCh));
483 }
while (isspace(yyCh));
485 saveState(&savedState);
486 yyMinBraceDepth = yyBraceDepth;
493 yyIfdefStack.push(IfdefState(yyBracketDepth, yyBraceDepth, yyParenDepth));
495 }
else if (yyCh ==
'n') {
499 }
while (yyCh != EOF && !isspace(yyCh) && yyCh !=
'"' && yyCh !=
'<' );
500 while (isspace(yyCh))
505 else if (yyCh ==
'<')
509 ushort *ptr = (ushort *)yyWord.unicode();
512 if (yyCh == EOF || yyCh ==
'\n')
520 yyWord.resize(ptr - (ushort *)yyWord.unicode());
521 return (tChar ==
'"') ? Tok_QuotedInclude : Tok_AngledInclude;
528 if (!yyIfdefStack.isEmpty()) {
529 IfdefState &is = yyIfdefStack.top();
530 if (is.elseLine != -1) {
531 if (yyBracketDepth != is.bracketDepth1st
532 || yyBraceDepth != is.braceDepth1st
533 || yyParenDepth != is.parenDepth1st)
535 <<
"Parenthesis/bracket/brace mismatch between "
536 "#if and #else branches; using #if branch\n";
538 is.bracketDepth1st = yyBracketDepth;
539 is.braceDepth1st = yyBraceDepth;
540 is.parenDepth1st = yyParenDepth;
541 saveState(&is.state);
543 is.elseLine = yyLineNo;
544 yyBracketDepth = is.bracketDepth;
545 yyBraceDepth = is.braceDepth;
546 yyParenDepth = is.parenDepth;
549 }
else if (yyCh ==
'n') {
551 if (!yyIfdefStack.isEmpty()) {
552 IfdefState is = yyIfdefStack.pop();
553 if (is.elseLine != -1) {
554 if (yyBracketDepth != is.bracketDepth1st
555 || yyBraceDepth != is.braceDepth1st
556 || yyParenDepth != is.parenDepth1st)
558 <<
"Parenthesis/brace mismatch between "
559 "#if and #else branches; using #if branch\n";
560 yyBracketDepth = is.bracketDepth1st;
561 yyBraceDepth = is.braceDepth1st;
562 yyParenDepth = is.parenDepth1st;
577 }
while (yyCh != EOF && yyCh !=
'\n');
579 }
else if (yyCh ==
'*') {
580 bool metAster =
false;
585 yyMsg() <<
"Unterminated C++ comment\n";
591 }
else if (metAster && yyCh ==
'/') {
602 }
while (yyCh !=
'\n' && yyCh != EOF);
604 }
else if ((yyCh >=
'A' && yyCh <=
'Z') || (yyCh >=
'a' && yyCh <=
'z') || yyCh ==
'_') {
605 ushort *ptr = (ushort *)yyWord.unicode();
609 }
while ((yyCh >=
'A' && yyCh <=
'Z') || (yyCh >=
'a' && yyCh <=
'z')
610 || (yyCh >=
'0' && yyCh <=
'9') || yyCh ==
'_');
611 yyWord.resize(ptr - (ushort *)yyWord.unicode());
612 yyTrailingSpace = isspace(yyCh);
616 if (yyCh ==
'"' && isStringLiteralPrefix(yyWord)) {
621 switch (yyWord.unicode()[0].unicode()) {
623 if (yyWord == strNULL)
627 if (yyWord == strQ_NULLPTR)
629 if (yyWord == strQ_OBJECT)
631 if (yyWord == strQ_SLOTS || yyWord == strQ_SIGNALS)
635 if (yyWord == strclass)
639 if (yyWord == strdecltype)
643 if (yyWord == strenum)
647 if (yyWord == strfriend)
651 if (yyWord == strnamespace)
652 return Tok_namespace;
653 if (yyWord == strnullptr)
657 if (yyWord == stroperator) {
661 while (isspace(yyCh))
663 while (yyCh ==
'+' || yyCh ==
'-' || yyCh ==
'*' || yyCh ==
'/' || yyCh ==
'%'
664 || yyCh ==
'=' || yyCh ==
'<' || yyCh ==
'>' || yyCh ==
'!'
665 || yyCh ==
'&' || yyCh ==
'|' || yyCh ==
'~' || yyCh ==
'^'
666 || yyCh ==
'[' || yyCh ==
']')
671 if (yyWord == strpublic || yyWord == strprotected || yyWord == strprivate)
675 if (yyWord == strreturn)
679 if (yyWord == strstruct)
681 if (yyWord == strslots || yyWord == strsignals)
685 if (yyWord == strusing)
691 if (yyCh ==
'"' && isRawStringLiteralPrefix(yyWord)) {
692 ptr =
reinterpret_cast<ushort *>(
const_cast<QChar *>(yyWord.unicode()));
695 for (yyCh = getChar(); yyCh != EOF && yyCh !=
'('; yyCh = getChar())
696 delimiter += QLatin1Char(yyCh);
700 ushort *ptr_past_end =
nullptr;
701 while (yyCh != EOF && !is_end) {
703 if (ptr_past_end !=
nullptr) {
704 if (delimiter.size() == ptr - ptr_past_end
705 && memcmp(delimiter.unicode(), ptr_past_end, (ptr - ptr_past_end) *
sizeof (ushort)) == 0
712 ptr_past_end =
nullptr;
718 if (delimiter.isEmpty()) {
724 ptr_past_end =
nullptr;
731 yyWord.resize(ptr_past_end - 1 -
reinterpret_cast<
const ushort *>(yyWord.unicode()));
733 yyWord.resize(ptr -
reinterpret_cast<
const ushort *>(yyWord.unicode()));
735 yyMsg() <<
"Unterminated/mismatched C++ Raw string\n";
738 return Tok_RawString;
746 loadState(savedState);
747 prospectiveContext.clear();
748 yyBraceDepth = yyMinBraceDepth;
760 ushort *ptr = (ushort *)yyWord.unicode();
766 }
while (yyCh !=
'\n');
767 yyWord.resize(ptr - (ushort *)yyWord.unicode());
769 }
else if (yyCh ==
'*') {
770 bool metAster =
false;
771 ushort *ptr = (ushort *)yyWord.unicode();
776 yyMsg() <<
"Unterminated C++ comment\n";
783 else if (metAster && yyCh ==
'/')
788 yyWord.resize(ptr - (ushort *)yyWord.unicode() - 2);
795 ushort *ptr = (ushort *)yyWord.unicode();
797 while (yyCh != EOF && yyCh !=
'\n' && yyCh !=
'"') {
800 if (yyCh == EOF || yyCh ==
'\n')
807 yyWord.resize(ptr - (ushort *)yyWord.unicode());
810 yyMsg() <<
"Unterminated C++ string\n";
826 return Tok_ColonColon;
838 return Tok_RightAngleBracket;
843 return Tok_LeftShift;
845 return Tok_LeftAngleBracket;
852 if (yyCh == EOF || yyCh ==
'\n') {
853 yyMsg() <<
"Unterminated C++ character\n";
864 if (yyBraceDepth == 0)
865 yyBraceLineNo = yyCurLineNo;
868 return Tok_LeftBrace;
870 if (yyBraceDepth == yyMinBraceDepth) {
873 <<
"Excess closing brace in C++ code"
874 " (or abuse of the C++ preprocessor)\n";
877 return Tok_Semicolon;
881 return Tok_RightBrace;
883 if (yyParenDepth == 0)
884 yyParenLineNo = yyCurLineNo;
887 return Tok_LeftParen;
889 if (yyParenDepth == 0)
891 <<
"Excess closing parenthesis in C++ code"
892 " (or abuse of the C++ preprocessor)\n";
896 return Tok_RightParen;
903 bool inString =
false;
905 bool escaped =
false;
908 while (depth > 0 && yyCh != EOF) {
911 }
else if (yyCh ==
'\\') {
913 }
else if (yyCh ==
'"' && !inChar) {
914 inString = !inString;
915 }
else if (yyCh ==
'\'' && !inString) {
917 }
else if (!inString && !inChar) {
920 else if (yyCh ==
']')
927 yyMsg(yyCurLineNo) <<
"Unterminated C++ attribute (missing ']]')\n";
928 return Tok_LeftBracket;
932 return Tok_Attribute;
934 if (yyBracketDepth == 0)
935 yyBracketLineNo = yyCurLineNo;
937 return Tok_LeftBracket;
939 if (yyBracketDepth == 0)
941 <<
"Excess closing bracket in C++ code"
942 " (or abuse of the C++ preprocessor)\n";
946 return Tok_RightBracket;
952 return Tok_Semicolon;
955 return Tok_QuestionMark;
958 if (yyCh ==
'x' || yyCh ==
'X') {
961 }
while ((yyCh >=
'0' && yyCh <=
'9') || yyCh ==
'\''
962 || (yyCh >=
'a' && yyCh <=
'f') || (yyCh >=
'A' && yyCh <=
'F'));
965 if (yyCh <
'0' || yyCh >
'9')
979 }
while ((yyCh >=
'0' && yyCh <=
'9') || yyCh ==
'\'');
991
992
993
1002 *
static_cast<CppParserState *>(
this) = state;
1007 Namespace *pns, *ns = &results->rootNamespace;
1008 for (
int i = 1; i < namespaces->size(); ++i) {
1010 if (!(ns = pns->children.value(namespaces->at(i)))) {
1013 if (haveLast || i < namespaces->size() - 1)
1014 if (
const Namespace *ons = findNamespace(*namespaces, i + 1))
1016 pns->children.insert(namespaces->at(i), ns);
1019 }
while (++i < namespaces->size());
1030 for (
int j = start; j < namespaces.size(); ++j)
1031 l += namespaces.at(j).value().size();
1032 ret.reserve(l + qMax(0, (namespaces.size() - start - 1)) * 2);
1033 for (
int i = start; i < namespaces.size(); ++i) {
1036 ret += namespaces.at(i).value();
1041QString
CppParser::joinNamespaces(
const QString &one,
const QString &two)
1043 return two.isEmpty() ? one : one.isEmpty() ? two : one + QStringLiteral(
"::") + two;
1047 VisitNamespaceCallback callback,
void *context,
1050 const Namespace *ns = &rslt->rootNamespace;
1051 for (
int i = 1; i < nsCount; ++i)
1052 if (!(ns = ns->children.value(namespaces.at(i))))
1054 if ((
this->*callback)(ns, context))
1057 for (
const ParseResults *sup : rslt->includes)
1058 if (vr.tryVisit(sup->fileId)
1059 && visitNamespace(namespaces, nsCount, callback, context, vr, sup))
1065 VisitNamespaceCallback callback,
void *context)
const
1068 return visitNamespace(namespaces, nsCount, callback, context, vr, results);
1073 QSet<HashStringList> *visited,
Namespace const **resolvedNs)
1093 if (
auto rns = ns->children.constFind(data
->segment); rns != ns->children.cend()) {
1099 auto nsai = ns->aliases.constFind(data
->segment);
1100 if (nsai != ns->aliases.constEnd()) {
1102 if (nsl.last().value().isEmpty()) {
1122 for (
const HashStringList &use : ns->usings)
1123 if (!data->visitedUsings->contains(use)) {
1124 data->visitedUsings->insert(use);
1125 if (qualifyOne(use.value(), use.value().size(), data->segment, data->resolved,
1126 data->resolvedNamespace, data->visitedUsings))
1134 QSet<HashStringList> *visitedUsings,
bool *foundViaUsing)
const
1136 QualifyOneData data(namespaces, nsCnt, segment, resolved, visitedUsings, resolvedNamespace);
1138 if (visitNamespace(namespaces, nsCnt, &
CppParser::qualifyOneCallbackOwn, &data)) {
1140 *foundViaUsing =
false;
1144 if (visitNamespace(namespaces, nsCnt, &
CppParser::qualifyOneCallbackUsing, &data)) {
1146 *foundViaUsing =
true;
1156 QSet<HashStringList> visitedUsings;
1158 return qualifyOne(namespaces, nsCnt, segment, resolved, resolvedNamespace, &visitedUsings);
1168 if (segments.first().value().isEmpty()) {
1170 if (segments.size() == 1) {
1187 auto matchSeg = segments.crbegin();
1188 auto matchNs = namespaces.crbegin();
1190 if (matchSeg->value() != matchNs->value())
1193 int matchingSuffixLength = 0;
1194 while (matchSeg != segments.crend()
1195 && matchNs != namespaces.crend()
1196 && matchSeg->value() == matchNs->value()) {
1200 matchingSuffixLength++;
1213 bool viaUsing =
false;
1219 int segIdx = initSegIdx;
1220 int resolveSize = nsIdx + 1;
1221 *resolved = namespaces;
1223 QSet<HashStringList> visitedUsings;
1224 if (!qualifyOne(*resolved, resolveSize, segments[segIdx], resolved, &resolvedNs,
1225 &visitedUsings, &viaUsing))
1229 resolveSize = resolved->size();
1230 }
while (segIdx < segments.size());
1232 if (segIdx == segments.size()) {
1236 else if (!trCandidate)
1237 trCandidate.emplace(*resolved);
1238 }
else if (resolvedNs) {
1240 noTrCandidate.emplace(*resolved);
1241 else if (!noTrCandidate)
1242 noTrCandidate.emplace(*resolved);
1244 }
else if (!unresolvedCandidate) {
1245 unresolvedCandidate.emplace(segments.mid(segIdx));
1250 }
while ((!isDeclaration || matchingSuffixLength-- > 0) && --nsIdx >= 0);
1263 *resolved = *trCandidate;
1265 }
else if (noTrCandidate) {
1266 *resolved = *noTrCandidate;
1268 }
else if (unresolvedCandidate && unresolved) {
1269 *unresolved = *unresolvedCandidate;
1275 *unresolved = segments.mid(initSegIdx);
1283 return fullyQualify(namespaces, namespaces.size(),
1284 segments, isDeclaration, resolved, unresolved);
1288 const QString &quali,
bool isDeclaration,
1292 for (
const QString &str : quali.split(
"::"_L1))
1293 segments << HashString(str);
1294 return fullyQualify(namespaces, segments, isDeclaration, resolved, unresolved);
1307 nsCount = namespaces.size();
1308 visitNamespace(namespaces, nsCount, &
CppParser::findNamespaceCallback, &ns);
1314 *namespaces << name;
1316 if (!(ns = findNamespace(*namespaces)))
1317 ns = modifyNamespace(namespaces,
false);
1319 const Namespace *cns = &results->rootNamespace;
1320 for (
int i = 1; i < namespaces->size(); ++i) {
1321 ns->usings << cns->usings;
1322 if (!(cns = cns->children.value(namespaces->at(i))))
1329 if (namespaces->size() > length)
1330 namespaces->erase(namespaces->begin() + length, namespaces->end());
1335
1336
1340 seed = qHash(s.namespaces, seed);
1341 seed = qHash(s.namespaceDepths, seed);
1342 seed = qHash(s.functionContext, seed);
1343 seed = qHash(s.functionContextUnresolved, seed);
1344 seed = qHash(s.pendingContext, seed);
1350 seed = qHash(key.cleanFile, seed);
1351 seed = qHash(key.parserState, seed);
1369QSet<QString> &
CppFiles::blacklistedFiles()
1371 static QSet<QString> blacklisted;
1378 IncludeCycle *
const cycle = includeCycles().value(key);
1381 return cycle->results;
1392 includeCycles().insert(key, cycle);
1395 cycle->fileNames.insert(key.cleanFile);
1396 cycle->results.insert(results);
1401 return translatedFiles().value(cleanFile);
1406 translatedFiles().insert(cleanFile, tor);
1411 return blacklistedFiles().contains(cleanFile);
1416 blacklistedFiles().insert(cleanFile);
1422 cycle->fileNames = fileNames;
1424 QSet<IncludeCycle *> intersectingCycles;
1425 for (
const QString &fileName : fileNames) {
1426 const ResultsCacheKey key = { fileName, parserState };
1427 IncludeCycle *intersectingCycle = includeCycles().value(key);
1429 if (intersectingCycle && !intersectingCycles.contains(intersectingCycle)) {
1430 intersectingCycles.insert(intersectingCycle);
1432 cycle->fileNames.unite(intersectingCycle->fileNames);
1433 cycle->results.unite(intersectingCycle->results);
1436 qDeleteAll(intersectingCycles);
1438 for (
const QString &fileName : std::as_const(cycle->fileNames))
1439 includeCycles().insert({ fileName, parserState }, cycle);
1444 QString fileExt = QFileInfo(name).suffix();
1445 return fileExt.isEmpty() || fileExt.startsWith(u'h', Qt::CaseInsensitive);
1449 QSet<QString> &inclusions)
1451 QString cleanFile = QDir::cleanPath(file);
1453 for (
const QRegularExpression &rx : std::as_const(cd.m_excludes)) {
1454 if (rx.match(cleanFile).hasMatch())
1458 const int index = includeStack.indexOf(cleanFile);
1460 CppFiles::addIncludeCycle(QSet<QString>(includeStack.cbegin() + index, includeStack.cend()),
1469 bool isIndirect =
false;
1470 if (!CppFiles::isBlacklisted(cleanFile)
1471 && isHeader(cleanFile)) {
1473 QSet<
const ParseResults *> res = CppFiles::getResults(ResultsCacheKey(cleanFile, *
this));
1474 if (!res.isEmpty()) {
1475 results->includes.unite(res);
1483 if (!f.open(QIODevice::ReadOnly)) {
1484 yyMsg() << qPrintable(
1485 QStringLiteral(
"Cannot open %1: %2\n").arg(cleanFile, f.errorString()));
1490 ts.setEncoding(yySourceEncoding);
1491 ts.setAutoDetectUnicode(
true);
1493 inclusions.insert(cleanFile);
1496 for (
const QString &projectRoot : std::as_const(cd.m_projectRoots))
1497 if (cleanFile.startsWith(projectRoot)) {
1498 parser.setTranslator(
new Translator);
1501 parser.setInput(ts, cleanFile);
1502 QStringList stack = includeStack;
1504 parser.parse(cd, stack, inclusions);
1508 parser.namespaces = namespaces;
1509 parser.functionContext = functionContext;
1510 parser.functionContextUnresolved = functionContextUnresolved;
1511 parser.setInput(ts, cleanFile);
1513 QStringList stack = includeStack;
1515 parser.parseInternal(cd, stack, inclusions);
1517 CppFiles::setBlacklisted(cleanFile);
1519 inclusions.remove(cleanFile);
1521 prospectiveContext.clear();
1522 pendingContext.clear();
1526
1527
1528
1529
1530
1531
1532
1533
1537 bool matches = (yyTok == t);
1545 bool matches =
false;
1548 if (yyTok != Tok_String && yyTok != Tok_RawString)
1551 if (yyTok == Tok_String)
1552 *s += transcode(yyWord);
1569 if (yyTok != Tok_Ident)
1571 if (yyWord == strQApplication || yyWord == strQCoreApplication) {
1573 if (yyTok == Tok_ColonColon)
1576 if (yyWord == strUnicodeUTF8) {
1580 if (yyWord == strLatin1 || yyWord == strDefaultCodec || yyWord == strCodecForTr)
1581 yyMsg() <<
"Unsupported encoding Latin1/DefaultCodec/CodecForTr\n";
1585bool CppParser::matchStringOrNull(QString *s)
1587 return matchString(s) || match(Tok_Null);
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1603 if (match(Tok_Null) || match(Tok_Integer))
1607 while (parenlevel >= 0) {
1609 if (yyTok == Tok_RightParen)
1611 else if (yyTok == Tok_LeftParen)
1613 else if (yyTok == Tok_Cancel || yyTok == Tok_Eof)
1619void CppParser::recordMessage(
int line,
const QString &context,
const QString &text,
1620 const QString &comment,
const QString &extracomment,
1621 const QString &msgid,
const QString &label,
1623 bool plural,
int startOffset,
int endOffset)
1625 TranslatorMessage msg(transcode(context), text, transcode(comment), QString(), yyFileName, line,
1626 QStringList(), TranslatorMessage::Unfinished, plural);
1627 msg.setExtraComment(transcode(extracomment.simplified()));
1630 if (!msgid.isEmpty())
1631 msg.setLabel(label);
1637void CppParser::handleTr(QString &prefix,
bool plural)
1639 if (!m_metaStrings.sourcetext().isEmpty())
1640 yyMsg() <<
"//% cannot be used with tr() / QT_TR_NOOP(). Ignoring\n";
1641 if (!m_metaStrings.label().isEmpty())
1642 yyMsg() <<
"labels cannot be used with text-based translation. Ignoring\n";
1644 int line = yyLineNo;
1645 const int startOffset = lookBackFunctionCallStart(prefix.size());
1648 if (matchString(&text)) {
1650 if (yyTok == Tok_RightParen) {
1652 }
else if (match(Tok_Comma) && matchStringOrNull(&comment)) {
1653 if (yyTok == Tok_RightParen) {
1655 }
else if (match(Tok_Comma)) {
1660 if (!pendingContext.isEmpty() && !prefix.startsWith(
"::"_L1)) {
1662 if (!fullyQualify(namespaces, pendingContext,
true, &functionContext, &unresolved)) {
1663 functionContextUnresolved = stringifyNamespace(0, unresolved);
1664 yyMsg() << qPrintable(
1665 QStringLiteral(
"Qualifying with unknown namespace/class %1::%2\n")
1666 .arg(stringifyNamespace(functionContext)).arg(unresolved.first().value()));
1668 pendingContext.clear();
1670 if (prefix.isEmpty()) {
1671 if (functionContextUnresolved.isEmpty()) {
1672 int idx = functionContext.size();
1674 yyMsg() <<
"tr() cannot be called without context\n";
1678 while (!(fctx = findNamespace(functionContext, idx)->classDef)->hasTrFunctions) {
1680 context = stringifyNamespace(functionContext);
1681 fctx = findNamespace(functionContext)->classDef;
1683 yyMsg() << qPrintable(
1684 QStringLiteral(
"Class '%1' lacks Q_OBJECT macro\n").arg(context));
1691 if (fctx->trQualification.isEmpty()) {
1694 context += functionContext.at(i).value();
1699 fctx->trQualification = context;
1701 context = fctx->trQualification;
1704 context = joinNamespaces(stringifyNamespace(functionContext), functionContextUnresolved);
1710 if (fullyQualify(functionContext, prefix,
false, &nsl, &unresolved)) {
1712 if (fctx->trQualification.isEmpty()) {
1713 context = stringifyNamespace(nsl);
1714 fctx->trQualification = context;
1716 context = fctx->trQualification;
1719 yyMsg() << qPrintable(QStringLiteral(
"Class '%1' lacks Q_OBJECT macro\n")
1724 context = joinNamespaces(stringifyNamespace(nsl), stringifyNamespace(0, unresolved));
1730 const int endOffset = yyInPtr - (
const ushort *)yyInStr.unicode() - 1;
1731 recordMessage(line, context, text, comment, m_metaStrings.extracomment(),
1732 m_metaStrings.msgid(), QString(), m_metaStrings.extra(),
1733 plural, startOffset, endOffset);
1735 m_metaStrings.clear();
1738void CppParser::handleTranslate(
int prefixSize,
bool plural)
1740 if (!m_metaStrings.sourcetext().isEmpty())
1741 yyMsg() <<
"//% cannot be used with translate() / QT_TRANSLATE_NOOP(). Ignoring\n";
1742 if (!m_metaStrings.label().isEmpty())
1743 yyMsg() <<
"labels cannot be used with text-based translation. Ignoring\n";
1744 const int startOffset = lookBackFunctionCallStart(prefixSize);
1745 int line = yyLineNo;
1748 if (matchString(&context)
1750 && matchString(&text) && !text.isEmpty())
1753 if (yyTok != Tok_RightParen) {
1755 if (match(Tok_Comma) && matchStringOrNull(&comment)) {
1756 if (yyTok != Tok_RightParen) {
1758 if (match(Tok_Comma)) {
1759 if (matchEncoding()) {
1760 if (yyTok != Tok_RightParen) {
1767 plural |= match(Tok_Comma);
1772 if (skipExpression() && yyTok == Tok_RightParen) {
1786 const int endOffset = yyInPtr - (
const ushort *)yyInStr.unicode() - 1;
1788 recordMessage(line, context, text, comment, m_metaStrings.extracomment(),
1789 m_metaStrings.msgid(), QString(), m_metaStrings.extra(),
1790 plural, startOffset, endOffset);
1792 m_metaStrings.clear();
1795void CppParser::handleTrId(
int prefixSize,
bool plural)
1797 if (!m_metaStrings.msgid().isEmpty())
1798 yyMsg() <<
"//= cannot be used with qtTrId() / QT_TRID_NOOP(). Ignoring\n";
1799 int line = yyLineNo;
1800 const int startOffset = lookBackFunctionCallStart(prefixSize);
1803 if (matchString(&msgid) && !msgid.isEmpty()) {
1804 plural |= match(Tok_Comma);
1805 const int endOffset = yyInPtr - (
const ushort *)yyInStr.unicode() - 1;
1807 recordMessage(line, QString(), transcode(m_metaStrings.sourcetext()), QString(),
1808 m_metaStrings.extracomment(), msgid, m_metaStrings.label(),
1809 m_metaStrings.extra(), plural, startOffset, endOffset);
1811 m_metaStrings.clear();
1814void CppParser::handleDeclareTrFunctions()
1819 if (yyTok != Tok_Ident)
1824 if (yyTok == Tok_RightParen)
1826 if (yyTok != Tok_ColonColon)
1830 Namespace *ns = modifyNamespace(&namespaces);
1831 ns->hasTrFunctions =
true;
1832 ns->trQualification = name;
1833 ns->trQualification.detach();
1837 QSet<QString> &inclusions)
1839 namespaces << HashString();
1840 functionContext = namespaces;
1841 functionContextUnresolved.clear();
1843 parseInternal(cd, includeStack, inclusions);
1846int CppParser::lookBackFunctionCallStart(
int prefixSize)
1848 const int funcNameOffset = yyInPtr - (
const ushort *)yyInStr.unicode();
1849 QStringView prefix = QStringView(yyInStr).sliced(0, funcNameOffset);
1852 while (prefix.back() !=
'('_L1);
1853 prefix.chop(prefixSize + yyWord.size() + 1);
1855 auto chopMatch = [](
auto& str,
const auto& match) {
1856 if (str.endsWith(match)) {
1857 str.chop(match.size());
1862 while (chopMatch(prefix,
"."_L1) || chopMatch(prefix,
"->"_L1)) {
1863 int pos = prefix.size() - 1;
1864 if (prefix.at(pos) ==
')'_L1) {
1867 while (count != 0 && pos >= 0) {
1868 if (QChar c = prefix.at(pos--); c ==
')'_L1)
1870 else if (c ==
'('_L1)
1872 else if (c ==
"\""_L1 || c ==
"'"_L1) {
1873 const QChar quotation = c;
1878 else if (c == quotation)
1884 while (pos >= 0 && (prefix.at(pos).isLetterOrNumber() || prefix.at(pos) ==
'_'_L1))
1886 prefix.slice(0, pos + 1);
1888 return prefix.size();
1893 bool forcePlural =
false;
1895 case TrFunctionAliasManager::Function_Q_DECLARE_TR_FUNCTIONS:
1896 handleDeclareTrFunctions();
1898 case TrFunctionAliasManager::Function_QT_TR_N_NOOP:
1901 case TrFunctionAliasManager::Function_tr:
1902 case TrFunctionAliasManager::Function_trUtf8:
1903 case TrFunctionAliasManager::Function_QT_TR_NOOP:
1904 case TrFunctionAliasManager::Function_QT_TR_NOOP_UTF8:
1906 handleTr(prefix, forcePlural);
1908 case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP:
1909 case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP3:
1912 case TrFunctionAliasManager::Function_translate:
1913 case TrFunctionAliasManager::Function_findMessage:
1914 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP:
1915 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP_UTF8:
1916 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3:
1917 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3_UTF8:
1919 handleTranslate(prefix.size(), forcePlural);
1921 case TrFunctionAliasManager::Function_QT_TRID_N_NOOP:
1924 case TrFunctionAliasManager::Function_qtTrId:
1925 case TrFunctionAliasManager::Function_QT_TRID_NOOP:
1927 handleTrId(prefix.size(), forcePlural);
1936 QSet<QString> &inclusions)
1938 static constexpr auto strColons(
"::"_L1);
1941 bool yyTokColonSeen =
false;
1942 bool yyTokIdentSeen =
false;
1943 bool maybeInTrailingReturnType =
false;
1945 const QList<TokenType> allowedTokensInFnTemplate{
1946 Tok_Ident, Tok_decltype, Tok_ColonColon, Tok_Comma,
1947 Tok_Integer, Tok_LeftAngleBracket, Tok_RightAngleBracket
1949 metaExpected =
true;
1951 prospectiveContext.clear();
1952 pendingContext.clear();
1954 yyWord.reserve(yyInStr.size());
1955 yyWordInitialCapacity = yyWord.capacity();
1956 yyInPtr = (
const ushort *)yyInStr.unicode();
1959 while (yyTok != Tok_Eof) {
1964 if (yyBracketDepth && yyBraceDepth == namespaceDepths.size()) {
1970 case Tok_QuotedInclude: {
1971 QString text = QDir(QFileInfo(yyFileName).absolutePath()).absoluteFilePath(yyWord);
1973 if (QFileInfo(text).isFile()) {
1974 processInclude(text, cd, includeStack, inclusions);
1980 case Tok_AngledInclude: {
1981 const QStringList cSources = cd.m_allCSources.values(yyWord);
1982 if (!cSources.isEmpty()) {
1983 for (
const QString &cSource : cSources)
1984 processInclude(cSource, cd, includeStack, inclusions);
1987 for (
const QString &incPath : std::as_const(cd.m_includePath)) {
1988 QString text = QDir(incPath).absoluteFilePath(yyWord);
1990 if (QFileInfo(text).isFile()) {
1991 processInclude(text, cd, includeStack, inclusions);
2002 if (yyTok == Tok_class)
2007
2008
2012 if (yyTok == Tok_Equals) {
2015 }
else if (yyBraceDepth == namespaceDepths.size() && yyParenDepth == 0) {
2021 QString text = yyWord;
2026 if (yyTok == Tok_ColonColon) {
2029 }
else if (yyTok == Tok_Ident) {
2030 if (yyWord == strfinal) {
2040 }
else if (yyTok == Tok_Attribute) {
2047 if (yyTok == Tok_Colon || yyTok == Tok_LeftAngleBracket) {
2053 if (yyTok == Tok_Eof)
2055 if (yyTok == Tok_Cancel)
2057 if (yyTok == Tok_class)
2059 if (yyTok == Tok_Ident) {
2061 if (yyTok == Tok_LeftParen)
2062 parseTranslate(prefix);
2064 goto tokenInTemplate;
2066 }
while (yyTok != Tok_LeftBrace && yyTok != Tok_Semicolon);
2067 if (yyTok == Tok_Semicolon)
2070 if (yyTok != Tok_LeftBrace) {
2077 if (!quali.isEmpty()) {
2080 if (!fullyQualify(namespaces, quali,
true, &nsl, 0)) {
2081 yyMsg() <<
"Ignoring definition of undeclared qualified class\n";
2084 namespaceDepths.push(namespaces.size());
2087 namespaceDepths.push(namespaces.size());
2089 enterNamespace(&namespaces, fct);
2092 Namespace *ns = modifyNamespace(&namespaces);
2095 functionContext = namespaces;
2096 functionContextUnresolved.clear();
2097 prospectiveContext.clear();
2098 pendingContext.clear();
2100 metaExpected =
true;
2107 while (yyTok == Tok_Attribute)
2109 if (yyTok == Tok_Ident) {
2110 QString text = yyWord;
2116 if (yyTok != Tok_ColonColon)
2119 if (yyTok != Tok_Ident)
2121 nestedNamespaces.append(ns);
2124 ns = HashString(text);
2126 if (yyTok == Tok_LeftBrace) {
2127 namespaceDepths.push(namespaces.size());
2128 for (
const auto &nns : nestedNamespaces)
2129 enterNamespace(&namespaces, nns);
2130 enterNamespace(&namespaces, ns);
2132 functionContext = namespaces;
2133 functionContextUnresolved.clear();
2134 prospectiveContext.clear();
2135 pendingContext.clear();
2136 metaExpected =
true;
2138 }
else if (yyTok == Tok_Equals) {
2141 NamespaceList fullName;
2143 if (yyTok == Tok_ColonColon)
2144 fullName.append(HashString(QString()));
2145 while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) {
2146 if (yyTok == Tok_Ident) {
2149 fullName.append(HashString(text));
2153 if (fullName.isEmpty())
2155 fullName.append(HashString(QString()));
2156 modifyNamespace(&namespaces)->aliases[ns] = fullName;
2158 }
else if (yyTok == Tok_LeftBrace) {
2160 namespaceDepths.push(namespaces.size());
2161 metaExpected =
true;
2168 if (yyTok == Tok_namespace) {
2171 if (yyTok == Tok_ColonColon)
2173 while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) {
2174 if (yyTok == Tok_Ident) {
2175 QString text = yyWord;
2182 if (fullyQualify(namespaces, fullName,
false, &nsl, 0))
2183 modifyNamespace(&namespaces)->usings << HashStringList(nsl);
2186 if (yyTok == Tok_ColonColon)
2188 while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) {
2189 if (yyTok == Tok_Ident) {
2190 QString text = yyWord;
2196 if (fullName.isEmpty())
2203 const HashString &ns = *(fullName.constEnd() - 2);
2204 modifyNamespace(&namespaces)->aliases[ns] = fullName;
2208 modifyNamespace(&namespaces)->hasTrFunctions =
true;
2212 if (yyTokColonSeen &&
2213 yyBraceDepth == namespaceDepths.size() && yyParenDepth == 0) {
2215 yyTokIdentSeen =
true;
2219 bool methodSpecialization =
false;
2220 if (yyTok == Tok_LeftAngleBracket) {
2225 while (count && allowedTokensInFnTemplate.contains(yyTok)) {
2226 if (yyTok == Tok_LeftAngleBracket)
2228 else if (yyTok == Tok_RightAngleBracket)
2232 methodSpecialization = count == 0;
2234 if (yyTok == Tok_LeftParen) {
2235 if (parseTranslate(prefix)) {
2242 if (yyTok == Tok_ColonColon && !maybeInTrailingReturnType && !yyTrailingSpace) {
2243 prefix += methodSpecialization ? className : yyWord;
2247 if (!prefix.isEmpty() && yyTok != Tok_LeftParen && yyTok != Tok_RightParen
2248 && yyTok != Tok_LeftBracket && yyTok != Tok_Equals) {
2251 prospectiveContext.clear();
2255 metaExpected =
false;
2259 if (yyParenDepth == 0 && yyBraceDepth == namespaceDepths.size())
2260 maybeInTrailingReturnType =
true;
2262 if (yyTok == Tok_Ident) {
2264 if (yyTok == Tok_LeftParen) {
2266 case TrFunctionAliasManager::Function_tr:
2267 case TrFunctionAliasManager::Function_trUtf8:
2268 yyMsg() <<
"Cannot invoke tr() like this\n";
2274 case Tok_ColonColon:
2275 if (yyTokIdentSeen || maybeInTrailingReturnType) {
2280 if (yyBraceDepth == namespaceDepths.size() && yyParenDepth == 0 && !yyTokColonSeen)
2281 prospectiveContext = prefix;
2282 if (!prefix.isEmpty())
2283 prefix += strColons;
2286 case Tok_RightBrace:
2287 if (!yyTokColonSeen) {
2288 if (yyBraceDepth + 1 == namespaceDepths.size()) {
2290 truncateNamespaces(&namespaces, namespaceDepths.pop());
2292 if (yyBraceDepth == namespaceDepths.size()) {
2294 if (!yyBraceDepth && !directInclude)
2295 truncateNamespaces(&functionContext, 1);
2297 functionContext = namespaces;
2298 functionContextUnresolved.clear();
2299 pendingContext.clear();
2304 maybeInTrailingReturnType =
false;
2305 prospectiveContext.clear();
2307 if (m_metaStrings.hasData()) {
2308 yyMsg() <<
"Discarding unconsumed meta data\n";
2309 m_metaStrings.clear();
2311 metaExpected =
true;
2318 }
while (yyTok == Tok_Access);
2319 metaExpected =
true;
2320 if (yyTok == Tok_Colon)
2325 if (yyBraceDepth == namespaceDepths.size() && yyParenDepth == 0) {
2326 if (!prospectiveContext.isEmpty()) {
2327 pendingContext = prospectiveContext;
2328 prospectiveContext.clear();
2331 if (yyTok == Tok_Colon) {
2332 if (lookAheadToSemicolonOrLeftBrace() != Tok_Semicolon)
2333 yyTokColonSeen =
true;
2336 metaExpected =
true;
2340 if (yyBraceDepth == namespaceDepths.size() + 1 && yyParenDepth == 0) {
2341 if (!prospectiveContext.isEmpty()) {
2342 pendingContext = prospectiveContext;
2343 prospectiveContext.clear();
2345 if (!yyTokIdentSeen) {
2347 yyTokColonSeen =
false;
2350 maybeInTrailingReturnType =
false;
2351 yyTokIdentSeen =
false;
2352 metaExpected =
true;
2356 if (!yyTokColonSeen && yyBraceDepth == namespaceDepths.size() && yyParenDepth == 1
2357 && !prospectiveContext.isEmpty()) {
2358 pendingContext = prospectiveContext;
2359 prospectiveContext.clear();
2361 yyTokIdentSeen =
false;
2362 metaExpected =
true;
2366 case Tok_QuestionMark:
2367 metaExpected =
true;
2370 case Tok_RightParen:
2371 if (yyParenDepth == 0 && !yyTokColonSeen && !pendingContext.isEmpty()
2372 && yyBraceDepth == namespaceDepths.size()) {
2374 prospectiveContext = pendingContext;
2375 pendingContext.clear();
2377 metaExpected =
true;
2383 auto initialParenDepth = yyParenDepth;
2389 while (yyParenDepth != initialParenDepth && yyTok != Tok_Eof)
2396 if (yyTok == Tok_class)
2402 if (yyTok == Tok_Colon)
2406 if (!yyParenDepth && !maybeInTrailingReturnType)
2407 prospectiveContext.clear();
2409 case Tok_RightBracket:
2417 if (yyBraceDepth != 0)
2418 yyMsg(yyBraceLineNo)
2419 <<
"Unbalanced opening brace in C++ code (or abuse of the C++ preprocessor)\n";
2420 else if (yyParenDepth != 0)
2421 yyMsg(yyParenLineNo)
2422 <<
"Unbalanced opening parenthesis in C++ code"
2423 " (or abuse of the C++ preprocessor)\n";
2424 else if (yyBracketDepth != 0)
2425 yyMsg(yyBracketLineNo)
2426 <<
"Unbalanced opening bracket in C++ code"
2427 " (or abuse of the C++ preprocessor)\n";
2432 if (!tor || !metaExpected)
2435 if (!m_metaStrings.parse(yyWord)) {
2436 yyMsg() << m_metaStrings.popError().toStdString();
2440 if (!m_metaStrings.label().isEmpty()) {
2443 if (!pendingContext.isEmpty())
2444 fullyQualify(namespaces, pendingContext,
true, &contextForLabels,
nullptr);
2446 QString context = stringifyNamespace(contextForLabels);
2451 int idx = context.lastIndexOf(
"::"_L1);
2452 className = idx >= 0 ? context.mid(idx + 2) : context;
2455 if (!m_metaStrings.resolveLabel(yyFileName, context, className))
2456 yyMsg() << m_metaStrings.popError().toStdString();
2459 if (m_metaStrings.magicComment()) {
2460 auto [context, comment] = *m_metaStrings.magicComment();
2461 TranslatorMessage msg(transcode(context), QString(), transcode(comment), QString(),
2462 yyFileName, yyLineNo, QStringList(), TranslatorMessage::Finished,
2464 msg.setExtraComment(transcode(m_metaStrings.extracomment().simplified()));
2467 m_metaStrings.clear();
2475 CppFiles::setTranslator(yyFileName, tor);
2483 if (!tor && results->includes.size() == 1
2484 && results->rootNamespace.children.isEmpty()
2485 && results->rootNamespace.aliases.isEmpty()
2486 && results->rootNamespace.usings.isEmpty()) {
2488 pr = *results->includes.cbegin();
2504 QStringConverter::Encoding e = cd.m_sourceIsUtf16 ? QStringConverter::Utf16 : QStringConverter::Utf8;
2506 for (
const QString &filename : filenames) {
2507 if (!CppFiles::getResults(ResultsCacheKey(filename)).isEmpty() || CppFiles::isBlacklisted(filename))
2510 QFile file(filename);
2511 if (!file.open(QIODevice::ReadOnly)) {
2512 cd.appendError(QStringLiteral(
"Cannot open %1: %2").arg(filename,
2513 file.errorString()));
2518 QTextStream ts(&file);
2520 ts.setAutoDetectUnicode(
true);
2521 parser.setInput(ts, filename);
2522 Translator *tor =
new Translator;
2523 parser.setTranslator(tor);
2524 QSet<QString> inclusions;
2525 parser.parse(cd, QStringList(), inclusions);
2526 parser.recordResults(isHeader(filename));
2529 for (
const QString &filename : filenames) {
2530 if (!CppFiles::isBlacklisted(filename)) {
2531 if (
const Translator *tor = CppFiles::getTranslator(filename)) {
2532 for (
const TranslatorMessage &msg : tor->messages())
2533 translator.extend(msg, cd);
static void setResults(const ResultsCacheKey &key, const ParseResults *results)
bool parseTranslate(QString &prefix)
void setInput(QTextStream &ts, const QString &fileName)
void setTranslator(Translator *_tor)
void setInput(const QString &in)
void parseInternal(ConversionData &cd, const QStringList &includeStack, QSet< QString > &inclusions)
CppParser(ParseResults *results=0)
void parse(ConversionData &cd, const QStringList &includeStack, QSet< QString > &inclusions)
const ParseResults * recordResults(bool isHeader)
void setEndOffset(int endOffset)
QHash< QString, QString > ExtraData
void setExtras(const ExtraData &extras)
void setStartOffset(int startOffset)
void setExtras(const ExtraData &extras)
void append(const TranslatorMessage &msg)
bool tryVisit(int fileId)
static bool isStringLiteralPrefix(const QStringView s)
static const QString strclass
static const QString strreturn
QDebug operator<<(QDebug debug, const HashStringList &lst)
static const QString strQCoreApplication
static const QString strQ_SIGNALS
static const QString strnamespace
static const QString strfinal
static const QString strenum
size_t qHash(const ResultsCacheKey &key, size_t seed)
static const QString strnullptr
static const QString strsignals
size_t qHash(const HashStringList &list)
static const QString strCodecForTr
static const QString strpublic
static const QString strQ_SLOTS
static const QString strUnicodeUTF8
static const QString strprotected
static const QString strLatin1
static bool isHeader(const QString &name)
static const QString strNULL
static const QString strstruct
static bool isRawStringLiteralPrefix(QStringView s)
static const QString stroperator
static const QString strusing
static const QString strQ_OBJECT
static const QString strQ_NULLPTR
size_t qHash(const HashString &str)
static const QString strQApplication
size_t qHash(const CppParserState &s, size_t seed)
static const QString strDefaultCodec
static const QString strprivate
static const QString strfriend
void loadCPP(Translator &translator, const QStringList &filenames, ConversionData &cd)
QDebug operator<<(QDebug debug, const HashString &s)
static const QString strslots
static const QString strdecltype
QHash< QString, const Translator * > TranslatorHash
QList< HashString > NamespaceList
QHash< ResultsCacheKey, IncludeCycle * > IncludeCycleHash
const HashString & segment
Namespace const ** resolvedNamespace
const NamespaceList & namespaces
QSet< HashStringList > * visitedUsings
QualifyOneData(const NamespaceList &ns, int nsc, const HashString &seg, NamespaceList *rslvd, QSet< HashStringList > *visited, Namespace const **resolvedNs)
TrFunctionAliasManager trFunctionAliasManager