Commit c6358e5d authored by Nikolai Kosjar's avatar Nikolai Kosjar

C++: Add utf16 indices to Macro and Document::MacroUse

In most cases we need to work with the utf16 indices. Only in
cppfindreferences the byte interface is still needed since there we read
in files and work on a QByteArray to save memory.

Change-Id: I6ef6a93fc1875a8c9a305c075d51a9ca034c41bb
Reviewed-by: default avatarErik Verbruggen <erik.verbruggen@digia.com>
parent bb7da966
......@@ -36,6 +36,21 @@ using namespace CPlusPlus;
\sa Token
*/
/*!
\fn static void Lexer::yyinp_utf8(const char *&currentSourceChar, unsigned char &yychar, unsigned &utf16charCounter)
Process a single unicode code point in an UTF-8 encoded source.
\a currentSourceChar points to the UTF-8 encoded source.
\a yychar must be the byte pointed to by \a currentSourceChar.
Points \a currentSourceChar to the byte of the next code point
and modifies \a yychar to the value pointed by the updated
\a currentSourceChar. \a utf16charCounter will be incremented by
the number of UTF-16 code units that were needed for that code
point.
*/
Lexer::Lexer(TranslationUnit *unit)
: _translationUnit(unit),
_control(unit->control()),
......
......@@ -61,6 +61,28 @@ public:
LanguageFeatures languageFeatures() const { return _languageFeatures; }
void setLanguageFeatures(LanguageFeatures features) { _languageFeatures = features; }
public:
static void yyinp_utf8(const char *&currentSourceChar, unsigned char &yychar,
unsigned &utf16charCounter)
{
++utf16charCounter;
// Process multi-byte UTF-8 code point (non-latin1)
if (CPLUSPLUS_UNLIKELY(isByteOfMultiByteCodePoint(yychar))) {
unsigned trailingBytesCurrentCodePoint = 1;
for (unsigned char c = yychar << 2; isByteOfMultiByteCodePoint(c); c <<= 1)
++trailingBytesCurrentCodePoint;
// Code points >= 0x00010000 are represented by two UTF-16 code units
if (trailingBytesCurrentCodePoint >= 3)
++utf16charCounter;
yychar = *(currentSourceChar += trailingBytesCurrentCodePoint + 1);
// Process single-byte UTF-8 code point (latin1)
} else {
yychar = *++currentSourceChar;
}
}
private:
void pushLineStartOffset();
void scan_helper(Token *tok);
......@@ -83,23 +105,7 @@ private:
void yyinp()
{
++_currentCharUtf16;
// Process multi-byte UTF-8 code point (non-latin1)
if (CPLUSPLUS_UNLIKELY(isByteOfMultiByteCodePoint(_yychar))) {
unsigned trailingBytesCurrentCodePoint = 1;
for (unsigned char c = _yychar << 2; isByteOfMultiByteCodePoint(c); c <<= 1)
++trailingBytesCurrentCodePoint;
// Code points >= 0x00010000 are represented by two UTF16 code units
if (trailingBytesCurrentCodePoint >= 3)
++_currentCharUtf16;
_yychar = *(_currentChar += trailingBytesCurrentCodePoint + 1);
// Process single-byte UTF-8 code point (latin1)
} else {
_yychar = *++_currentChar;
}
yyinp_utf8(_currentChar, _yychar, _currentCharUtf16);
if (CPLUSPLUS_UNLIKELY(_yychar == '\n'))
pushLineStartOffset();
}
......
......@@ -264,7 +264,7 @@ void TranslationUnit::tokenize()
currentExpanded = true;
const std::pair<unsigned, unsigned> &p = lineColumn[lineColumnIdx];
if (p.first)
_expandedLineColumn.insert(std::make_pair(tk.bytesBegin(), p));
_expandedLineColumn.insert(std::make_pair(tk.utf16charsBegin(), p));
else
currentGenerated = true;
......
......@@ -365,25 +365,31 @@ void Document::appendMacro(const Macro &macro)
_definedMacros.append(macro);
}
void Document::addMacroUse(const Macro &macro, unsigned offset, unsigned length,
void Document::addMacroUse(const Macro &macro,
unsigned bytesOffset, unsigned bytesLength,
unsigned utf16charsOffset, unsigned utf16charLength,
unsigned beginLine,
const QVector<MacroArgumentReference> &actuals)
{
MacroUse use(macro, offset, offset + length, beginLine);
MacroUse use(macro,
bytesOffset, bytesOffset + bytesLength,
utf16charsOffset, utf16charsOffset + utf16charLength,
beginLine);
foreach (const MacroArgumentReference &actual, actuals) {
const Block arg(actual.position(), actual.position() + actual.length());
const Block arg(0, 0, actual.utf16charsOffset(),
actual.utf16charsOffset() + actual.utf16charsLength());
use.addArgument(arg);
}
_macroUses.append(use);
}
void Document::addUndefinedMacroUse(const QByteArray &name, unsigned offset)
void Document::addUndefinedMacroUse(const QByteArray &name,
unsigned bytesOffset, unsigned utf16charsOffset)
{
QByteArray copy(name.data(), name.size());
UndefinedMacroUse use(copy, offset);
UndefinedMacroUse use(copy, bytesOffset, utf16charsOffset);
_undefinedMacroUses.append(use);
}
......@@ -548,19 +554,23 @@ const Macro *Document::findMacroDefinitionAt(unsigned line) const
return 0;
}
const Document::MacroUse *Document::findMacroUseAt(unsigned offset) const
const Document::MacroUse *Document::findMacroUseAt(unsigned utf16charsOffset) const
{
foreach (const Document::MacroUse &use, _macroUses) {
if (use.contains(offset) && (offset < use.begin() + use.macro().name().length()))
if (use.containsUtf16charOffset(utf16charsOffset)
&& (utf16charsOffset < use.utf16charsBegin() + use.macro().nameToQString().size())) {
return &use;
}
}
return 0;
}
const Document::UndefinedMacroUse *Document::findUndefinedMacroUseAt(unsigned offset) const
const Document::UndefinedMacroUse *Document::findUndefinedMacroUseAt(unsigned utf16charsOffset) const
{
foreach (const Document::UndefinedMacroUse &use, _undefinedMacroUses) {
if (use.contains(offset) && (offset < use.begin() + use.name().length()))
if (use.containsUtf16charOffset(utf16charsOffset)
&& (utf16charsOffset < use.utf16charsBegin()
+ QString::fromUtf8(use.name(), use.name().size()).length()))
return &use;
}
return 0;
......@@ -581,21 +591,21 @@ void Document::setUtf8Source(const QByteArray &source)
_translationUnit->setSource(_source.constBegin(), _source.size());
}
void Document::startSkippingBlocks(unsigned start)
void Document::startSkippingBlocks(unsigned utf16charsOffset)
{
_skippedBlocks.append(Block(start, 0));
_skippedBlocks.append(Block(0, 0, utf16charsOffset, 0));
}
void Document::stopSkippingBlocks(unsigned stop)
void Document::stopSkippingBlocks(unsigned utf16charsOffset)
{
if (_skippedBlocks.isEmpty())
return;
unsigned start = _skippedBlocks.back().begin();
if (start > stop)
unsigned start = _skippedBlocks.back().utf16charsBegin();
if (start > utf16charsOffset)
_skippedBlocks.removeLast(); // Ignore this block, it's invalid.
else
_skippedBlocks.back() = Block(start, stop);
_skippedBlocks.back() = Block(0, 0, start, utf16charsOffset);
}
bool Document::isTokenized() const
......
......@@ -77,10 +77,12 @@ public:
QString fileName() const;
void appendMacro(const Macro &macro);
void addMacroUse(const Macro &macro, unsigned offset, unsigned length,
unsigned beginLine,
const QVector<MacroArgumentReference> &range);
void addUndefinedMacroUse(const QByteArray &name, unsigned offset);
void addMacroUse(const Macro &macro,
unsigned bytesOffset, unsigned bytesLength,
unsigned utf16charsOffset, unsigned utf16charLength,
unsigned beginLine, const QVector<MacroArgumentReference> &range);
void addUndefinedMacroUse(const QByteArray &name,
unsigned bytesOffset, unsigned utf16charsOffset);
Control *control() const;
TranslationUnit *translationUnit() const;
......@@ -108,8 +110,8 @@ public:
void setFingerprint(const QByteArray &fingerprint)
{ m_fingerprint = fingerprint; }
void startSkippingBlocks(unsigned offset);
void stopSkippingBlocks(unsigned offset);
void startSkippingBlocks(unsigned utf16charsOffset);
void stopSkippingBlocks(unsigned utf16charsOffset);
enum ParseMode { // ### keep in sync with CPlusPlus::TranslationUnit
ParseTranlationUnit,
......@@ -207,22 +209,34 @@ public:
class Block
{
unsigned _begin;
unsigned _end;
unsigned _bytesBegin;
unsigned _bytesEnd;
unsigned _utf16charsBegin;
unsigned _utf16charsEnd;
public:
inline Block(unsigned begin = 0, unsigned end = 0)
: _begin(begin), _end(end)
{ }
inline Block(unsigned bytesBegin = 0, unsigned bytesEnd = 0,
unsigned utf16charsBegin = 0, unsigned utf16charsEnd = 0)
: _bytesBegin(bytesBegin),
_bytesEnd(bytesEnd),
_utf16charsBegin(utf16charsBegin),
_utf16charsEnd(utf16charsEnd)
{}
inline unsigned bytesBegin() const
{ return _bytesBegin; }
inline unsigned bytesEnd() const
{ return _bytesEnd; }
inline unsigned begin() const
{ return _begin; }
inline unsigned utf16charsBegin() const
{ return _utf16charsBegin; }
inline unsigned end() const
{ return _end; }
inline unsigned utf16charsEnd() const
{ return _utf16charsEnd; }
bool contains(unsigned pos) const
{ return pos >= _begin && pos < _end; }
bool containsUtf16charOffset(unsigned utf16charOffset) const
{ return utf16charOffset >= _utf16charsBegin && utf16charOffset < _utf16charsEnd; }
};
class Include {
......@@ -259,8 +273,11 @@ public:
unsigned _beginLine;
public:
inline MacroUse(const Macro &macro, unsigned begin, unsigned end, unsigned beginLine)
: Block(begin, end),
inline MacroUse(const Macro &macro,
unsigned bytesBegin, unsigned bytesEnd,
unsigned utf16charsBegin, unsigned utf16charsEnd,
unsigned beginLine)
: Block(bytesBegin, bytesEnd, utf16charsBegin, utf16charsEnd),
_macro(macro),
_beginLine(beginLine)
{ }
......@@ -293,8 +310,12 @@ public:
public:
inline UndefinedMacroUse(
const QByteArray &name,
unsigned begin)
: Block(begin, begin + name.length()),
unsigned bytesBegin,
unsigned utf16charsBegin)
: Block(bytesBegin,
bytesBegin + name.length(),
utf16charsBegin,
utf16charsBegin + QString::fromUtf8(name, name.size()).size()),
_name(name)
{ }
......@@ -328,8 +349,8 @@ public:
{ return _includeGuardMacroName; }
const Macro *findMacroDefinitionAt(unsigned line) const;
const MacroUse *findMacroUseAt(unsigned offset) const;
const UndefinedMacroUse *findUndefinedMacroUseAt(unsigned offset) const;
const MacroUse *findMacroUseAt(unsigned utf16charsOffset) const;
const UndefinedMacroUse *findUndefinedMacroUseAt(unsigned utf16charsOffset) const;
void keepSourceAndAST();
void releaseSourceAndAST();
......
......@@ -108,37 +108,45 @@ static const Macro revision(const Snapshot &s, const Macro &m)
return m;
}
void FastPreprocessor::passedMacroDefinitionCheck(unsigned offset, unsigned line, const Macro &macro)
void FastPreprocessor::passedMacroDefinitionCheck(unsigned bytesOffset, unsigned utf16charsOffset,
unsigned line, const Macro &macro)
{
Q_ASSERT(_currentDoc);
_currentDoc->addMacroUse(revision(_snapshot, macro),
offset, macro.name().length(), line,
QVector<MacroArgumentReference>());
bytesOffset, macro.name().size(),
utf16charsOffset, macro.nameToQString().size(),
line, QVector<MacroArgumentReference>());
}
void FastPreprocessor::failedMacroDefinitionCheck(unsigned offset, const ByteArrayRef &name)
void FastPreprocessor::failedMacroDefinitionCheck(unsigned bytesOffset, unsigned utf16charsOffset,
const ByteArrayRef &name)
{
Q_ASSERT(_currentDoc);
_currentDoc->addUndefinedMacroUse(QByteArray(name.start(), name.size()), offset);
_currentDoc->addUndefinedMacroUse(QByteArray(name.start(), name.size()),
bytesOffset, utf16charsOffset);
}
void FastPreprocessor::notifyMacroReference(unsigned offset, unsigned line, const Macro &macro)
void FastPreprocessor::notifyMacroReference(unsigned bytesOffset, unsigned utf16charsOffset,
unsigned line, const Macro &macro)
{
Q_ASSERT(_currentDoc);
_currentDoc->addMacroUse(revision(_snapshot, macro),
offset, macro.name().length(), line,
QVector<MacroArgumentReference>());
bytesOffset, macro.name().size(),
utf16charsOffset, macro.nameToQString().size(),
line, QVector<MacroArgumentReference>());
}
void FastPreprocessor::startExpandingMacro(unsigned offset, unsigned line,
const Macro &macro,
const QVector<MacroArgumentReference> &actuals)
void FastPreprocessor::startExpandingMacro(unsigned bytesOffset, unsigned utf16charsOffset,
unsigned line, const Macro &macro,
const QVector<MacroArgumentReference> &actuals)
{
Q_ASSERT(_currentDoc);
_currentDoc->addMacroUse(revision(_snapshot, macro),
offset, macro.name().length(), line, actuals);
bytesOffset, macro.name().size(),
utf16charsOffset, macro.nameToQString().size(),
line, actuals);
}
......@@ -61,12 +61,13 @@ public:
virtual void macroAdded(const Macro &);
virtual void passedMacroDefinitionCheck(unsigned, unsigned, const Macro &);
virtual void failedMacroDefinitionCheck(unsigned, const ByteArrayRef &);
virtual void passedMacroDefinitionCheck(unsigned, unsigned, unsigned, const Macro &);
virtual void failedMacroDefinitionCheck(unsigned, unsigned, const ByteArrayRef &);
virtual void notifyMacroReference(unsigned, unsigned, const Macro &);
virtual void notifyMacroReference(unsigned, unsigned, unsigned, const Macro &);
virtual void startExpandingMacro(unsigned,
unsigned,
unsigned,
const Macro &,
const QVector<MacroArgumentReference> &);
......
......@@ -55,7 +55,8 @@ Macro::Macro()
_hashcode(0),
_fileRevision(0),
_line(0),
_offset(0),
_bytesOffset(0),
_utf16charsOffset(0),
_length(0),
_state(0)
{ }
......
......@@ -71,6 +71,9 @@ public:
QByteArray name() const
{ return _name; }
QString nameToQString() const
{ return QString::fromUtf8(_name, _name.size()); }
void setName(const QByteArray &name)
{ _name = name; }
......@@ -107,11 +110,17 @@ public:
void setLine(unsigned line)
{ _line = line; }
unsigned offset() const
{ return _offset; }
unsigned bytesOffset() const
{ return _bytesOffset; }
void setBytesOffset(unsigned bytesOffset)
{ _bytesOffset = bytesOffset; }
unsigned utf16CharOffset() const
{ return _utf16charsOffset; }
void setOffset(unsigned offset)
{ _offset = offset; }
void setUtf16charOffset(unsigned utf16charOffset)
{ _utf16charsOffset = utf16charOffset; }
unsigned length() const
{ return _length; }
......@@ -161,7 +170,8 @@ private:
unsigned _hashcode;
unsigned _fileRevision;
unsigned _line;
unsigned _offset;
unsigned _bytesOffset;
unsigned _utf16charsOffset;
unsigned _length;
union
......
......@@ -58,5 +58,6 @@ void Internal::PPToken::squeezeSource()
m_src = m_src.mid(byteOffset, f.bytes);
m_src.squeeze();
byteOffset = 0;
utf16charOffset = 0;
}
}
......@@ -46,19 +46,19 @@ class Macro;
class CPLUSPLUS_EXPORT MacroArgumentReference
{
unsigned _position;
unsigned _length;
unsigned _utf16charsOffset;
unsigned _utf16charsLength;
public:
explicit MacroArgumentReference(unsigned position = 0, unsigned length = 0)
: _position(position), _length(length)
explicit MacroArgumentReference(unsigned utf16charsOffset = 0, unsigned utf16charsLength = 0)
: _utf16charsOffset(utf16charsOffset), _utf16charsLength(utf16charsLength)
{ }
unsigned position() const
{ return _position; }
unsigned utf16charsOffset() const
{ return _utf16charsOffset; }
unsigned length() const
{ return _length; }
unsigned utf16charsLength() const
{ return _utf16charsLength; }
};
class CPLUSPLUS_EXPORT Client
......@@ -79,24 +79,26 @@ public:
virtual void macroAdded(const Macro &macro) = 0;
virtual void passedMacroDefinitionCheck(unsigned offset, unsigned line, const Macro &macro) = 0;
virtual void failedMacroDefinitionCheck(unsigned offset, const ByteArrayRef &name) = 0;
virtual void passedMacroDefinitionCheck(unsigned bytesOffset, unsigned utf16charsOffset,
unsigned line, const Macro &macro) = 0;
virtual void failedMacroDefinitionCheck(unsigned bytesOffset, unsigned utf16charsOffset,
const ByteArrayRef &name) = 0;
virtual void notifyMacroReference(unsigned offset, unsigned line, const Macro &macro) = 0;
virtual void notifyMacroReference(unsigned bytesOffset, unsigned utf16charsOffset,
unsigned line, const Macro &macro) = 0;
virtual void startExpandingMacro(unsigned offset,
unsigned line,
const Macro &macro,
virtual void startExpandingMacro(unsigned bytesOffset, unsigned utf16charsOffset,
unsigned line, const Macro &macro,
const QVector<MacroArgumentReference> &actuals
= QVector<MacroArgumentReference>()) = 0;
virtual void stopExpandingMacro(unsigned offset, const Macro &macro) = 0;
virtual void stopExpandingMacro(unsigned bytesOffset, const Macro &macro) = 0; // TODO: ?!
/// Mark the given macro name as the include guard for the current file.
virtual void markAsIncludeGuard(const QByteArray &macroName) = 0;
/// Start skipping from the given offset.
virtual void startSkippingBlocks(unsigned offset) = 0;
virtual void stopSkippingBlocks(unsigned offset) = 0;
/// Start skipping from the given utf16charsOffset.
virtual void startSkippingBlocks(unsigned utf16charsOffset) = 0;
virtual void stopSkippingBlocks(unsigned utf16charsOffset) = 0;
virtual void sourceNeeded(unsigned line, const QString &fileName, IncludeType mode) = 0;
......
This diff is collapsed.
......@@ -95,7 +95,8 @@ private:
void preprocess(const QString &filename, const QByteArray &source,
QByteArray *result, QByteArray *includeGuardMacroName,
bool noLines, bool markGeneratedTokens, bool inCondition,
unsigned offsetRef = 0, unsigned lineRef = 1);
unsigned bytesOffsetRef = 0, unsigned utf16charOffsetRef = 0,
unsigned lineRef = 1);
enum { MAX_LEVEL = 512 };
......@@ -128,7 +129,8 @@ private:
bool m_noLines;
bool m_inCondition;
unsigned m_offsetRef;
unsigned m_bytesOffsetRef;
unsigned m_utf16charsOffsetRef;
QByteArray *m_result;
unsigned m_lineRef;
......
......@@ -717,7 +717,7 @@ const Macro *CPPEditorWidget::findCanonicalMacro(const QTextCursor &cursor, Docu
if (const Macro *macro = doc->findMacroDefinitionAt(line)) {
QTextCursor macroCursor = cursor;
const QByteArray name = identifierUnderCursor(&macroCursor).toLatin1();
const QByteArray name = identifierUnderCursor(&macroCursor).toUtf8();
if (macro->name() == name)
return macro;
} else if (const Document::MacroUse *use = doc->findMacroUseAt(cursor.position())) {
......@@ -836,9 +836,9 @@ void CPPEditorWidget::markSymbols(const QTextCursor &tc, const SemanticInfo &inf
//Macro definition
if (macro->fileName() == info.doc->fileName()) {
QTextCursor cursor(document());
cursor.setPosition(macro->offset());
cursor.setPosition(macro->utf16CharOffset());
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor,
macro->name().length());
macro->nameToQString().size());
QTextEdit::ExtraSelection sel;
sel.format = occurrencesFormat;
......@@ -850,14 +850,14 @@ void CPPEditorWidget::markSymbols(const QTextCursor &tc, const SemanticInfo &inf
foreach (const Document::MacroUse &use, info.doc->macroUses()) {
const Macro &useMacro = use.macro();
if (useMacro.line() != macro->line()
|| useMacro.offset() != macro->offset()
|| useMacro.utf16CharOffset() != macro->utf16CharOffset()
|| useMacro.length() != macro->length()
|| useMacro.fileName() != macro->fileName())
continue;
QTextCursor cursor(document());
cursor.setPosition(use.begin());
cursor.setPosition(use.end(), QTextCursor::KeepAnchor);
cursor.setPosition(use.utf16charsBegin());
cursor.setPosition(use.utf16charsEnd(), QTextCursor::KeepAnchor);
QTextEdit::ExtraSelection sel;
sel.format = occurrencesFormat;
......
......@@ -142,9 +142,9 @@ bool CppElementEvaluator::matchIncludeFile(const CPlusPlus::Document::Ptr &docum
bool CppElementEvaluator::matchMacroInUse(const CPlusPlus::Document::Ptr &document, unsigned pos)
{
foreach (const Document::MacroUse &use, document->macroUses()) {
if (use.contains(pos)) {
const unsigned begin = use.begin();
if (pos < begin + use.macro().name().length()) {
if (use.containsUtf16charOffset(pos)) {
const unsigned begin = use.utf16charsBegin();
if (pos < begin + use.macro().nameToQString().size()) {
m_element = QSharedPointer<CppElement>(new CppMacro(use.macro()));
return true;
}
......@@ -270,7 +270,7 @@ CppInclude::CppInclude(const Document::Include &includeFile) :
CppMacro::CppMacro(const Macro &macro)
{
helpCategory = TextEditor::HelpItem::Macro;
const QString macroName = QLatin1String(macro.name());
const QString macroName = QString::fromUtf8(macro.name(), macro.name().size());
helpIdCandidates = QStringList(macroName);
helpMark = macroName;
link = CPPEditorWidget::Link(macro.fileName(), macro.line());
......
......@@ -591,7 +591,7 @@ BaseTextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &
const Macro *macro = doc->findMacroDefinitionAt(line);
if (macro) {
QTextCursor macroCursor = cursor;
const QByteArray name = CPPEditorWidget::identifierUnderCursor(&macroCursor).toLatin1();
const QByteArray name = CPPEditorWidget::identifierUnderCursor(&macroCursor).toUtf8();
if (macro->name() == name)
return link; //already on definition!
} else if (const Document::MacroUse *use = doc->findMacroUseAt(endOfToken - 1)) {
......@@ -602,8 +602,8 @@ BaseTextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &
const Macro &macro = use->macro();
link.targetFileName = macro.fileName();
link.targetLine = macro.line();
link.linkTextStart = use->begin();
link.linkTextEnd = use->end();
link.linkTextStart = use->utf16charsBegin();
link.linkTextEnd = use->utf16charsEnd();
}
return link;
}
......@@ -722,7 +722,7 @@ BaseTextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &
// Handle macro uses
QTextCursor macroCursor = cursor;
const QByteArray name = CPPEditorWidget::identifierUnderCursor(&macroCursor).toLatin1();
const QByteArray name = CPPEditorWidget::identifierUnderCursor(&macroCursor).toUtf8();
link = findMacroLink(name, documentFromSemanticInfo);
if (link.hasValidTarget()) {
link.linkTextStart = macroCursor.selectionStart();
......
......@@ -660,8 +660,9 @@ void Dumper::dumpDocuments(const QList<CPlusPlus::Document::Ptr> &documents, boo
const QString type = use.isFunctionLike()
? QLatin1String("function-like") : QLatin1String("object-like");
m_out << i4 << "at line " << use.beginLine() << ", "
<< QString::fromUtf8(use.macro().name()) << ", begin=" << use.begin()
<< ", end=" << use.end() << ", " << type << ", args="
<< use.macro().nameToQString().size()