forked from qt-creator/qt-creator
Clang: fix utf8 related column numbers
Use new clang_getFileContents to efficiently convert utf8 byte offsets from line start to column numbers. Also provide simplier backwards convertion to pass resulting utf8 offset to clang. Task-number: QTCREATORBUG-16941 Change-Id: If0e58fe01ad3e281b7e952e972b9e86f6e75aadb Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
@@ -368,26 +368,23 @@ QFuture<CppTools::CursorInfo> BackendCommunicator::requestReferences(
|
||||
const FileContainer &fileContainer,
|
||||
quint32 line,
|
||||
quint32 column,
|
||||
QTextDocument *textDocument,
|
||||
const CppTools::SemanticInfo::LocalUseMap &localUses)
|
||||
{
|
||||
const RequestReferencesMessage message(fileContainer, line, column);
|
||||
m_sender->requestReferences(message);
|
||||
|
||||
return m_receiver.addExpectedReferencesMessage(message.ticketNumber(), textDocument,
|
||||
localUses);
|
||||
return m_receiver.addExpectedReferencesMessage(message.ticketNumber(), localUses);
|
||||
}
|
||||
|
||||
QFuture<CppTools::CursorInfo> BackendCommunicator::requestLocalReferences(
|
||||
const FileContainer &fileContainer,
|
||||
quint32 line,
|
||||
quint32 column,
|
||||
QTextDocument *textDocument)
|
||||
quint32 column)
|
||||
{
|
||||
const RequestReferencesMessage message(fileContainer, line, column, true);
|
||||
m_sender->requestReferences(message);
|
||||
|
||||
return m_receiver.addExpectedReferencesMessage(message.ticketNumber(), textDocument);
|
||||
return m_receiver.addExpectedReferencesMessage(message.ticketNumber());
|
||||
}
|
||||
|
||||
QFuture<CppTools::ToolTipInfo> BackendCommunicator::requestToolTip(
|
||||
|
||||
@@ -75,13 +75,11 @@ public:
|
||||
const FileContainer &fileContainer,
|
||||
quint32 line,
|
||||
quint32 column,
|
||||
QTextDocument *textDocument,
|
||||
const LocalUseMap &localUses);
|
||||
QFuture<CppTools::CursorInfo> requestLocalReferences(
|
||||
const FileContainer &fileContainer,
|
||||
quint32 line,
|
||||
quint32 column,
|
||||
QTextDocument *textDocument);
|
||||
quint32 column);
|
||||
QFuture<CppTools::ToolTipInfo> requestToolTip(const FileContainer &fileContainer,
|
||||
quint32 line,
|
||||
quint32 column);
|
||||
|
||||
@@ -101,16 +101,14 @@ void BackendReceiver::deleteProcessorsOfEditorWidget(TextEditor::TextEditorWidge
|
||||
|
||||
QFuture<CppTools::CursorInfo> BackendReceiver::addExpectedReferencesMessage(
|
||||
quint64 ticket,
|
||||
QTextDocument *textDocument,
|
||||
const CppTools::SemanticInfo::LocalUseMap &localUses)
|
||||
{
|
||||
QTC_CHECK(textDocument);
|
||||
QTC_CHECK(!m_referencesTable.contains(ticket));
|
||||
|
||||
QFutureInterface<CppTools::CursorInfo> futureInterface;
|
||||
futureInterface.reportStarted();
|
||||
|
||||
const ReferencesEntry entry{futureInterface, textDocument, localUses};
|
||||
const ReferencesEntry entry{futureInterface, localUses};
|
||||
m_referencesTable.insert(ticket, entry);
|
||||
|
||||
return futureInterface.future();
|
||||
@@ -221,24 +219,17 @@ void BackendReceiver::documentAnnotationsChanged(const DocumentAnnotationsChange
|
||||
}
|
||||
|
||||
static
|
||||
CppTools::CursorInfo::Range toCursorInfoRange(const QTextDocument &textDocument,
|
||||
const SourceRangeContainer &sourceRange)
|
||||
CppTools::CursorInfo::Range toCursorInfoRange(const SourceRangeContainer &sourceRange)
|
||||
{
|
||||
const SourceLocationContainer start = sourceRange.start();
|
||||
const SourceLocationContainer end = sourceRange.end();
|
||||
const unsigned length = end.column() - start.column();
|
||||
|
||||
const QTextBlock block = textDocument.findBlockByNumber(static_cast<int>(start.line()) - 1);
|
||||
const int shift = ClangCodeModel::Utils::extraUtf8CharsShift(block.text(),
|
||||
static_cast<int>(start.column()));
|
||||
const uint column = start.column() - static_cast<uint>(shift);
|
||||
|
||||
return CppTools::CursorInfo::Range(start.line(), column, length);
|
||||
return CppTools::CursorInfo::Range(start.line(), start.column(), length);
|
||||
}
|
||||
|
||||
static
|
||||
CppTools::CursorInfo toCursorInfo(const QTextDocument &textDocument,
|
||||
const CppTools::SemanticInfo::LocalUseMap &localUses,
|
||||
CppTools::CursorInfo toCursorInfo(const CppTools::SemanticInfo::LocalUseMap &localUses,
|
||||
const ReferencesMessage &message)
|
||||
{
|
||||
CppTools::CursorInfo result;
|
||||
@@ -246,7 +237,7 @@ CppTools::CursorInfo toCursorInfo(const QTextDocument &textDocument,
|
||||
|
||||
result.areUseRangesForLocalVariable = message.isLocalVariable();
|
||||
for (const SourceRangeContainer &reference : references)
|
||||
result.useRanges.append(toCursorInfoRange(textDocument, reference));
|
||||
result.useRanges.append(toCursorInfoRange(reference));
|
||||
|
||||
result.useRanges.reserve(references.size());
|
||||
result.localUses = localUses;
|
||||
@@ -284,8 +275,7 @@ void BackendReceiver::references(const ReferencesMessage &message)
|
||||
if (futureInterface.isCanceled())
|
||||
return; // Editor document closed or a new request was issued making this result outdated.
|
||||
|
||||
QTC_ASSERT(entry.textDocument, return);
|
||||
futureInterface.reportResult(toCursorInfo(*entry.textDocument, entry.localUses, message));
|
||||
futureInterface.reportResult(toCursorInfo(entry.localUses, message));
|
||||
futureInterface.reportFinished();
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,6 @@ public:
|
||||
|
||||
QFuture<CppTools::CursorInfo>
|
||||
addExpectedReferencesMessage(quint64 ticket,
|
||||
QTextDocument *textDocument,
|
||||
const CppTools::SemanticInfo::LocalUseMap &localUses
|
||||
= CppTools::SemanticInfo::LocalUseMap());
|
||||
QFuture<CppTools::SymbolInfo> addExpectedRequestFollowSymbolMessage(quint64 ticket);
|
||||
@@ -82,13 +81,10 @@ private:
|
||||
struct ReferencesEntry {
|
||||
ReferencesEntry() = default;
|
||||
ReferencesEntry(QFutureInterface<CppTools::CursorInfo> futureInterface,
|
||||
QTextDocument *textDocument,
|
||||
const CppTools::SemanticInfo::LocalUseMap &localUses)
|
||||
: futureInterface(futureInterface)
|
||||
, textDocument(textDocument)
|
||||
, localUses(localUses) {}
|
||||
QFutureInterface<CppTools::CursorInfo> futureInterface;
|
||||
QPointer<QTextDocument> textDocument;
|
||||
CppTools::SemanticInfo::LocalUseMap localUses;
|
||||
};
|
||||
QHash<quint64, ReferencesEntry> m_referencesTable;
|
||||
|
||||
@@ -559,7 +559,8 @@ ClangCompletionAssistProcessor::extractLineColumn(int position)
|
||||
int line = -1, column = -1;
|
||||
::Utils::Text::convertPosition(m_interface->textDocument(), position, &line, &column);
|
||||
const QTextBlock block = m_interface->textDocument()->findBlock(position);
|
||||
column += ClangCodeModel::Utils::extraUtf8CharsShift(block.text(), column) + 1;
|
||||
const QString stringOnTheLeft = block.text().left(column);
|
||||
column = stringOnTheLeft.toUtf8().size() + 1; // '+ 1' is for 1-based columns
|
||||
return {line, column};
|
||||
}
|
||||
|
||||
|
||||
@@ -64,8 +64,7 @@ int positionInText(QTextDocument *textDocument,
|
||||
{
|
||||
auto textBlock = textDocument->findBlockByNumber(
|
||||
static_cast<int>(sourceLocationContainer.line()) - 1);
|
||||
int column = static_cast<int>(sourceLocationContainer.column()) - 1;
|
||||
column -= ClangCodeModel::Utils::extraUtf8CharsShift(textBlock.text(), column);
|
||||
const int column = static_cast<int>(sourceLocationContainer.column()) - 1;
|
||||
return textBlock.position() + column;
|
||||
}
|
||||
|
||||
|
||||
@@ -331,20 +331,19 @@ ClangEditorDocumentProcessor::cursorInfo(const CppTools::CursorInfoParams ¶m
|
||||
{
|
||||
int line, column;
|
||||
convertPosition(params.textCursor, &line, &column);
|
||||
++column; // for 1-based columns
|
||||
|
||||
if (!isCursorOnIdentifier(params.textCursor))
|
||||
return defaultCursorInfoFuture();
|
||||
|
||||
const QTextBlock block = params.textCursor.document()->findBlockByNumber(line - 1);
|
||||
column += ClangCodeModel::Utils::extraUtf8CharsShift(block.text(), column);
|
||||
const QString stringOnTheLeft = block.text().left(column);
|
||||
column = stringOnTheLeft.toUtf8().size() + 1; // '+ 1' is for 1-based columns
|
||||
const CppTools::SemanticInfo::LocalUseMap localUses
|
||||
= CppTools::BuiltinCursorInfo::findLocalUses(params.semanticInfo.doc, line, column);
|
||||
|
||||
return m_communicator.requestReferences(simpleFileContainer(),
|
||||
static_cast<quint32>(line),
|
||||
static_cast<quint32>(column),
|
||||
textDocument(),
|
||||
localUses);
|
||||
}
|
||||
|
||||
@@ -361,8 +360,7 @@ QFuture<CppTools::CursorInfo> ClangEditorDocumentProcessor::requestLocalReferenc
|
||||
|
||||
return m_communicator.requestLocalReferences(simpleFileContainer(),
|
||||
static_cast<quint32>(line),
|
||||
static_cast<quint32>(column),
|
||||
textDocument());
|
||||
static_cast<quint32>(column));
|
||||
}
|
||||
|
||||
QFuture<CppTools::SymbolInfo>
|
||||
|
||||
@@ -190,31 +190,5 @@ void setLastSentDocumentRevision(const QString &filePath, uint revision)
|
||||
document->sendTracker().setLastSentRevision(int(revision));
|
||||
}
|
||||
|
||||
// CLANG-UPGRADE-CHECK: Workaround still needed?
|
||||
// Remove once clang reports correct columns for lines with multi-byte utf8.
|
||||
int extraUtf8CharsShift(const QString &str, int column)
|
||||
{
|
||||
int shift = 0;
|
||||
const QByteArray byteArray = str.toUtf8();
|
||||
for (int i = 0; i < qMin(str.length(), column); ++i) {
|
||||
const uchar firstByte = static_cast<uchar>(byteArray.at(i));
|
||||
// Skip different amount of bytes depending on value
|
||||
if (firstByte < 0xC0) {
|
||||
continue;
|
||||
} else if (firstByte < 0xE0) {
|
||||
++shift;
|
||||
++i;
|
||||
} else if (firstByte < 0xF0) {
|
||||
shift += 2;
|
||||
i += 2;
|
||||
} else {
|
||||
shift += 3;
|
||||
i += 3;
|
||||
}
|
||||
}
|
||||
return shift;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Utils
|
||||
} // namespace Clang
|
||||
|
||||
@@ -47,7 +47,5 @@ CppTools::ProjectPart::Ptr projectPartForFileBasedOnProcessor(const QString &fil
|
||||
bool isProjectPartLoaded(const CppTools::ProjectPart::Ptr projectPart);
|
||||
QString projectPartIdForFile(const QString &filePath);
|
||||
|
||||
int extraUtf8CharsShift(const QString &str, int column);
|
||||
|
||||
} // namespace Utils
|
||||
} // namespace Clang
|
||||
|
||||
Reference in New Issue
Block a user