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 ==
']')
926 if (yyCh == EOF || 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;
1280 return fullyQualify(namespaces, namespaces.size(),
1281 segments, isDeclaration, resolved, unresolved);
1285 const QString &quali,
bool isDeclaration,
1289 for (
const QString &str : quali.split(
"::"_L1))
1290 segments << HashString(str);
1291 return fullyQualify(namespaces, segments, isDeclaration, resolved, unresolved);
1304 nsCount = namespaces.size();
1305 visitNamespace(namespaces, nsCount, &
CppParser::findNamespaceCallback, &ns);
1311 *namespaces << name;
1313 if (!(ns = findNamespace(*namespaces)))
1314 ns = modifyNamespace(namespaces,
false);
1316 const Namespace *cns = &results->rootNamespace;
1317 for (
int i = 1; i < namespaces->size(); ++i) {
1318 ns->usings << cns->usings;
1319 if (!(cns = cns->children.value(namespaces->at(i))))
1326 if (namespaces->size() > length)
1327 namespaces->erase(namespaces->begin() + length, namespaces->end());
1332
1333
1337 seed = qHash(s.namespaces, seed);
1338 seed = qHash(s.namespaceDepths, seed);
1339 seed = qHash(s.functionContext, seed);
1340 seed = qHash(s.functionContextUnresolved, seed);
1341 seed = qHash(s.pendingContext, seed);
1347 seed = qHash(key.cleanFile, seed);
1348 seed = qHash(key.parserState, seed);
1366QSet<QString> &
CppFiles::blacklistedFiles()
1368 static QSet<QString> blacklisted;
1375 IncludeCycle *
const cycle = includeCycles().value(key);
1378 return cycle->results;
1389 includeCycles().insert(key, cycle);
1392 cycle->fileNames.insert(key.cleanFile);
1393 cycle->results.insert(results);
1398 return translatedFiles().value(cleanFile);
1403 translatedFiles().insert(cleanFile, tor);
1408 return blacklistedFiles().contains(cleanFile);
1413 blacklistedFiles().insert(cleanFile);
1419 cycle->fileNames = fileNames;
1421 QSet<IncludeCycle *> intersectingCycles;
1422 for (
const QString &fileName : fileNames) {
1423 const ResultsCacheKey key = { fileName, parserState };
1424 IncludeCycle *intersectingCycle = includeCycles().value(key);
1426 if (intersectingCycle && !intersectingCycles.contains(intersectingCycle)) {
1427 intersectingCycles.insert(intersectingCycle);
1429 cycle->fileNames.unite(intersectingCycle->fileNames);
1430 cycle->results.unite(intersectingCycle->results);
1433 qDeleteAll(intersectingCycles);
1435 for (
const QString &fileName : std::as_const(cycle->fileNames))
1436 includeCycles().insert({ fileName, parserState }, cycle);
1441 QString fileExt = QFileInfo(name).suffix();
1442 return fileExt.isEmpty() || fileExt.startsWith(u'h', Qt::CaseInsensitive);
1446 QSet<QString> &inclusions)
1448 QString cleanFile = QDir::cleanPath(file);
1450 for (
const QRegularExpression &rx : std::as_const(cd.m_excludes)) {
1451 if (rx.match(cleanFile).hasMatch())
1455 const int index = includeStack.indexOf(cleanFile);
1457 CppFiles::addIncludeCycle(QSet<QString>(includeStack.cbegin() + index, includeStack.cend()),
1466 bool isIndirect =
false;
1467 if (!CppFiles::isBlacklisted(cleanFile)
1468 && isHeader(cleanFile)) {
1470 QSet<
const ParseResults *> res = CppFiles::getResults(ResultsCacheKey(cleanFile, *
this));
1471 if (!res.isEmpty()) {
1472 results->includes.unite(res);
1480 if (!f.open(QIODevice::ReadOnly)) {
1481 yyMsg() << qPrintable(
1482 QStringLiteral(
"Cannot open %1: %2\n").arg(cleanFile, f.errorString()));
1487 ts.setEncoding(yySourceEncoding);
1488 ts.setAutoDetectUnicode(
true);
1490 inclusions.insert(cleanFile);
1493 for (
const QString &projectRoot : std::as_const(cd.m_projectRoots))
1494 if (cleanFile.startsWith(projectRoot)) {
1495 parser.setTranslator(
new Translator);
1498 parser.setInput(ts, cleanFile);
1499 QStringList stack = includeStack;
1501 parser.parse(cd, stack, inclusions);
1505 parser.namespaces = namespaces;
1506 parser.functionContext = functionContext;
1507 parser.functionContextUnresolved = functionContextUnresolved;
1508 parser.setInput(ts, cleanFile);
1510 QStringList stack = includeStack;
1512 parser.parseInternal(cd, stack, inclusions);
1514 CppFiles::setBlacklisted(cleanFile);
1516 inclusions.remove(cleanFile);
1518 prospectiveContext.clear();
1519 pendingContext.clear();
1523
1524
1525
1526
1527
1528
1529
1530
1534 bool matches = (yyTok == t);
1542 bool matches =
false;
1545 if (yyTok != Tok_String && yyTok != Tok_RawString)
1548 if (yyTok == Tok_String)
1549 *s += transcode(yyWord);
1566 if (yyTok != Tok_Ident)
1568 if (yyWord == strQApplication || yyWord == strQCoreApplication) {
1570 if (yyTok == Tok_ColonColon)
1573 if (yyWord == strUnicodeUTF8) {
1577 if (yyWord == strLatin1 || yyWord == strDefaultCodec || yyWord == strCodecForTr)
1578 yyMsg() <<
"Unsupported encoding Latin1/DefaultCodec/CodecForTr\n";
1582bool CppParser::matchStringOrNull(QString *s)
1584 return matchString(s) || match(Tok_Null);
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1600 if (match(Tok_Null) || match(Tok_Integer))
1604 while (parenlevel >= 0) {
1606 if (yyTok == Tok_RightParen)
1608 else if (yyTok == Tok_LeftParen)
1610 else if (yyTok == Tok_Cancel || yyTok == Tok_Eof)
1616void CppParser::recordMessage(
int line,
const QString &context,
const QString &text,
1617 const QString &comment,
const QString &extracomment,
1618 const QString &msgid,
const QString &label,
1620 bool plural,
int startOffset,
int endOffset)
1622 TranslatorMessage msg(transcode(context), text, transcode(comment), QString(), yyFileName, line,
1623 QStringList(), TranslatorMessage::Unfinished, plural);
1624 msg.setExtraComment(transcode(extracomment.simplified()));
1627 if (!msgid.isEmpty())
1628 msg.setLabel(label);
1634void CppParser::handleTr(QString &prefix,
bool plural)
1636 if (!m_metaStrings.sourcetext().isEmpty())
1637 yyMsg() <<
"//% cannot be used with tr() / QT_TR_NOOP(). Ignoring\n";
1638 if (!m_metaStrings.label().isEmpty())
1639 yyMsg() <<
"labels cannot be used with text-based translation. Ignoring\n";
1641 int line = yyLineNo;
1642 const int startOffset = lookBackFunctionCallStart(prefix.size());
1645 if (matchString(&text)) {
1647 if (yyTok == Tok_RightParen) {
1649 }
else if (match(Tok_Comma) && matchStringOrNull(&comment)) {
1650 if (yyTok == Tok_RightParen) {
1652 }
else if (match(Tok_Comma)) {
1657 if (!pendingContext.isEmpty() && !prefix.startsWith(
"::"_L1)) {
1659 if (!fullyQualify(namespaces, pendingContext,
true, &functionContext, &unresolved)) {
1660 functionContextUnresolved = stringifyNamespace(0, unresolved);
1661 yyMsg() << qPrintable(
1662 QStringLiteral(
"Qualifying with unknown namespace/class %1::%2\n")
1663 .arg(stringifyNamespace(functionContext)).arg(unresolved.first().value()));
1665 pendingContext.clear();
1667 if (prefix.isEmpty()) {
1668 if (functionContextUnresolved.isEmpty()) {
1669 int idx = functionContext.size();
1671 yyMsg() <<
"tr() cannot be called without context\n";
1675 while (!(fctx = findNamespace(functionContext, idx)->classDef)->hasTrFunctions) {
1677 context = stringifyNamespace(functionContext);
1678 fctx = findNamespace(functionContext)->classDef;
1680 yyMsg() << qPrintable(
1681 QStringLiteral(
"Class '%1' lacks Q_OBJECT macro\n").arg(context));
1688 if (fctx->trQualification.isEmpty()) {
1691 context += functionContext.at(i).value();
1696 fctx->trQualification = context;
1698 context = fctx->trQualification;
1701 context = joinNamespaces(stringifyNamespace(functionContext), functionContextUnresolved);
1707 if (fullyQualify(functionContext, prefix,
false, &nsl, &unresolved)) {
1709 if (fctx->trQualification.isEmpty()) {
1710 context = stringifyNamespace(nsl);
1711 fctx->trQualification = context;
1713 context = fctx->trQualification;
1716 yyMsg() << qPrintable(QStringLiteral(
"Class '%1' lacks Q_OBJECT macro\n")
1721 context = joinNamespaces(stringifyNamespace(nsl), stringifyNamespace(0, unresolved));
1727 const int endOffset = yyInPtr - (
const ushort *)yyInStr.unicode() - 1;
1728 recordMessage(line, context, text, comment, m_metaStrings.extracomment(),
1729 m_metaStrings.msgid(), QString(), m_metaStrings.extra(),
1730 plural, startOffset, endOffset);
1732 m_metaStrings.clear();
1735void CppParser::handleTranslate(
int prefixSize,
bool plural)
1737 if (!m_metaStrings.sourcetext().isEmpty())
1738 yyMsg() <<
"//% cannot be used with translate() / QT_TRANSLATE_NOOP(). Ignoring\n";
1739 if (!m_metaStrings.label().isEmpty())
1740 yyMsg() <<
"labels cannot be used with text-based translation. Ignoring\n";
1741 const int startOffset = lookBackFunctionCallStart(prefixSize);
1742 int line = yyLineNo;
1745 if (matchString(&context)
1747 && matchString(&text) && !text.isEmpty())
1750 if (yyTok != Tok_RightParen) {
1752 if (match(Tok_Comma) && matchStringOrNull(&comment)) {
1753 if (yyTok != Tok_RightParen) {
1755 if (match(Tok_Comma)) {
1756 if (matchEncoding()) {
1757 if (yyTok != Tok_RightParen) {
1764 plural |= match(Tok_Comma);
1769 if (skipExpression() && yyTok == Tok_RightParen) {
1783 const int endOffset = yyInPtr - (
const ushort *)yyInStr.unicode() - 1;
1785 recordMessage(line, context, text, comment, m_metaStrings.extracomment(),
1786 m_metaStrings.msgid(), QString(), m_metaStrings.extra(),
1787 plural, startOffset, endOffset);
1789 m_metaStrings.clear();
1792void CppParser::handleTrId(
int prefixSize,
bool plural)
1794 if (!m_metaStrings.msgid().isEmpty())
1795 yyMsg() <<
"//= cannot be used with qtTrId() / QT_TRID_NOOP(). Ignoring\n";
1796 int line = yyLineNo;
1797 const int startOffset = lookBackFunctionCallStart(prefixSize);
1800 if (matchString(&msgid) && !msgid.isEmpty()) {
1801 plural |= match(Tok_Comma);
1802 const int endOffset = yyInPtr - (
const ushort *)yyInStr.unicode() - 1;
1804 recordMessage(line, QString(), transcode(m_metaStrings.sourcetext()), QString(),
1805 m_metaStrings.extracomment(), msgid, m_metaStrings.label(),
1806 m_metaStrings.extra(), plural, startOffset, endOffset);
1808 m_metaStrings.clear();
1811void CppParser::handleDeclareTrFunctions()
1816 if (yyTok != Tok_Ident)
1821 if (yyTok == Tok_RightParen)
1823 if (yyTok != Tok_ColonColon)
1827 Namespace *ns = modifyNamespace(&namespaces);
1828 ns->hasTrFunctions =
true;
1829 ns->trQualification = name;
1830 ns->trQualification.detach();
1834 QSet<QString> &inclusions)
1836 namespaces << HashString();
1837 functionContext = namespaces;
1838 functionContextUnresolved.clear();
1840 parseInternal(cd, includeStack, inclusions);
1843int CppParser::lookBackFunctionCallStart(
int prefixSize)
1845 const int funcNameOffset = yyInPtr - (
const ushort *)yyInStr.unicode();
1846 QStringView prefix = QStringView(yyInStr).sliced(0, funcNameOffset);
1849 while (prefix.back() !=
'('_L1);
1850 prefix.chop(prefixSize + yyWord.size() + 1);
1852 auto chopMatch = [](
auto& str,
const auto& match) {
1853 if (str.endsWith(match)) {
1854 str.chop(match.size());
1859 while (chopMatch(prefix,
"."_L1) || chopMatch(prefix,
"->"_L1)) {
1860 int pos = prefix.size() - 1;
1861 if (prefix.at(pos) ==
')'_L1) {
1864 while (count != 0 && pos >= 0) {
1865 if (QChar c = prefix.at(pos--); c ==
')'_L1)
1867 else if (c ==
'('_L1)
1869 else if (c ==
"\""_L1 || c ==
"'"_L1) {
1870 const QChar quotation = c;
1875 else if (c == quotation)
1881 while (pos >= 0 && (prefix.at(pos).isLetterOrNumber() || prefix.at(pos) ==
'_'_L1))
1883 prefix.slice(0, pos + 1);
1885 return prefix.size();
1890 bool forcePlural =
false;
1892 case TrFunctionAliasManager::Function_Q_DECLARE_TR_FUNCTIONS:
1893 handleDeclareTrFunctions();
1895 case TrFunctionAliasManager::Function_QT_TR_N_NOOP:
1898 case TrFunctionAliasManager::Function_tr:
1899 case TrFunctionAliasManager::Function_trUtf8:
1900 case TrFunctionAliasManager::Function_QT_TR_NOOP:
1901 case TrFunctionAliasManager::Function_QT_TR_NOOP_UTF8:
1903 handleTr(prefix, forcePlural);
1905 case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP:
1906 case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP3:
1909 case TrFunctionAliasManager::Function_translate:
1910 case TrFunctionAliasManager::Function_findMessage:
1911 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP:
1912 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP_UTF8:
1913 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3:
1914 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3_UTF8:
1916 handleTranslate(prefix.size(), forcePlural);
1918 case TrFunctionAliasManager::Function_QT_TRID_N_NOOP:
1921 case TrFunctionAliasManager::Function_qtTrId:
1922 case TrFunctionAliasManager::Function_QT_TRID_NOOP:
1924 handleTrId(prefix.size(), forcePlural);
1933 QSet<QString> &inclusions)
1935 static constexpr auto strColons(
"::"_L1);
1938 bool yyTokColonSeen =
false;
1939 bool yyTokIdentSeen =
false;
1940 bool maybeInTrailingReturnType =
false;
1942 const QList<TokenType> allowedTokensInFnTemplate{
1943 Tok_Ident, Tok_decltype, Tok_ColonColon, Tok_Comma,
1944 Tok_Integer, Tok_LeftAngleBracket, Tok_RightAngleBracket
1946 metaExpected =
true;
1948 prospectiveContext.clear();
1949 pendingContext.clear();
1951 yyWord.reserve(yyInStr.size());
1952 yyWordInitialCapacity = yyWord.capacity();
1953 yyInPtr = (
const ushort *)yyInStr.unicode();
1956 while (yyTok != Tok_Eof) {
1961 if (yyBracketDepth && yyBraceDepth == namespaceDepths.size()) {
1967 case Tok_QuotedInclude: {
1968 QString text = QDir(QFileInfo(yyFileName).absolutePath()).absoluteFilePath(yyWord);
1970 if (QFileInfo(text).isFile()) {
1971 processInclude(text, cd, includeStack, inclusions);
1977 case Tok_AngledInclude: {
1978 const QStringList cSources = cd.m_allCSources.values(yyWord);
1979 if (!cSources.isEmpty()) {
1980 for (
const QString &cSource : cSources)
1981 processInclude(cSource, cd, includeStack, inclusions);
1984 for (
const QString &incPath : std::as_const(cd.m_includePath)) {
1985 QString text = QDir(incPath).absoluteFilePath(yyWord);
1987 if (QFileInfo(text).isFile()) {
1988 processInclude(text, cd, includeStack, inclusions);
1999 if (yyTok == Tok_class)
2004
2005
2009 if (yyTok == Tok_Equals) {
2012 }
else if (yyBraceDepth == namespaceDepths.size() && yyParenDepth == 0) {
2018 QString text = yyWord;
2023 if (yyTok == Tok_ColonColon) {
2026 }
else if (yyTok == Tok_Ident) {
2027 if (yyWord == strfinal) {
2037 }
else if (yyTok == Tok_Attribute) {
2044 if (yyTok == Tok_Colon || yyTok == Tok_LeftAngleBracket) {
2050 if (yyTok == Tok_Eof)
2052 if (yyTok == Tok_Cancel)
2054 if (yyTok == Tok_class)
2056 if (yyTok == Tok_Ident) {
2058 if (yyTok == Tok_LeftParen)
2059 parseTranslate(prefix);
2061 goto tokenInTemplate;
2063 }
while (yyTok != Tok_LeftBrace && yyTok != Tok_Semicolon);
2064 if (yyTok == Tok_Semicolon)
2067 if (yyTok != Tok_LeftBrace) {
2074 if (!quali.isEmpty()) {
2077 if (!fullyQualify(namespaces, quali,
true, &nsl, 0)) {
2078 yyMsg() <<
"Ignoring definition of undeclared qualified class\n";
2081 namespaceDepths.push(namespaces.size());
2084 namespaceDepths.push(namespaces.size());
2086 enterNamespace(&namespaces, fct);
2089 Namespace *ns = modifyNamespace(&namespaces);
2092 functionContext = namespaces;
2093 functionContextUnresolved.clear();
2094 prospectiveContext.clear();
2095 pendingContext.clear();
2097 metaExpected =
true;
2104 while (yyTok == Tok_Attribute)
2106 if (yyTok == Tok_Ident) {
2107 QString text = yyWord;
2113 if (yyTok != Tok_ColonColon)
2116 if (yyTok != Tok_Ident)
2118 nestedNamespaces.append(ns);
2121 ns = HashString(text);
2123 if (yyTok == Tok_LeftBrace) {
2124 namespaceDepths.push(namespaces.size());
2125 for (
const auto &nns : nestedNamespaces)
2126 enterNamespace(&namespaces, nns);
2127 enterNamespace(&namespaces, ns);
2129 functionContext = namespaces;
2130 functionContextUnresolved.clear();
2131 prospectiveContext.clear();
2132 pendingContext.clear();
2133 metaExpected =
true;
2135 }
else if (yyTok == Tok_Equals) {
2138 NamespaceList fullName;
2140 if (yyTok == Tok_ColonColon)
2141 fullName.append(HashString(QString()));
2142 while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) {
2143 if (yyTok == Tok_Ident) {
2146 fullName.append(HashString(text));
2150 if (fullName.isEmpty())
2152 fullName.append(HashString(QString()));
2153 modifyNamespace(&namespaces)->aliases[ns] = fullName;
2155 }
else if (yyTok == Tok_LeftBrace) {
2157 namespaceDepths.push(namespaces.size());
2158 metaExpected =
true;
2165 if (yyTok == Tok_namespace) {
2168 if (yyTok == Tok_ColonColon)
2170 while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) {
2171 if (yyTok == Tok_Ident) {
2172 QString text = yyWord;
2179 if (fullyQualify(namespaces, fullName,
false, &nsl, 0))
2180 modifyNamespace(&namespaces)->usings << HashStringList(nsl);
2183 if (yyTok == Tok_ColonColon)
2185 while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) {
2186 if (yyTok == Tok_Ident) {
2187 QString text = yyWord;
2193 if (fullName.isEmpty())
2200 const HashString &ns = *(fullName.constEnd() - 2);
2201 modifyNamespace(&namespaces)->aliases[ns] = fullName;
2205 modifyNamespace(&namespaces)->hasTrFunctions =
true;
2209 if (yyTokColonSeen &&
2210 yyBraceDepth == namespaceDepths.size() && yyParenDepth == 0) {
2212 yyTokIdentSeen =
true;
2216 bool methodSpecialization =
false;
2217 if (yyTok == Tok_LeftAngleBracket) {
2222 while (count && allowedTokensInFnTemplate.contains(yyTok)) {
2223 if (yyTok == Tok_LeftAngleBracket)
2225 else if (yyTok == Tok_RightAngleBracket)
2229 methodSpecialization = count == 0;
2231 if (yyTok == Tok_LeftParen) {
2232 if (parseTranslate(prefix)) {
2239 if (yyTok == Tok_ColonColon && !maybeInTrailingReturnType && !yyTrailingSpace) {
2240 prefix += methodSpecialization ? className : yyWord;
2244 if (!prefix.isEmpty() && yyTok != Tok_LeftParen && yyTok != Tok_RightParen
2245 && yyTok != Tok_LeftBracket && yyTok != Tok_Equals) {
2248 prospectiveContext.clear();
2252 metaExpected =
false;
2256 if (yyParenDepth == 0 && yyBraceDepth == namespaceDepths.size())
2257 maybeInTrailingReturnType =
true;
2259 if (yyTok == Tok_Ident) {
2261 if (yyTok == Tok_LeftParen) {
2263 case TrFunctionAliasManager::Function_tr:
2264 case TrFunctionAliasManager::Function_trUtf8:
2265 yyMsg() <<
"Cannot invoke tr() like this\n";
2271 case Tok_ColonColon:
2272 if (yyTokIdentSeen || maybeInTrailingReturnType) {
2277 if (yyBraceDepth == namespaceDepths.size() && yyParenDepth == 0 && !yyTokColonSeen)
2278 prospectiveContext = prefix;
2279 if (!prefix.isEmpty())
2280 prefix += strColons;
2283 case Tok_RightBrace:
2284 if (!yyTokColonSeen) {
2285 if (yyBraceDepth + 1 == namespaceDepths.size()) {
2287 truncateNamespaces(&namespaces, namespaceDepths.pop());
2289 if (yyBraceDepth == namespaceDepths.size()) {
2291 if (!yyBraceDepth && !directInclude)
2292 truncateNamespaces(&functionContext, 1);
2294 functionContext = namespaces;
2295 functionContextUnresolved.clear();
2296 pendingContext.clear();
2301 maybeInTrailingReturnType =
false;
2302 prospectiveContext.clear();
2304 if (m_metaStrings.hasData()) {
2305 yyMsg() <<
"Discarding unconsumed meta data\n";
2306 m_metaStrings.clear();
2308 metaExpected =
true;
2315 }
while (yyTok == Tok_Access);
2316 metaExpected =
true;
2317 if (yyTok == Tok_Colon)
2322 if (yyBraceDepth == namespaceDepths.size() && yyParenDepth == 0) {
2323 if (!prospectiveContext.isEmpty()) {
2324 pendingContext = prospectiveContext;
2325 prospectiveContext.clear();
2328 if (yyTok == Tok_Colon) {
2329 if (lookAheadToSemicolonOrLeftBrace() != Tok_Semicolon)
2330 yyTokColonSeen =
true;
2333 metaExpected =
true;
2337 if (yyBraceDepth == namespaceDepths.size() + 1 && yyParenDepth == 0) {
2338 if (!prospectiveContext.isEmpty()) {
2339 pendingContext = prospectiveContext;
2340 prospectiveContext.clear();
2342 if (!yyTokIdentSeen) {
2344 yyTokColonSeen =
false;
2347 maybeInTrailingReturnType =
false;
2348 yyTokIdentSeen =
false;
2349 metaExpected =
true;
2353 if (!yyTokColonSeen && yyBraceDepth == namespaceDepths.size() && yyParenDepth == 1
2354 && !prospectiveContext.isEmpty()) {
2355 pendingContext = prospectiveContext;
2356 prospectiveContext.clear();
2358 yyTokIdentSeen =
false;
2359 metaExpected =
true;
2363 case Tok_QuestionMark:
2364 metaExpected =
true;
2367 case Tok_RightParen:
2368 if (yyParenDepth == 0 && !yyTokColonSeen && !pendingContext.isEmpty()
2369 && yyBraceDepth == namespaceDepths.size()) {
2371 prospectiveContext = pendingContext;
2372 pendingContext.clear();
2374 metaExpected =
true;
2380 auto initialParenDepth = yyParenDepth;
2386 while (yyParenDepth != initialParenDepth && yyTok != Tok_Eof)
2393 if (yyTok == Tok_class)
2399 if (yyTok == Tok_Colon)
2403 if (!yyParenDepth && !maybeInTrailingReturnType)
2404 prospectiveContext.clear();
2406 case Tok_RightBracket:
2414 if (yyBraceDepth != 0)
2415 yyMsg(yyBraceLineNo)
2416 <<
"Unbalanced opening brace in C++ code (or abuse of the C++ preprocessor)\n";
2417 else if (yyParenDepth != 0)
2418 yyMsg(yyParenLineNo)
2419 <<
"Unbalanced opening parenthesis in C++ code"
2420 " (or abuse of the C++ preprocessor)\n";
2421 else if (yyBracketDepth != 0)
2422 yyMsg(yyBracketLineNo)
2423 <<
"Unbalanced opening bracket in C++ code"
2424 " (or abuse of the C++ preprocessor)\n";
2429 if (!tor || !metaExpected)
2432 if (!m_metaStrings.parse(yyWord)) {
2433 yyMsg() << m_metaStrings.popError().toStdString();
2437 if (!m_metaStrings.label().isEmpty()) {
2440 if (!pendingContext.isEmpty())
2441 fullyQualify(namespaces, pendingContext,
true, &contextForLabels,
nullptr);
2443 QString context = stringifyNamespace(contextForLabels);
2448 int idx = context.lastIndexOf(
"::"_L1);
2449 className = idx >= 0 ? context.mid(idx + 2) : context;
2452 if (!m_metaStrings.resolveLabel(yyFileName, context, className))
2453 yyMsg() << m_metaStrings.popError().toStdString();
2456 if (m_metaStrings.magicComment()) {
2457 auto [context, comment] = *m_metaStrings.magicComment();
2458 TranslatorMessage msg(transcode(context), QString(), transcode(comment), QString(),
2459 yyFileName, yyLineNo, QStringList(), TranslatorMessage::Finished,
2461 msg.setExtraComment(transcode(m_metaStrings.extracomment().simplified()));
2464 m_metaStrings.clear();
2472 CppFiles::setTranslator(yyFileName, tor);
2480 if (!tor && results->includes.size() == 1
2481 && results->rootNamespace.children.isEmpty()
2482 && results->rootNamespace.aliases.isEmpty()
2483 && results->rootNamespace.usings.isEmpty()) {
2485 pr = *results->includes.cbegin();
2501 QStringConverter::Encoding e = cd.m_sourceIsUtf16 ? QStringConverter::Utf16 : QStringConverter::Utf8;
2503 for (
const QString &filename : filenames) {
2504 if (!CppFiles::getResults(ResultsCacheKey(filename)).isEmpty() || CppFiles::isBlacklisted(filename))
2507 QFile file(filename);
2508 if (!file.open(QIODevice::ReadOnly)) {
2509 cd.appendError(QStringLiteral(
"Cannot open %1: %2").arg(filename,
2510 file.errorString()));
2515 QTextStream ts(&file);
2517 ts.setAutoDetectUnicode(
true);
2518 parser.setInput(ts, filename);
2519 Translator *tor =
new Translator;
2520 parser.setTranslator(tor);
2521 QSet<QString> inclusions;
2522 parser.parse(cd, QStringList(), inclusions);
2523 parser.recordResults(isHeader(filename));
2526 for (
const QString &filename : filenames) {
2527 if (!CppFiles::isBlacklisted(filename)) {
2528 if (
const Translator *tor = CppFiles::getTranslator(filename)) {
2529 for (
const TranslatorMessage &msg : tor->messages())
2530 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