ClangFormat: Fix iteration through text blocks

Document might be edited between consecutive currentBlock.next()
calls which is unsafe. Let's instead operate with block numbers.

Fixes: QTCREATORBUG-21521
Change-Id: I6863a77a32f5583269e1c796f38afb45cc9e7f77
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
Ivan Donchevskii
2018-11-26 10:50:07 +01:00
parent 8e31cfff91
commit 386535cf18

View File

@@ -69,6 +69,13 @@ void adjustFormatStyleForLineBreak(format::FormatStyle &style)
style.SortUsingDeclarations = false; style.SortUsingDeclarations = false;
} }
StringRef clearExtraNewline(StringRef text)
{
while (text.startswith("\n\n"))
text = text.drop_front();
return text;
}
Replacements filteredReplacements(const Replacements &replacements, Replacements filteredReplacements(const Replacements &replacements,
int offset, int offset,
int extraOffsetToAdd, int extraOffsetToAdd,
@@ -83,10 +90,13 @@ Replacements filteredReplacements(const Replacements &replacements,
if (replacementOffset + 1 >= offset) if (replacementOffset + 1 >= offset)
replacementOffset += extraOffsetToAdd; replacementOffset += extraOffsetToAdd;
StringRef text = onlyIndention ? clearExtraNewline(replacement.getReplacementText())
: replacement.getReplacementText();
Error error = filtered.add(Replacement(replacement.getFilePath(), Error error = filtered.add(Replacement(replacement.getFilePath(),
static_cast<unsigned int>(replacementOffset), static_cast<unsigned int>(replacementOffset),
replacement.getLength(), replacement.getLength(),
replacement.getReplacementText())); text));
// Throws if error is not checked. // Throws if error is not checked.
if (error) if (error)
break; break;
@@ -335,10 +345,19 @@ void ClangFormatIndenter::indent(QTextDocument *doc,
bool /*autoTriggered*/) bool /*autoTriggered*/)
{ {
if (cursor.hasSelection()) { if (cursor.hasSelection()) {
QTextBlock currentBlock = doc->findBlock(cursor.selectionStart()); // Calling currentBlock.next() might be unsafe because we change the document.
while (currentBlock.isValid() && currentBlock.position() < cursor.selectionEnd()) { // Let's operate with block numbers instead.
const int startNumber = doc->findBlock(cursor.selectionStart()).blockNumber();
const int endNumber = doc->findBlock(cursor.selectionEnd()).blockNumber();
for (int currentBlockNumber = startNumber; currentBlockNumber <= endNumber;
++currentBlockNumber) {
const QTextBlock currentBlock = doc->findBlockByNumber(currentBlockNumber);
if (currentBlock.isValid()) {
const int blocksAmount = doc->blockCount();
indentBlock(doc, currentBlock, typedChar, tabSettings); indentBlock(doc, currentBlock, typedChar, tabSettings);
currentBlock = currentBlock.next(); QTC_CHECK(blocksAmount == doc->blockCount()
&& "ClangFormat plugin indentation changed the amount of blocks.");
}
} }
} else { } else {
indentBlock(doc, cursor.block(), typedChar, tabSettings); indentBlock(doc, cursor.block(), typedChar, tabSettings);