Merge remote-tracking branch 'origin/4.9'

Change-Id: I966cfc1c63ccfdccb124edb44574fec1ecc5ad23
This commit is contained in:
Eike Ziller
2019-02-07 10:18:06 +01:00
60 changed files with 1202 additions and 337 deletions

View File

@@ -254,5 +254,23 @@
<string>@SHORT_VERSION@</string> <string>@SHORT_VERSION@</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>@MACOSX_DEPLOYMENT_TARGET@</string> <string>@MACOSX_DEPLOYMENT_TARGET@</string>
</dict> <key>NSAppleEventsUsageDescription</key>
</plist> <string>This application wants to run AppleScript.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>A user application wants to access bluetooth.</string>
<key>NSCalendarsUsageDescription</key>
<string>A user application wants to access calendars.</string>
<key>NSCameraUsageDescription</key>
<string>A user application wants to access the camera.</string>
<key>NSContactsUsageDescription</key>
<string>A user application wants to access contacts.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>A user application wants to access location information.</string>
<key>NSMicrophoneUsageDescription</key>
<string>A user application wants to access the microphone.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>A user application wants write access to the photo library.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>A user application wants to access the photo library.</string>
<key>NSRemindersUsageDescription</key>
<string>A user application wants to access the reminders.</string>

View File

@@ -182,6 +182,13 @@ public:
{ {
CompilerMacros macros = compilerMacros; CompilerMacros macros = compilerMacros;
macros.erase(std::remove_if(macros.begin(),
macros.end(),
[](const auto &macro) {
return macro.type == CompilerMacroType::NotDefined;
}),
macros.end());
std::sort(macros.begin(), std::sort(macros.begin(),
macros.end(), macros.end(),
[](const CompilerMacro &first, const CompilerMacro &second) { [](const CompilerMacro &first, const CompilerMacro &second) {
@@ -263,7 +270,7 @@ public:
void addNoStdIncAndNoStdLibInc() void addNoStdIncAndNoStdLibInc()
{ {
commandLine.emplace_back("-nostdinc"); commandLine.emplace_back("-nostdinc");
commandLine.emplace_back("-nostdlibinc"); commandLine.emplace_back("-nostdinc++");
} }
public: public:

View File

@@ -31,6 +31,8 @@
namespace ClangBackEnd { namespace ClangBackEnd {
enum class CompilerMacroType : unsigned char { Define, NotDefined };
class CompilerMacro class CompilerMacro
{ {
public: public:
@@ -40,39 +42,57 @@ public:
: key(std::move(key)) : key(std::move(key))
, value(std::move(value)) , value(std::move(value))
, index(index) , index(index)
, type(CompilerMacroType::Define)
{}
CompilerMacro(Utils::SmallString &&key)
: key(std::move(key))
{}
CompilerMacro(const Utils::SmallString &key)
: key(key)
{} {}
friend QDataStream &operator<<(QDataStream &out, const CompilerMacro &compilerMacro) friend QDataStream &operator<<(QDataStream &out, const CompilerMacro &compilerMacro)
{ {
out << compilerMacro.key; out << compilerMacro.key;
out << compilerMacro.value; out << compilerMacro.value;
out << compilerMacro.index;
out << static_cast<unsigned char>(compilerMacro.type);
return out; return out;
} }
friend QDataStream &operator>>(QDataStream &in, CompilerMacro &compilerMacro) friend QDataStream &operator>>(QDataStream &in, CompilerMacro &compilerMacro)
{ {
unsigned char type;
in >> compilerMacro.key; in >> compilerMacro.key;
in >> compilerMacro.value; in >> compilerMacro.value;
in >> compilerMacro.index;
in >> type;
compilerMacro.type = static_cast<CompilerMacroType>(type);
return in; return in;
} }
friend bool operator==(const CompilerMacro &first, const CompilerMacro &second) friend bool operator==(const CompilerMacro &first, const CompilerMacro &second)
{ {
return first.key == second.key return first.key == second.key && first.value == second.value && first.type == second.type;
&& first.value == second.value;
} }
friend bool operator<(const CompilerMacro &first, const CompilerMacro &second) friend bool operator<(const CompilerMacro &first, const CompilerMacro &second)
{ {
return std::tie(first.key, first.value) < std::tie(second.key, second.value); return std::tie(first.key, first.type, first.value)
< std::tie(second.key, second.type, second.value);
} }
public: public:
Utils::SmallString key; Utils::SmallString key;
Utils::SmallString value; Utils::SmallString value;
int index = 0; int index = -1;
CompilerMacroType type = CompilerMacroType::NotDefined;
}; };
using CompilerMacros = std::vector<CompilerMacro>; using CompilerMacros = std::vector<CompilerMacro>;

View File

@@ -161,5 +161,6 @@ public:
using ProjectPartContainers = std::vector<ProjectPartContainer>; using ProjectPartContainers = std::vector<ProjectPartContainer>;
QDebug operator<<(QDebug debug, const ProjectPartContainer &container); CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const ProjectPartContainer &container);
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -471,7 +471,9 @@ void TestResultsPane::updateSummaryLabel()
if (count) if (count)
labelText += ", " + QString::number(count) + ' ' + tr("fatals"); labelText += ", " + QString::number(count) + ' ' + tr("fatals");
count = m_model->resultTypeCount(Result::BlacklistedFail) count = m_model->resultTypeCount(Result::BlacklistedFail)
+ m_model->resultTypeCount(Result::BlacklistedPass); + m_model->resultTypeCount(Result::BlacklistedXFail)
+ m_model->resultTypeCount(Result::BlacklistedPass)
+ m_model->resultTypeCount(Result::BlacklistedXPass);
if (count) if (count)
labelText += ", " + QString::number(count) + ' ' + tr("blacklisted"); labelText += ", " + QString::number(count) + ' ' + tr("blacklisted");
count = m_model->resultTypeCount(Result::Skip); count = m_model->resultTypeCount(Result::Skip);

View File

@@ -27,6 +27,7 @@
#include <clang/Tooling/Core/Replacement.h> #include <clang/Tooling/Core/Replacement.h>
#include <utils/algorithm.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/textutils.h> #include <utils/textutils.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -57,20 +58,29 @@ static llvm::StringRef clearExtraNewline(llvm::StringRef text)
static clang::tooling::Replacements filteredReplacements( static clang::tooling::Replacements filteredReplacements(
const clang::tooling::Replacements &replacements, const clang::tooling::Replacements &replacements,
int offset, int offset,
int extraOffsetToAdd, int utf8LineLengthBeforeCursor,
bool onlyIndention) int extraOffsetFromStartOfFile,
int extraEmptySpaceOffset,
ReplacementsToKeep replacementsToKeep)
{ {
clang::tooling::Replacements filtered; clang::tooling::Replacements filtered;
for (const clang::tooling::Replacement &replacement : replacements) { for (const clang::tooling::Replacement &replacement : replacements) {
int replacementOffset = static_cast<int>(replacement.getOffset()); int replacementOffset = static_cast<int>(replacement.getOffset());
if (onlyIndention && replacementOffset != offset - 1) const bool replacementDoesNotMatchRestriction
= (replacementsToKeep == ReplacementsToKeep::OnlyIndent
&& replacementOffset != offset - 1)
|| (replacementsToKeep == ReplacementsToKeep::OnlyBeforeIndent
&& replacementOffset >= offset + utf8LineLengthBeforeCursor - 1);
if (replacementDoesNotMatchRestriction)
continue; continue;
if (replacementOffset + 1 >= offset) if (replacementOffset >= offset - 1)
replacementOffset += extraOffsetToAdd; replacementOffset += extraEmptySpaceOffset;
replacementOffset += extraOffsetFromStartOfFile;
llvm::StringRef text = onlyIndention ? clearExtraNewline(replacement.getReplacementText()) llvm::StringRef text = replacementsToKeep == ReplacementsToKeep::OnlyIndent
: replacement.getReplacementText(); ? clearExtraNewline(replacement.getReplacementText())
: replacement.getReplacementText();
llvm::Error error = filtered.add( llvm::Error error = filtered.add(
clang::tooling::Replacement(replacement.getFilePath(), clang::tooling::Replacement(replacement.getFilePath(),
@@ -78,8 +88,14 @@ static clang::tooling::Replacements filteredReplacements(
replacement.getLength(), replacement.getLength(),
text)); text));
// Throws if error is not checked. // Throws if error is not checked.
if (error) if (error) {
error = llvm::handleErrors(std::move(error),
[](const llvm::ErrorInfoBase &) -> llvm::Error {
return llvm::Error::success();
});
QTC_CHECK(!error && "Error must be a \"success\" at this point");
break; break;
}
} }
return filtered; return filtered;
} }
@@ -140,9 +156,16 @@ static int previousEmptyLinesLength(const QTextBlock &currentBlock)
static void modifyToIndentEmptyLines( static void modifyToIndentEmptyLines(
QByteArray &buffer, int offset, int &length, const QTextBlock &block, bool secondTry) QByteArray &buffer, int offset, int &length, const QTextBlock &block, bool secondTry)
{ {
const QString blockText = block.text().trimmed(); const QString blockText = block.text();
const bool closingParenBlock = blockText.startsWith(')'); int firstNonWhitespace = Utils::indexOf(blockText,
if (blockText.isEmpty() || closingParenBlock) { [](const QChar &ch) { return !ch.isSpace(); });
if (firstNonWhitespace > 0)
offset += firstNonWhitespace;
const bool closingParenBlock = firstNonWhitespace >= 0
&& blockText.at(firstNonWhitespace) == ')';
if (firstNonWhitespace < 0 || closingParenBlock) {
//This extra text works for the most cases. //This extra text works for the most cases.
QByteArray dummyText("a;"); QByteArray dummyText("a;");
@@ -153,15 +176,8 @@ static void modifyToIndentEmptyLines(
prevBlock = prevBlock.previous(); prevBlock = prevBlock.previous();
prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty(); prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty();
} }
if (prevBlock.text().endsWith(',')) if (closingParenBlock || prevBlock.text().endsWith(','))
dummyText = "int a"; dummyText = "&& a";
if (closingParenBlock) {
if (prevBlock.text().endsWith(','))
dummyText = "int a";
else
dummyText = "&& a";
}
length += dummyText.length(); length += dummyText.length();
buffer.insert(offset, dummyText); buffer.insert(offset, dummyText);
@@ -169,6 +185,9 @@ static void modifyToIndentEmptyLines(
if (secondTry) { if (secondTry) {
int nextLinePos = buffer.indexOf('\n', offset); int nextLinePos = buffer.indexOf('\n', offset);
if (nextLinePos < 0)
nextLinePos = buffer.size() - 1;
if (nextLinePos > 0) { if (nextLinePos > 0) {
// If first try was not successful try to put ')' in the end of the line to close possibly // If first try was not successful try to put ')' in the end of the line to close possibly
// unclosed parentheses. // unclosed parentheses.
@@ -187,7 +206,9 @@ static Utils::LineColumn utf16LineColumn(const QTextBlock &block,
int utf8Offset) int utf8Offset)
{ {
// If lastIndexOf('\n') returns -1 then we are fine to add 1 and get 0 offset. // If lastIndexOf('\n') returns -1 then we are fine to add 1 and get 0 offset.
const int lineStartUtf8Offset = utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1; const int lineStartUtf8Offset = utf8Offset == 0
? 0
: utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1;
int line = block.blockNumber() + 1; // Init with the line corresponding the block. int line = block.blockNumber() + 1; // Init with the line corresponding the block.
if (utf8Offset < blockOffsetUtf8) { if (utf8Offset < blockOffsetUtf8) {
@@ -299,8 +320,10 @@ void ClangFormatBaseIndenter::indent(const QTextCursor &cursor,
if (currentBlock.isValid()) { if (currentBlock.isValid()) {
const int blocksAmount = m_doc->blockCount(); const int blocksAmount = m_doc->blockCount();
indentBlock(currentBlock, typedChar, cursorPositionInEditor); indentBlock(currentBlock, typedChar, cursorPositionInEditor);
QTC_CHECK(blocksAmount == m_doc->blockCount()
&& "ClangFormat plugin indentation changed the amount of blocks."); // Only blocks before current might be added/removed, so it's safe to modify the index.
if (blocksAmount != m_doc->blockCount())
currentBlockNumber += (m_doc->blockCount() - blocksAmount);
} }
} }
} else { } else {
@@ -328,24 +351,30 @@ TextEditor::Replacements ClangFormatBaseIndenter::format(const QTextCursor &curs
{ {
int utf8Offset; int utf8Offset;
int utf8Length; int utf8Length;
QTextBlock block;
const QByteArray buffer = m_doc->toPlainText().toUtf8(); const QByteArray buffer = m_doc->toPlainText().toUtf8();
QTextBlock block = cursor.block();
if (cursor.hasSelection()) { if (cursor.hasSelection()) {
block = m_doc->findBlock(cursor.selectionStart()); block = m_doc->findBlock(cursor.selectionStart());
const QTextBlock end = m_doc->findBlock(cursor.selectionEnd()); const QTextBlock end = m_doc->findBlock(cursor.selectionEnd());
utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1); utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return TextEditor::Replacements();); QTC_ASSERT(utf8Offset >= 0, return TextEditor::Replacements(););
utf8Length = selectedLines(m_doc, block, end).toUtf8().size(); utf8Length = selectedLines(m_doc, block, end).toUtf8().size();
} else { } else {
const QTextBlock block = cursor.block(); block = cursor.block();
utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1); utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return TextEditor::Replacements();); QTC_ASSERT(utf8Offset >= 0, return TextEditor::Replacements(););
utf8Length = block.text().toUtf8().size(); utf8Length = block.text().toUtf8().size();
} }
const TextEditor::Replacements toReplace const TextEditor::Replacements toReplace = replacements(buffer,
= replacements(buffer, utf8Offset, utf8Length, block, QChar::Null, false); utf8Offset,
utf8Length,
block,
cursorPositionInEditor,
ReplacementsToKeep::All,
QChar::Null);
applyReplacements(block, toReplace); applyReplacements(block, toReplace);
return toReplace; return toReplace;
@@ -359,17 +388,62 @@ TextEditor::Replacements ClangFormatBaseIndenter::format(
return format(cursor, cursorPositionInEditor); return format(cursor, cursorPositionInEditor);
} }
int ClangFormatBaseIndenter::indentBeforeCursor(const QTextBlock &block,
const QChar &typedChar,
int cursorPositionInEditor)
{
const QByteArray buffer = m_doc->toPlainText().toUtf8();
const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return cursorPositionInEditor;);
const TextEditor::Replacements toReplace = replacements(buffer,
utf8Offset,
0,
block,
cursorPositionInEditor,
ReplacementsToKeep::OnlyBeforeIndent,
typedChar);
applyReplacements(block, toReplace);
for (const TextEditor::Replacement &replacement : toReplace)
cursorPositionInEditor += replacement.text.length() - replacement.length;
return cursorPositionInEditor;
}
void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block, void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
const QChar &typedChar, const QChar &typedChar,
int /*cursorPositionInEditor*/) int cursorPositionInEditor)
{ {
trimFirstNonEmptyBlock(block); QTextBlock currentBlock = block;
trimCurrentBlock(block); const int blockPosition = currentBlock.position();
trimFirstNonEmptyBlock(currentBlock);
if (formatWhileTyping()
&& (cursorPositionInEditor == -1 || cursorPositionInEditor >= blockPosition)) {
// Format before current position only in case the cursor is inside the indented block.
// So if cursor position is less then the block position then the current line is before
// the indented block - don't trigger extra formatting in this case.
// cursorPositionInEditor == -1 means the consition matches automatically.
if (cursorPositionInEditor >= 0)
cursorPositionInEditor += currentBlock.position() - blockPosition;
else
cursorPositionInEditor = currentBlock.position();
cursorPositionInEditor = indentBeforeCursor(currentBlock, typedChar, cursorPositionInEditor);
currentBlock = m_doc->findBlock(cursorPositionInEditor);
}
trimCurrentBlock(currentBlock);
const QByteArray buffer = m_doc->toPlainText().toUtf8(); const QByteArray buffer = m_doc->toPlainText().toUtf8();
const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1); const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return;); QTC_ASSERT(utf8Offset >= 0, return;);
applyReplacements(block, replacements(buffer, utf8Offset, 0, block, typedChar)); applyReplacements(currentBlock,
replacements(buffer,
utf8Offset,
0,
currentBlock,
cursorPositionInEditor,
ReplacementsToKeep::OnlyIndent,
typedChar));
} }
void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block, void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
@@ -380,7 +454,7 @@ void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
indentBlock(block, typedChar, cursorPositionInEditor); indentBlock(block, typedChar, cursorPositionInEditor);
} }
int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, int /*cursorPositionInEditor*/) int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, int cursorPositionInEditor)
{ {
trimFirstNonEmptyBlock(block); trimFirstNonEmptyBlock(block);
trimCurrentBlock(block); trimCurrentBlock(block);
@@ -388,7 +462,12 @@ int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, int /*cursorPosi
const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1); const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return 0;); QTC_ASSERT(utf8Offset >= 0, return 0;);
const TextEditor::Replacements toReplace = replacements(buffer, utf8Offset, 0, block); const TextEditor::Replacements toReplace = replacements(buffer,
utf8Offset,
0,
block,
cursorPositionInEditor,
ReplacementsToKeep::OnlyIndent);
if (toReplace.empty()) if (toReplace.empty())
return -1; return -1;
@@ -447,12 +526,30 @@ clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const
return clang::format::getLLVMStyle(); return clang::format::getLLVMStyle();
} }
static int formattingRangeStart(const QTextBlock &currentBlock,
const QByteArray &buffer,
int documentRevision)
{
QTextBlock prevBlock = currentBlock.previous();
while ((prevBlock.position() > 0 || prevBlock.length() > 0)
&& prevBlock.revision() != documentRevision
&& (currentBlock.blockNumber() - prevBlock.blockNumber() < kMaxLinesFromCurrentBlock)) {
// Find the first block with not matching revision.
prevBlock = prevBlock.previous();
}
if (prevBlock.revision() == documentRevision)
prevBlock = prevBlock.next();
return Utils::Text::utf8NthLineOffset(prevBlock.document(), buffer, prevBlock.blockNumber() + 1);
}
TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer, TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer,
int utf8Offset, int utf8Offset,
int utf8Length, int utf8Length,
const QTextBlock &block, const QTextBlock &block,
int cursorPositionInEditor,
ReplacementsToKeep replacementsToKeep,
const QChar &typedChar, const QChar &typedChar,
bool onlyIndention,
bool secondTry) const bool secondTry) const
{ {
clang::format::FormatStyle style = styleForFile(); clang::format::FormatStyle style = styleForFile();
@@ -461,13 +558,22 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer
int originalLengthUtf8 = utf8Length; int originalLengthUtf8 = utf8Length;
QByteArray originalBuffer = buffer; QByteArray originalBuffer = buffer;
int extraOffset = 0; int utf8LineLengthBeforeCursor = 0;
if (onlyIndention) { if (cursorPositionInEditor > 0 && typedChar != QChar::Null) {
// Format starting with the electric character if it's present.
utf8LineLengthBeforeCursor
= block.text().left(cursorPositionInEditor - block.position()).toUtf8().size();
}
int extraOffsetFromStartOfFile = 0;
int extraEmptySpaceOffset = 0;
int rangeStart = 0;
if (replacementsToKeep != ReplacementsToKeep::All) {
if (block.blockNumber() > kMaxLinesFromCurrentBlock) { if (block.blockNumber() > kMaxLinesFromCurrentBlock) {
extraOffset = Utils::Text::utf8NthLineOffset(block.document(), extraOffsetFromStartOfFile
buffer, = Utils::Text::utf8NthLineOffset(block.document(),
block.blockNumber() buffer,
- kMaxLinesFromCurrentBlock); block.blockNumber() - kMaxLinesFromCurrentBlock);
} }
int endOffset = Utils::Text::utf8NthLineOffset(block.document(), int endOffset = Utils::Text::utf8NthLineOffset(block.document(),
buffer, buffer,
@@ -476,22 +582,30 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer
if (endOffset == -1) if (endOffset == -1)
endOffset = buffer.size(); endOffset = buffer.size();
buffer = buffer.mid(extraOffset, endOffset - extraOffset);
utf8Offset -= extraOffset;
const int emptySpaceLength = previousEmptyLinesLength(block); if (replacementsToKeep == ReplacementsToKeep::OnlyBeforeIndent)
utf8Offset -= emptySpaceLength; rangeStart = formattingRangeStart(block, buffer, lastSaveRevision());
buffer.remove(utf8Offset, emptySpaceLength);
extraOffset += emptySpaceLength; buffer = buffer.mid(extraOffsetFromStartOfFile, endOffset - extraOffsetFromStartOfFile);
utf8Offset -= extraOffsetFromStartOfFile;
rangeStart -= extraOffsetFromStartOfFile;
adjustFormatStyleForLineBreak(style); extraEmptySpaceOffset = previousEmptyLinesLength(block);
if (typedChar == QChar::Null) utf8Offset -= extraEmptySpaceOffset;
modifyToIndentEmptyLines(buffer, utf8Offset, utf8Length, block, secondTry); buffer.remove(utf8Offset, extraEmptySpaceOffset);
if (replacementsToKeep == ReplacementsToKeep::OnlyIndent)
adjustFormatStyleForLineBreak(style);
modifyToIndentEmptyLines(buffer, utf8Offset, utf8Length, block, secondTry);
} }
std::vector<clang::tooling::Range> ranges{ if (replacementsToKeep != ReplacementsToKeep::OnlyBeforeIndent || utf8Offset < rangeStart)
{static_cast<unsigned int>(utf8Offset), static_cast<unsigned int>(utf8Length)}}; rangeStart = utf8Offset;
unsigned int rangeLength = static_cast<unsigned int>(utf8Offset + utf8Length - rangeStart);
std::vector<clang::tooling::Range> ranges{{static_cast<unsigned int>(rangeStart), rangeLength}};
clang::format::FormattingAttemptStatus status; clang::format::FormattingAttemptStatus status;
clang::tooling::Replacements clangReplacements = reformat(style, clang::tooling::Replacements clangReplacements = reformat(style,
@@ -500,21 +614,25 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer
m_fileName.toString().toStdString(), m_fileName.toString().toStdString(),
&status); &status);
if (!status.FormatComplete) clang::tooling::Replacements filtered;
return TextEditor::Replacements(); if (status.FormatComplete) {
filtered = filteredReplacements(clangReplacements,
const clang::tooling::Replacements filtered = filteredReplacements(clangReplacements, utf8Offset,
utf8Offset, utf8LineLengthBeforeCursor,
extraOffset, extraOffsetFromStartOfFile,
onlyIndention); extraEmptySpaceOffset,
const bool canTryAgain = onlyIndention && typedChar == QChar::Null && !secondTry; replacementsToKeep);
}
const bool canTryAgain = replacementsToKeep == ReplacementsToKeep::OnlyIndent
&& typedChar == QChar::Null && !secondTry;
if (canTryAgain && filtered.empty()) { if (canTryAgain && filtered.empty()) {
return replacements(originalBuffer, return replacements(originalBuffer,
originalOffsetUtf8, originalOffsetUtf8,
originalLengthUtf8, originalLengthUtf8,
block, block,
cursorPositionInEditor,
replacementsToKeep,
typedChar, typedChar,
onlyIndention,
true); true);
} }

View File

@@ -31,6 +31,8 @@
namespace ClangFormat { namespace ClangFormat {
enum class ReplacementsToKeep { OnlyIndent, OnlyBeforeIndent, All };
class ClangFormatBaseIndenter : public TextEditor::Indenter class ClangFormatBaseIndenter : public TextEditor::Indenter
{ {
public: public:
@@ -69,18 +71,24 @@ public:
protected: protected:
virtual clang::format::FormatStyle styleForFile() const; virtual clang::format::FormatStyle styleForFile() const;
virtual bool formatCodeInsteadOfIndent() const { return false; } virtual bool formatCodeInsteadOfIndent() const { return false; }
virtual bool formatWhileTyping() const { return false; }
virtual int lastSaveRevision() const { return 0; }
private: private:
TextEditor::Replacements format(const QTextCursor &cursor, int cursorPositionInEditor); TextEditor::Replacements format(const QTextCursor &cursor, int cursorPositionInEditor);
void indent(const QTextCursor &cursor, const QChar &typedChar, int cursorPositionInEditor); void indent(const QTextCursor &cursor, const QChar &typedChar, int cursorPositionInEditor);
void indentBlock(const QTextBlock &block, const QChar &typedChar, int cursorPositionInEditor); void indentBlock(const QTextBlock &block, const QChar &typedChar, int cursorPositionInEditor);
int indentFor(const QTextBlock &block, int cursorPositionInEditor); int indentFor(const QTextBlock &block, int cursorPositionInEditor);
int indentBeforeCursor(const QTextBlock &block,
const QChar &typedChar,
int cursorPositionInEditor);
TextEditor::Replacements replacements(QByteArray buffer, TextEditor::Replacements replacements(QByteArray buffer,
int utf8Offset, int utf8Offset,
int utf8Length, int utf8Length,
const QTextBlock &block, const QTextBlock &block,
int cursorPositionInEditor,
ReplacementsToKeep replacementsToKeep,
const QChar &typedChar = QChar::Null, const QChar &typedChar = QChar::Null,
bool onlyIndention = true,
bool secondTry = false) const; bool secondTry = false) const;
}; };

View File

@@ -127,12 +127,31 @@ ClangFormatConfigWidget::ClangFormatConfigWidget(ProjectExplorer::Project *proje
initialize(); initialize();
} }
void ClangFormatConfigWidget::hideGlobalCheckboxes()
{
m_ui->formatAlways->hide();
m_ui->formatWhileTyping->hide();
m_ui->formatOnSave->hide();
}
void ClangFormatConfigWidget::showGlobalCheckboxes()
{
m_ui->formatAlways->setChecked(ClangFormatSettings::instance().formatCodeInsteadOfIndent());
m_ui->formatAlways->show();
m_ui->formatWhileTyping->setChecked(ClangFormatSettings::instance().formatWhileTyping());
m_ui->formatWhileTyping->show();
m_ui->formatOnSave->setChecked(ClangFormatSettings::instance().formatOnSave());
m_ui->formatOnSave->show();
}
void ClangFormatConfigWidget::initialize() void ClangFormatConfigWidget::initialize()
{ {
m_ui->projectHasClangFormat->show(); m_ui->projectHasClangFormat->show();
m_ui->clangFormatOptionsTable->show(); m_ui->clangFormatOptionsTable->show();
m_ui->applyButton->show(); m_ui->applyButton->show();
m_ui->formatAlways->hide(); hideGlobalCheckboxes();
QLayoutItem *lastItem = m_ui->verticalLayout->itemAt(m_ui->verticalLayout->count() - 1); QLayoutItem *lastItem = m_ui->verticalLayout->itemAt(m_ui->verticalLayout->count() - 1);
if (lastItem->spacerItem()) if (lastItem->spacerItem())
@@ -171,8 +190,7 @@ void ClangFormatConfigWidget::initialize()
"and can be configured in Projects > Code Style > C++.")); "and can be configured in Projects > Code Style > C++."));
} }
createStyleFileIfNeeded(true); createStyleFileIfNeeded(true);
m_ui->formatAlways->setChecked(ClangFormatSettings::instance().formatCodeInsteadOfIndent()); showGlobalCheckboxes();
m_ui->formatAlways->show();
m_ui->applyButton->hide(); m_ui->applyButton->hide();
} }
@@ -186,7 +204,6 @@ void ClangFormatConfigWidget::fillTable()
std::string configText = clang::format::configurationAsText(style); std::string configText = clang::format::configurationAsText(style);
std::istringstream stream(configText); std::istringstream stream(configText);
readTable(m_ui->clangFormatOptionsTable, stream); readTable(m_ui->clangFormatOptionsTable, stream);
} }
ClangFormatConfigWidget::~ClangFormatConfigWidget() = default; ClangFormatConfigWidget::~ClangFormatConfigWidget() = default;
@@ -196,6 +213,8 @@ void ClangFormatConfigWidget::apply()
if (!m_project) { if (!m_project) {
ClangFormatSettings &settings = ClangFormatSettings::instance(); ClangFormatSettings &settings = ClangFormatSettings::instance();
settings.setFormatCodeInsteadOfIndent(m_ui->formatAlways->isChecked()); settings.setFormatCodeInsteadOfIndent(m_ui->formatAlways->isChecked());
settings.setFormatWhileTyping(m_ui->formatWhileTyping->isChecked());
settings.setFormatOnSave(m_ui->formatOnSave->isChecked());
settings.write(); settings.write();
} }

View File

@@ -51,6 +51,9 @@ private:
void initialize(); void initialize();
void fillTable(); void fillTable();
void hideGlobalCheckboxes();
void showGlobalCheckboxes();
ProjectExplorer::Project *m_project; ProjectExplorer::Project *m_project;
std::unique_ptr<Ui::ClangFormatConfigWidget> m_ui; std::unique_ptr<Ui::ClangFormatConfigWidget> m_ui;
}; };

View File

@@ -33,6 +33,20 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="formatWhileTyping">
<property name="text">
<string>Format while typing</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="formatOnSave">
<property name="text">
<string>Format edited code on file save</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QLabel" name="projectHasClangFormat"> <widget class="QLabel" name="projectHasClangFormat">
<property name="text"> <property name="text">

View File

@@ -32,5 +32,7 @@ static const char SETTINGS_FILE_ALT_NAME[] = "_clang-format";
static const char SAMPLE_FILE_NAME[] = "test.cpp"; static const char SAMPLE_FILE_NAME[] = "test.cpp";
static const char SETTINGS_ID[] = "ClangFormat"; static const char SETTINGS_ID[] = "ClangFormat";
static const char FORMAT_CODE_INSTEAD_OF_INDENT_ID[] = "ClangFormat.FormatCodeInsteadOfIndent"; static const char FORMAT_CODE_INSTEAD_OF_INDENT_ID[] = "ClangFormat.FormatCodeInsteadOfIndent";
static const char FORMAT_WHILE_TYPING_ID[] = "ClangFormat.FormatWhileTyping";
static const char FORMAT_CODE_ON_SAVE_ID[] = "ClangFormat.FormatCodeOnSave";
} // namespace Constants } // namespace Constants
} // namespace ClangFormat } // namespace ClangFormat

View File

@@ -28,6 +28,7 @@
#include "clangformatutils.h" #include "clangformatutils.h"
#include <texteditor/tabsettings.h> #include <texteditor/tabsettings.h>
#include <texteditor/textdocumentlayout.h>
using namespace clang; using namespace clang;
using namespace format; using namespace format;
@@ -49,6 +50,11 @@ bool ClangFormatIndenter::formatCodeInsteadOfIndent() const
return ClangFormatSettings::instance().formatCodeInsteadOfIndent(); return ClangFormatSettings::instance().formatCodeInsteadOfIndent();
} }
bool ClangFormatIndenter::formatWhileTyping() const
{
return ClangFormatSettings::instance().formatWhileTyping();
}
Utils::optional<TabSettings> ClangFormatIndenter::tabSettings() const Utils::optional<TabSettings> ClangFormatIndenter::tabSettings() const
{ {
FormatStyle style = currentProjectStyle(); FormatStyle style = currentProjectStyle();
@@ -76,4 +82,14 @@ Utils::optional<TabSettings> ClangFormatIndenter::tabSettings() const
return tabSettings; return tabSettings;
} }
int ClangFormatIndenter::lastSaveRevision() const
{
return qobject_cast<TextEditor::TextDocumentLayout *>(m_doc->documentLayout())->lastSaveRevision;
}
bool ClangFormatIndenter::formatOnSave() const
{
return ClangFormatSettings::instance().formatOnSave();
}
} // namespace ClangFormat } // namespace ClangFormat

View File

@@ -36,10 +36,13 @@ class ClangFormatIndenter final : public ClangFormatBaseIndenter
public: public:
ClangFormatIndenter(QTextDocument *doc); ClangFormatIndenter(QTextDocument *doc);
Utils::optional<TextEditor::TabSettings> tabSettings() const override; Utils::optional<TextEditor::TabSettings> tabSettings() const override;
bool formatOnSave() const override;
private: private:
bool formatCodeInsteadOfIndent() const override; bool formatCodeInsteadOfIndent() const override;
bool formatWhileTyping() const override;
clang::format::FormatStyle styleForFile() const override; clang::format::FormatStyle styleForFile() const override;
int lastSaveRevision() const override;
}; };
} // namespace ClangFormat } // namespace ClangFormat

View File

@@ -42,6 +42,10 @@ ClangFormatSettings::ClangFormatSettings()
settings->beginGroup(QLatin1String(Constants::SETTINGS_ID)); settings->beginGroup(QLatin1String(Constants::SETTINGS_ID));
m_formatCodeInsteadOfIndent m_formatCodeInsteadOfIndent
= settings->value(QLatin1String(Constants::FORMAT_CODE_INSTEAD_OF_INDENT_ID), false).toBool(); = settings->value(QLatin1String(Constants::FORMAT_CODE_INSTEAD_OF_INDENT_ID), false).toBool();
m_formatWhileTyping = settings->value(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), false)
.toBool();
m_formatOnSave = settings->value(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), false)
.toBool();
settings->endGroup(); settings->endGroup();
} }
@@ -51,6 +55,8 @@ void ClangFormatSettings::write() const
settings->beginGroup(QLatin1String(Constants::SETTINGS_ID)); settings->beginGroup(QLatin1String(Constants::SETTINGS_ID));
settings->setValue(QLatin1String(Constants::FORMAT_CODE_INSTEAD_OF_INDENT_ID), settings->setValue(QLatin1String(Constants::FORMAT_CODE_INSTEAD_OF_INDENT_ID),
m_formatCodeInsteadOfIndent); m_formatCodeInsteadOfIndent);
settings->setValue(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), m_formatWhileTyping);
settings->setValue(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), m_formatOnSave);
settings->endGroup(); settings->endGroup();
} }
@@ -64,4 +70,24 @@ bool ClangFormatSettings::formatCodeInsteadOfIndent() const
return m_formatCodeInsteadOfIndent; return m_formatCodeInsteadOfIndent;
} }
void ClangFormatSettings::setFormatWhileTyping(bool enable)
{
m_formatWhileTyping = enable;
}
bool ClangFormatSettings::formatWhileTyping() const
{
return m_formatWhileTyping;
}
void ClangFormatSettings::setFormatOnSave(bool enable)
{
m_formatOnSave = enable;
}
bool ClangFormatSettings::formatOnSave() const
{
return m_formatOnSave;
}
} // namespace ClangFormat } // namespace ClangFormat

View File

@@ -37,8 +37,16 @@ public:
void setFormatCodeInsteadOfIndent(bool enable); void setFormatCodeInsteadOfIndent(bool enable);
bool formatCodeInsteadOfIndent() const; bool formatCodeInsteadOfIndent() const;
void setFormatWhileTyping(bool enable);
bool formatWhileTyping() const;
void setFormatOnSave(bool enable);
bool formatOnSave() const;
private: private:
bool m_formatCodeInsteadOfIndent = false; bool m_formatCodeInsteadOfIndent = false;
bool m_formatWhileTyping = false;
bool m_formatOnSave = false;
}; };
} // namespace ClangFormat } // namespace ClangFormat

View File

@@ -152,35 +152,38 @@ void DiagnosticView::goBack()
QModelIndex DiagnosticView::getIndex(const QModelIndex &index, Direction direction) const QModelIndex DiagnosticView::getIndex(const QModelIndex &index, Direction direction) const
{ {
QModelIndex parentIndex = index.parent(); const QModelIndex parentIndex = index.parent();
QModelIndex followingTopIndex = index;
// Use direct sibling for level 2 and 3 items is possible
if (parentIndex.isValid()) { if (parentIndex.isValid()) {
const QModelIndex nextIndex = index.sibling(index.row() + direction, index.column()); // Use direct sibling for level 2 and 3 items
if (nextIndex.isValid()) const QModelIndex followingIndex = index.sibling(index.row() + direction, 0);
return nextIndex; if (followingIndex.isValid())
return followingIndex;
// First/Last level 3 item? Continue on level 2 item.
if (parentIndex.parent().isValid())
return direction == Previous ? parentIndex : getIndex(parentIndex, direction);
followingTopIndex = getTopLevelIndex(parentIndex, direction);
} }
// Last level 3 item? Continue on level 2 item // Skip top level items without children
if (parentIndex.parent().isValid()) while (!model()->hasChildren(followingTopIndex))
return getIndex(parentIndex, direction); followingTopIndex = getTopLevelIndex(followingTopIndex, direction);
// Find next/previous level 2 item // Select first/last level 2 item
QModelIndex nextTopIndex = getTopLevelIndex(parentIndex.isValid() ? parentIndex : index, const int row = direction == Next ? 0 : model()->rowCount(followingTopIndex) - 1;
direction); return model()->index(row, 0, followingTopIndex);
while (!model()->hasChildren(nextTopIndex))
nextTopIndex = getTopLevelIndex(nextTopIndex, direction);
return model()->index(direction == Next ? 0 : model()->rowCount(nextTopIndex) - 1,
0,
nextTopIndex);
} }
QModelIndex DiagnosticView::getTopLevelIndex(const QModelIndex &index, Direction direction) const QModelIndex DiagnosticView::getTopLevelIndex(const QModelIndex &index, Direction direction) const
{ {
QModelIndex below = index.sibling(index.row() + direction, 0); QModelIndex following = index.sibling(index.row() + direction, 0);
if (below.isValid()) if (following.isValid())
return below; return following;
return model()->index(direction == Next ? 0 : model()->rowCount(index) - 1, 0); const int row = direction == Next ? 0 : model()->rowCount() - 1;
return model()->index(row, 0);
} }
QList<QAction *> DiagnosticView::customActions() const QList<QAction *> DiagnosticView::customActions() const

View File

@@ -25,6 +25,8 @@
#include "clangtoolslogfilereader.h" #include "clangtoolslogfilereader.h"
#include <cpptools/cppprojectfile.h>
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
#include <QObject> #include <QObject>
@@ -147,6 +149,10 @@ static Diagnostic buildDiagnostic(const CXDiagnostic cxDiagnostic,
clang_disposeDiagnosticSet(cxChildDiagnostics); clang_disposeDiagnosticSet(cxChildDiagnostics);
}); });
using CppTools::ProjectFile;
const bool isHeaderFile = ProjectFile::isHeader(
ProjectFile::classify(diagnostic.location.filePath));
for (unsigned i = 0; i < clang_getNumDiagnosticsInSet(cxChildDiagnostics); ++i) { for (unsigned i = 0; i < clang_getNumDiagnosticsInSet(cxChildDiagnostics); ++i) {
CXDiagnostic cxDiagnostic = clang_getDiagnosticInSet(cxChildDiagnostics, i); CXDiagnostic cxDiagnostic = clang_getDiagnosticInSet(cxChildDiagnostics, i);
Utils::ExecuteOnDestruction cleanUpDiagnostic([&]() { Utils::ExecuteOnDestruction cleanUpDiagnostic([&]() {
@@ -156,6 +162,9 @@ static Diagnostic buildDiagnostic(const CXDiagnostic cxDiagnostic,
if (diagnosticStep.isValid()) if (diagnosticStep.isValid())
continue; continue;
if (isHeaderFile && diagnosticStep.message.contains("in file included from"))
continue;
if (isInvalidDiagnosticLocation(diagnostic, diagnosticStep, nativeFilePath)) if (isInvalidDiagnosticLocation(diagnostic, diagnosticStep, nativeFilePath))
return diagnostic; return diagnostic;

View File

@@ -97,7 +97,7 @@ CMakeKitConfigWidget::~CMakeKitConfigWidget()
QString CMakeKitConfigWidget::displayName() const QString CMakeKitConfigWidget::displayName() const
{ {
return tr("CMake Tool:"); return tr("CMake Tool");
} }
void CMakeKitConfigWidget::makeReadOnly() void CMakeKitConfigWidget::makeReadOnly()
@@ -230,7 +230,7 @@ CMakeGeneratorKitConfigWidget::~CMakeGeneratorKitConfigWidget()
QString CMakeGeneratorKitConfigWidget::displayName() const QString CMakeGeneratorKitConfigWidget::displayName() const
{ {
return tr("CMake generator:"); return tr("CMake generator");
} }
void CMakeGeneratorKitConfigWidget::makeReadOnly() void CMakeGeneratorKitConfigWidget::makeReadOnly()

View File

@@ -173,3 +173,34 @@ const QMap<QString, QUrl> &HelpItem::links() const
} }
return *m_helpLinks; return *m_helpLinks;
} }
static QUrl findBestLink(const QMap<QString, QUrl> &links)
{
if (links.isEmpty())
return QUrl();
if (links.size() == 1)
return links.first();
QUrl source = links.first();
// workaround to show the latest Qt version
int version = 0;
QRegExp exp("(\\d+)");
foreach (const QUrl &link, links) {
const QString &authority = link.authority();
if (authority.startsWith("com.trolltech.")
|| authority.startsWith("org.qt-project.")) {
if (exp.indexIn(authority) >= 0) {
const int tmpVersion = exp.cap(1).toInt();
if (tmpVersion > version) {
source = link;
version = tmpVersion;
}
}
}
}
return source;
}
const QUrl HelpItem::bestLink() const
{
return findBestLink(links());
}

View File

@@ -78,6 +78,7 @@ public:
QString extractContent(bool extended) const; QString extractContent(bool extended) const;
const QMap<QString, QUrl> &links() const; const QMap<QString, QUrl> &links() const;
const QUrl bestLink() const;
private: private:
QUrl m_helpUrl; QUrl m_helpUrl;

View File

@@ -48,15 +48,15 @@ QSettings *InfoBar::m_settings = nullptr;
Utils::Theme *InfoBar::m_theme = nullptr; Utils::Theme *InfoBar::m_theme = nullptr;
InfoBarEntry::InfoBarEntry(Id _id, const QString &_infoText, GlobalSuppressionMode _globalSuppression) InfoBarEntry::InfoBarEntry(Id _id, const QString &_infoText, GlobalSuppressionMode _globalSuppression)
: id(_id) : m_id(_id)
, infoText(_infoText) , m_infoText(_infoText)
, globalSuppression(_globalSuppression) , m_globalSuppression(_globalSuppression)
{ {
} }
void InfoBarEntry::setCustomButtonInfo(const QString &_buttonText, CallBack callBack) void InfoBarEntry::setCustomButtonInfo(const QString &_buttonText, CallBack callBack)
{ {
buttonText = _buttonText; m_buttonText = _buttonText;
m_buttonCallBack = callBack; m_buttonCallBack = callBack;
} }
@@ -69,14 +69,14 @@ void InfoBarEntry::setCancelButtonInfo(CallBack callBack)
void InfoBarEntry::setCancelButtonInfo(const QString &_cancelButtonText, CallBack callBack) void InfoBarEntry::setCancelButtonInfo(const QString &_cancelButtonText, CallBack callBack)
{ {
m_useCancelButton = true; m_useCancelButton = true;
cancelButtonText = _cancelButtonText; m_cancelButtonText = _cancelButtonText;
m_cancelButtonCallBack = callBack; m_cancelButtonCallBack = callBack;
} }
void InfoBarEntry::removeCancelButton() void InfoBarEntry::removeCancelButton()
{ {
m_useCancelButton = false; m_useCancelButton = false;
cancelButtonText.clear(); m_cancelButtonText.clear();
m_cancelButtonCallBack = nullptr; m_cancelButtonCallBack = nullptr;
} }
@@ -94,14 +94,14 @@ void InfoBar::addInfo(const InfoBarEntry &info)
void InfoBar::removeInfo(Id id) void InfoBar::removeInfo(Id id)
{ {
const int size = m_infoBarEntries.size(); const int size = m_infoBarEntries.size();
Utils::erase(m_infoBarEntries, Utils::equal(&InfoBarEntry::id, id)); Utils::erase(m_infoBarEntries, Utils::equal(&InfoBarEntry::m_id, id));
if (size != m_infoBarEntries.size()) if (size != m_infoBarEntries.size())
emit changed(); emit changed();
} }
bool InfoBar::containsInfo(Id id) const bool InfoBar::containsInfo(Id id) const
{ {
return Utils::anyOf(m_infoBarEntries, Utils::equal(&InfoBarEntry::id, id)); return Utils::anyOf(m_infoBarEntries, Utils::equal(&InfoBarEntry::m_id, id));
} }
// Remove and suppress id // Remove and suppress id
@@ -240,7 +240,7 @@ void InfoBarDisplay::update()
vbox->setMargin(0); vbox->setMargin(0);
vbox->addLayout(hbox); vbox->addLayout(hbox);
QLabel *infoWidgetLabel = new QLabel(info.infoText); QLabel *infoWidgetLabel = new QLabel(info.m_infoText);
infoWidgetLabel->setWordWrap(true); infoWidgetLabel->setWordWrap(true);
hbox->addWidget(infoWidgetLabel); hbox->addWidget(infoWidgetLabel);
@@ -270,17 +270,17 @@ void InfoBarDisplay::update()
m_isShowingDetailsWidget = false; m_isShowingDetailsWidget = false;
} }
if (!info.buttonText.isEmpty()) { if (!info.m_buttonText.isEmpty()) {
auto infoWidgetButton = new QToolButton; auto infoWidgetButton = new QToolButton;
infoWidgetButton->setText(info.buttonText); infoWidgetButton->setText(info.m_buttonText);
connect(infoWidgetButton, &QAbstractButton::clicked, [info]() { info.m_buttonCallBack(); }); connect(infoWidgetButton, &QAbstractButton::clicked, [info]() { info.m_buttonCallBack(); });
hbox->addWidget(infoWidgetButton); hbox->addWidget(infoWidgetButton);
} }
const Id id = info.id; const Id id = info.m_id;
QToolButton *infoWidgetSuppressButton = nullptr; QToolButton *infoWidgetSuppressButton = nullptr;
if (info.globalSuppression == InfoBarEntry::GlobalSuppressionEnabled) { if (info.m_globalSuppression == InfoBarEntry::GlobalSuppressionEnabled) {
infoWidgetSuppressButton = new QToolButton; infoWidgetSuppressButton = new QToolButton;
infoWidgetSuppressButton->setText(tr("Do Not Show Again")); infoWidgetSuppressButton->setText(tr("Do Not Show Again"));
connect(infoWidgetSuppressButton, &QAbstractButton::clicked, this, [this, id] { connect(infoWidgetSuppressButton, &QAbstractButton::clicked, this, [this, id] {
@@ -301,7 +301,7 @@ void InfoBarDisplay::update()
}); });
} }
if (info.cancelButtonText.isEmpty()) { if (info.m_cancelButtonText.isEmpty()) {
if (infoWidgetCloseButton) { if (infoWidgetCloseButton) {
infoWidgetCloseButton->setAutoRaise(true); infoWidgetCloseButton->setAutoRaise(true);
infoWidgetCloseButton->setIcon(Utils::Icons::CLOSE_FOREGROUND.icon()); infoWidgetCloseButton->setIcon(Utils::Icons::CLOSE_FOREGROUND.icon());
@@ -314,7 +314,7 @@ void InfoBarDisplay::update()
if (infoWidgetCloseButton) if (infoWidgetCloseButton)
hbox->addWidget(infoWidgetCloseButton); hbox->addWidget(infoWidgetCloseButton);
} else { } else {
infoWidgetCloseButton->setText(info.cancelButtonText); infoWidgetCloseButton->setText(info.m_cancelButtonText);
hbox->addWidget(infoWidgetCloseButton); hbox->addWidget(infoWidgetCloseButton);
if (infoWidgetSuppressButton) if (infoWidgetSuppressButton)
hbox->addWidget(infoWidgetSuppressButton); hbox->addWidget(infoWidgetSuppressButton);

View File

@@ -67,13 +67,13 @@ public:
void setDetailsWidgetCreator(const DetailsWidgetCreator &creator); void setDetailsWidgetCreator(const DetailsWidgetCreator &creator);
private: private:
Id id; Id m_id;
QString infoText; QString m_infoText;
QString buttonText; QString m_buttonText;
CallBack m_buttonCallBack; CallBack m_buttonCallBack;
QString cancelButtonText; QString m_cancelButtonText;
CallBack m_cancelButtonCallBack; CallBack m_cancelButtonCallBack;
GlobalSuppressionMode globalSuppression; GlobalSuppressionMode m_globalSuppression;
DetailsWidgetCreator m_detailsWidgetCreator; DetailsWidgetCreator m_detailsWidgetCreator;
bool m_useCancelButton = true; bool m_useCancelButton = true;
friend class InfoBar; friend class InfoBar;

View File

@@ -44,6 +44,7 @@
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <texteditor/icodestylepreferencesfactory.h> #include <texteditor/icodestylepreferencesfactory.h>
#include <texteditor/textdocumentlayout.h>
#include <texteditor/texteditorsettings.h> #include <texteditor/texteditorsettings.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
@@ -447,5 +448,47 @@ TextEditor::TabSettings CppEditorDocument::tabSettings() const
return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings()); return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings());
} }
static int formatRange(QTextDocument *doc,
TextEditor::Indenter *indenter,
std::pair<int, int> editedRange,
const TextEditor::TabSettings &tabSettings)
{
QTextCursor cursor(doc);
cursor.setPosition(editedRange.first);
cursor.setPosition(editedRange.second, QTextCursor::KeepAnchor);
const int oldBlockCount = doc->blockCount();
indenter->format(cursor, tabSettings);
return doc->blockCount() - oldBlockCount;
}
bool CppEditorDocument::save(QString *errorString, const QString &fileName, bool autoSave)
{
if (indenter()->formatOnSave()) {
auto *layout = qobject_cast<TextEditor::TextDocumentLayout *>(document()->documentLayout());
const int documentRevision = layout->lastSaveRevision;
std::pair<int, int> editedRange;
for (int i = 0; i < document()->blockCount(); ++i) {
const QTextBlock block = document()->findBlockByNumber(i);
if (block.revision() == documentRevision) {
if (editedRange.first != -1)
i += formatRange(document(), indenter(), editedRange, tabSettings());
editedRange = std::make_pair(-1, -1);
continue;
}
// block.revision() != documentRevision
if (editedRange.first == -1)
editedRange.first = block.position();
editedRange.second = block.position() + block.length();
}
if (editedRange.first != -1)
formatRange(document(), indenter(), editedRange, tabSettings());
}
return TextEditor::TextDocument::save(errorString, fileName, autoSave);
}
} // namespace Internal } // namespace Internal
} // namespace CppEditor } // namespace CppEditor

View File

@@ -69,6 +69,10 @@ public:
QFuture<CppTools::CursorInfo> cursorInfo(const CppTools::CursorInfoParams &params); QFuture<CppTools::CursorInfo> cursorInfo(const CppTools::CursorInfoParams &params);
TextEditor::TabSettings tabSettings() const override; TextEditor::TabSettings tabSettings() const override;
bool save(QString *errorString,
const QString &fileName = QString(),
bool autoSave = false) override;
signals: signals:
void codeWarningsUpdated(unsigned contentsRevision, void codeWarningsUpdated(unsigned contentsRevision,
const QList<QTextEdit::ExtraSelection> selections, const QList<QTextEdit::ExtraSelection> selections,

View File

@@ -93,7 +93,7 @@ QString DebuggerKitConfigWidget::toolTip() const
QString DebuggerKitConfigWidget::displayName() const QString DebuggerKitConfigWidget::displayName() const
{ {
return tr("Debugger:"); return tr("Debugger");
} }
void DebuggerKitConfigWidget::makeReadOnly() void DebuggerKitConfigWidget::makeReadOnly()

View File

@@ -620,30 +620,6 @@ HelpViewer *HelpPluginPrivate::viewerForContextHelp()
return viewerForHelpViewerLocation(LocalHelpManager::contextHelpOption()); return viewerForHelpViewerLocation(LocalHelpManager::contextHelpOption());
} }
static QUrl findBestLink(const QMap<QString, QUrl> &links)
{
if (links.isEmpty())
return QUrl();
QUrl source = links.constBegin().value();
// workaround to show the latest Qt version
int version = 0;
QRegExp exp("(\\d+)");
foreach (const QUrl &link, links) {
const QString &authority = link.authority();
if (authority.startsWith("com.trolltech.")
|| authority.startsWith("org.qt-project.")) {
if (exp.indexIn(authority) >= 0) {
const int tmpVersion = exp.cap(1).toInt();
if (tmpVersion > version) {
source = link;
version = tmpVersion;
}
}
}
}
return source;
}
void HelpPluginPrivate::requestContextHelp() void HelpPluginPrivate::requestContextHelp()
{ {
// Find out what to show // Find out what to show
@@ -660,9 +636,7 @@ void HelpPluginPrivate::requestContextHelp()
void HelpPluginPrivate::showContextHelp(const HelpItem &contextHelp) void HelpPluginPrivate::showContextHelp(const HelpItem &contextHelp)
{ {
const QMap<QString, QUrl> &links = contextHelp.links(); const QUrl source = contextHelp.bestLink();
const QUrl source = findBestLink(links);
if (!source.isValid()) { if (!source.isValid()) {
// No link found or no context object // No link found or no context object
HelpViewer *viewer = showHelpUrl(QUrl(Help::Constants::AboutBlank), HelpViewer *viewer = showHelpUrl(QUrl(Help::Constants::AboutBlank),

View File

@@ -82,7 +82,7 @@ SysRootInformationConfigWidget::~SysRootInformationConfigWidget()
QString SysRootInformationConfigWidget::displayName() const QString SysRootInformationConfigWidget::displayName() const
{ {
return tr("Sysroot:"); return tr("Sysroot");
} }
QString SysRootInformationConfigWidget::toolTip() const QString SysRootInformationConfigWidget::toolTip() const
@@ -177,7 +177,7 @@ ToolChainInformationConfigWidget::~ToolChainInformationConfigWidget()
QString ToolChainInformationConfigWidget::displayName() const QString ToolChainInformationConfigWidget::displayName() const
{ {
return tr("Compiler:"); return tr("Compiler");
} }
QString ToolChainInformationConfigWidget::toolTip() const QString ToolChainInformationConfigWidget::toolTip() const
@@ -285,7 +285,7 @@ QWidget *DeviceTypeInformationConfigWidget::mainWidget() const
QString DeviceTypeInformationConfigWidget::displayName() const QString DeviceTypeInformationConfigWidget::displayName() const
{ {
return tr("Device type:"); return tr("Device type");
} }
QString DeviceTypeInformationConfigWidget::toolTip() const QString DeviceTypeInformationConfigWidget::toolTip() const
@@ -358,7 +358,7 @@ QWidget *DeviceInformationConfigWidget::mainWidget() const
QString DeviceInformationConfigWidget::displayName() const QString DeviceInformationConfigWidget::displayName() const
{ {
return tr("Device:"); return tr("Device");
} }
QString DeviceInformationConfigWidget::toolTip() const QString DeviceInformationConfigWidget::toolTip() const
@@ -437,7 +437,7 @@ QWidget *KitEnvironmentConfigWidget::mainWidget() const
QString KitEnvironmentConfigWidget::displayName() const QString KitEnvironmentConfigWidget::displayName() const
{ {
return tr("Environment:"); return tr("Environment");
} }
QString KitEnvironmentConfigWidget::toolTip() const QString KitEnvironmentConfigWidget::toolTip() const

View File

@@ -216,7 +216,7 @@ void KitManagerConfigWidget::addConfigWidget(KitConfigWidget *widget)
QTC_ASSERT(widget, return); QTC_ASSERT(widget, return);
QTC_ASSERT(!m_widgets.contains(widget), return); QTC_ASSERT(!m_widgets.contains(widget), return);
QString name = widget->displayName(); const QString name = widget->displayName() + ':';
QString toolTip = widget->toolTip(); QString toolTip = widget->toolTip();
auto action = new QAction(tr("Mark as Mutable"), nullptr); auto action = new QAction(tr("Mark as Mutable"), nullptr);

View File

@@ -398,7 +398,7 @@ bool FlatModel::trimEmptyDirectories(WrapperNode *parent)
Qt::DropActions FlatModel::supportedDragActions() const Qt::DropActions FlatModel::supportedDragActions() const
{ {
return Qt::MoveAction; return Qt::CopyAction;
} }
QStringList FlatModel::mimeTypes() const QStringList FlatModel::mimeTypes() const

View File

@@ -55,7 +55,7 @@ QWidget *QmakeKitConfigWidget::mainWidget() const
QString QmakeKitConfigWidget::displayName() const QString QmakeKitConfigWidget::displayName() const
{ {
return tr("Qt mkspec:"); return tr("Qt mkspec");
} }
QString QmakeKitConfigWidget::toolTip() const QString QmakeKitConfigWidget::toolTip() const

View File

@@ -72,7 +72,7 @@ QtKitConfigWidget::~QtKitConfigWidget()
QString QtKitConfigWidget::displayName() const QString QtKitConfigWidget::displayName() const
{ {
return tr("Qt version:"); return tr("Qt version");
} }
QString QtKitConfigWidget::toolTip() const QString QtKitConfigWidget::toolTip() const

View File

@@ -99,6 +99,8 @@ public:
return Replacements(); return Replacements();
} }
virtual bool formatOnSave() const { return false; }
// Expects a list of blocks in order of occurrence in the document. // Expects a list of blocks in order of occurrence in the document.
virtual IndentationForBlock indentationForBlocks(const QVector<QTextBlock> &blocks, virtual IndentationForBlock indentationForBlocks(const QVector<QTextBlock> &blocks,
const TabSettings &tabSettings, const TabSettings &tabSettings,

View File

@@ -692,7 +692,8 @@ public:
QTextCursor m_pendingLinkUpdate; QTextCursor m_pendingLinkUpdate;
QTextCursor m_lastLinkUpdate; QTextCursor m_lastLinkUpdate;
QRegExp m_searchExpr; QRegularExpression m_searchExpr;
QString m_findText;
FindFlags m_findFlags; FindFlags m_findFlags;
void highlightSearchResults(const QTextBlock &block, const PaintEventData &data) const; void highlightSearchResults(const QTextBlock &block, const PaintEventData &data) const;
QTimer m_delayedUpdateTimer; QTimer m_delayedUpdateTimer;
@@ -3715,7 +3716,7 @@ QTextBlock TextEditorWidgetPrivate::foldedBlockAt(const QPoint &pos, QRect *box)
void TextEditorWidgetPrivate::highlightSearchResults(const QTextBlock &block, const PaintEventData &data) const void TextEditorWidgetPrivate::highlightSearchResults(const QTextBlock &block, const PaintEventData &data) const
{ {
if (m_searchExpr.isEmpty()) if (m_searchExpr.pattern().isEmpty())
return; return;
int blockPosition = block.position(); int blockPosition = block.position();
@@ -3734,10 +3735,11 @@ void TextEditorWidgetPrivate::highlightSearchResults(const QTextBlock &block, co
.toTextCharFormat(C_SEARCH_RESULT).background().color().darker(120); .toTextCharFormat(C_SEARCH_RESULT).background().color().darker(120);
while (idx < text.length()) { while (idx < text.length()) {
idx = m_searchExpr.indexIn(text, idx + l); const QRegularExpressionMatch match = m_searchExpr.match(text, idx + 1);
if (idx < 0) if (!match.hasMatch())
break; break;
l = m_searchExpr.matchedLength(); idx = match.capturedStart();
l = match.capturedLength();
if (l == 0) if (l == 0)
break; break;
if ((m_findFlags & FindWholeWords) if ((m_findFlags & FindWholeWords)
@@ -4332,7 +4334,7 @@ void TextEditorWidgetPrivate::paintSearchResultOverlay(const PaintEventData &dat
QPainter &painter) const QPainter &painter) const
{ {
m_searchResultOverlay->clear(); m_searchResultOverlay->clear();
if (m_searchExpr.isEmpty()) if (m_searchExpr.pattern().isEmpty())
return; return;
const int margin = 5; const int margin = 5;
@@ -5335,7 +5337,7 @@ void TextEditorWidgetPrivate::slotUpdateRequest(const QRect &r, int dy)
m_extraArea->scroll(0, dy); m_extraArea->scroll(0, dy);
} else if (r.width() > 4) { // wider than cursor width, not just cursor blinking } else if (r.width() > 4) { // wider than cursor width, not just cursor blinking
m_extraArea->update(0, r.y(), m_extraArea->width(), r.height()); m_extraArea->update(0, r.y(), m_extraArea->width(), r.height());
if (!m_searchExpr.isEmpty()) { if (!m_searchExpr.pattern().isEmpty()) {
const int m = m_searchResultOverlay->dropShadowWidth(); const int m = m_searchResultOverlay->dropShadowWidth();
q->viewport()->update(r.adjusted(-m, -m, m, m)); q->viewport()->update(r.adjusted(-m, -m, m, m));
} }
@@ -6350,13 +6352,16 @@ void TextEditorWidgetPrivate::clearLink()
void TextEditorWidgetPrivate::highlightSearchResultsSlot(const QString &txt, FindFlags findFlags) void TextEditorWidgetPrivate::highlightSearchResultsSlot(const QString &txt, FindFlags findFlags)
{ {
if (m_searchExpr.pattern() == txt) const QString pattern = (findFlags & FindRegularExpression) ? txt
: QRegularExpression::escape(txt);
const QRegularExpression::PatternOptions options
= (findFlags & FindCaseSensitively) ? QRegularExpression::NoPatternOption
: QRegularExpression::CaseInsensitiveOption;
if (m_searchExpr.pattern() == pattern && m_searchExpr.patternOptions() == options)
return; return;
m_searchExpr.setPattern(txt); m_searchExpr.setPattern(pattern);
m_searchExpr.setPatternSyntax((findFlags & FindRegularExpression) ? m_searchExpr.setPatternOptions(options);
QRegExp::RegExp : QRegExp::FixedString); m_findText = txt;
m_searchExpr.setCaseSensitivity((findFlags & FindCaseSensitively) ?
Qt::CaseSensitive : Qt::CaseInsensitive);
m_findFlags = findFlags; m_findFlags = findFlags;
m_delayedUpdateTimer.start(50); m_delayedUpdateTimer.start(50);
@@ -6414,7 +6419,7 @@ void TextEditorWidgetPrivate::highlightSearchResultsInScrollBar()
m_searchWatcher = nullptr; m_searchWatcher = nullptr;
} }
const QString &txt = m_searchExpr.pattern(); const QString &txt = m_findText;
if (txt.isEmpty()) if (txt.isEmpty())
return; return;
@@ -8608,7 +8613,7 @@ void TextEditorLinkLabel::mouseMoveEvent(QMouseEvent *event)
data->addFile(m_link.targetFileName, m_link.targetLine, m_link.targetColumn); data->addFile(m_link.targetFileName, m_link.targetLine, m_link.targetColumn);
auto drag = new QDrag(this); auto drag = new QDrag(this);
drag->setMimeData(data); drag->setMimeData(data);
drag->exec(Qt::MoveAction); drag->exec(Qt::CopyAction);
} }
void TextEditorLinkLabel::mouseReleaseEvent(QMouseEvent *event) void TextEditorLinkLabel::mouseReleaseEvent(QMouseEvent *event)

View File

@@ -55,6 +55,7 @@
#include <QTemporaryDir> #include <QTemporaryDir>
#include <QTimer> #include <QTimer>
#include <chrono> #include <chrono>
#include <iostream>
#include <thread> #include <thread>
using namespace std::chrono_literals; using namespace std::chrono_literals;
@@ -183,16 +184,6 @@ struct Data // because we have a cycle dependency
PrecompiledHeaderStorage<> preCompiledHeaderStorage{database}; PrecompiledHeaderStorage<> preCompiledHeaderStorage{database};
ClangBackEnd::ProgressCounter progressCounter{ ClangBackEnd::ProgressCounter progressCounter{
[&](int progress, int total) { clangPchManagerServer.setProgress(progress, total); }}; [&](int progress, int total) { clangPchManagerServer.setProgress(progress, total); }};
TaskScheduler systemTaskScheduler{pchCreatorManager,
pchTaskQueue,
progressCounter,
std::thread::hardware_concurrency(),
ClangBackEnd::CallDoInMainThreadAfterFinished::No};
TaskScheduler projectTaskScheduler{pchCreatorManager,
pchTaskQueue,
progressCounter,
std::thread::hardware_concurrency(),
ClangBackEnd::CallDoInMainThreadAfterFinished::Yes};
ClangBackEnd::PchTaskQueue pchTaskQueue{systemTaskScheduler, ClangBackEnd::PchTaskQueue pchTaskQueue{systemTaskScheduler,
projectTaskScheduler, projectTaskScheduler,
progressCounter, progressCounter,
@@ -212,10 +203,32 @@ struct Data // because we have a cycle dependency
database}; database};
ClangBackEnd::PchTaskGenerator pchTaskGenerator{buildDependencyProvider, pchTaskMerger}; ClangBackEnd::PchTaskGenerator pchTaskGenerator{buildDependencyProvider, pchTaskMerger};
PchManagerServer clangPchManagerServer{includeWatcher, pchTaskGenerator, projectParts, generatedFiles}; PchManagerServer clangPchManagerServer{includeWatcher, pchTaskGenerator, projectParts, generatedFiles};
TaskScheduler systemTaskScheduler{pchCreatorManager,
pchTaskQueue,
progressCounter,
std::thread::hardware_concurrency(),
ClangBackEnd::CallDoInMainThreadAfterFinished::No};
TaskScheduler projectTaskScheduler{pchCreatorManager,
pchTaskQueue,
progressCounter,
std::thread::hardware_concurrency(),
ClangBackEnd::CallDoInMainThreadAfterFinished::Yes};
}; };
#ifdef Q_OS_WIN
static void messageOutput(QtMsgType type, const QMessageLogContext &, const QString &msg)
{
std::wcout << msg.toStdWString() << std::endl;
if (type == QtFatalMsg)
abort();
}
#endif
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
#ifdef Q_OS_WIN
qInstallMessageHandler(messageOutput);
#endif
try { try {
QCoreApplication::setOrganizationName(QStringLiteral("QtProject")); QCoreApplication::setOrganizationName(QStringLiteral("QtProject"));
QCoreApplication::setOrganizationDomain(QStringLiteral("qt-project.org")); QCoreApplication::setOrganizationDomain(QStringLiteral("qt-project.org"));

View File

@@ -58,6 +58,7 @@ public:
auto &preprocessor = compilerInstance.getPreprocessor(); auto &preprocessor = compilerInstance.getPreprocessor();
preprocessor.SetSuppressIncludeNotFoundError(true); preprocessor.SetSuppressIncludeNotFoundError(true);
preprocessor.SetMacroExpansionOnlyInDirectives();
auto macroPreprocessorCallbacks = new CollectBuildDependencyPreprocessorCallbacks( auto macroPreprocessorCallbacks = new CollectBuildDependencyPreprocessorCallbacks(
m_buildDependency, m_buildDependency,

View File

@@ -66,6 +66,8 @@ void PchManagerServer::updateProjectParts(UpdateProjectPartsMessage &&message)
if (m_generatedFiles.isValid()) { if (m_generatedFiles.isValid()) {
m_pchTaskGenerator.addProjectParts(std::move(newProjectParts), m_pchTaskGenerator.addProjectParts(std::move(newProjectParts),
std::move(message.toolChainArguments)); std::move(message.toolChainArguments));
} else {
m_projectParts.updateDeferred(newProjectParts);
} }
} }

View File

@@ -43,7 +43,7 @@ public:
FilePathIds &&includes, FilePathIds &&includes,
FilePathIds &&allIncludes, FilePathIds &&allIncludes,
CompilerMacros &&compilerMacros, CompilerMacros &&compilerMacros,
UsedMacros &&usedMacros, Utils::SmallStringVector &&usedMacros,
Utils::SmallStringVector toolChainArguments, Utils::SmallStringVector toolChainArguments,
IncludeSearchPaths systemIncludeSearchPaths, IncludeSearchPaths systemIncludeSearchPaths,
IncludeSearchPaths projectIncludeSearchPaths, IncludeSearchPaths projectIncludeSearchPaths,
@@ -54,7 +54,6 @@ public:
, includes(includes) , includes(includes)
, allIncludes(allIncludes) , allIncludes(allIncludes)
, compilerMacros(compilerMacros) , compilerMacros(compilerMacros)
, usedMacros(usedMacros)
, systemIncludeSearchPaths(std::move(systemIncludeSearchPaths)) , systemIncludeSearchPaths(std::move(systemIncludeSearchPaths))
, projectIncludeSearchPaths(std::move(projectIncludeSearchPaths)) , projectIncludeSearchPaths(std::move(projectIncludeSearchPaths))
, toolChainArguments(std::move(toolChainArguments)) , toolChainArguments(std::move(toolChainArguments))
@@ -67,7 +66,7 @@ public:
FilePathIds &&includes, FilePathIds &&includes,
FilePathIds &&allIncludes, FilePathIds &&allIncludes,
CompilerMacros &&compilerMacros, CompilerMacros &&compilerMacros,
UsedMacros &&usedMacros, Utils::SmallStringVector &&usedMacros,
Utils::SmallStringVector toolChainArguments, Utils::SmallStringVector toolChainArguments,
IncludeSearchPaths systemIncludeSearchPaths, IncludeSearchPaths systemIncludeSearchPaths,
IncludeSearchPaths projectIncludeSearchPaths, IncludeSearchPaths projectIncludeSearchPaths,
@@ -78,7 +77,6 @@ public:
, includes(includes) , includes(includes)
, allIncludes(allIncludes) , allIncludes(allIncludes)
, compilerMacros(compilerMacros) , compilerMacros(compilerMacros)
, usedMacros(usedMacros)
, systemIncludeSearchPaths(std::move(systemIncludeSearchPaths)) , systemIncludeSearchPaths(std::move(systemIncludeSearchPaths))
, projectIncludeSearchPaths(std::move(projectIncludeSearchPaths)) , projectIncludeSearchPaths(std::move(projectIncludeSearchPaths))
, toolChainArguments(std::move(toolChainArguments)) , toolChainArguments(std::move(toolChainArguments))
@@ -92,7 +90,6 @@ public:
return first.systemPchPath == second.systemPchPath return first.systemPchPath == second.systemPchPath
&& first.projectPartIds == second.projectPartIds && first.includes == second.includes && first.projectPartIds == second.projectPartIds && first.includes == second.includes
&& first.compilerMacros == second.compilerMacros && first.compilerMacros == second.compilerMacros
&& first.usedMacros == second.usedMacros
&& first.systemIncludeSearchPaths == second.systemIncludeSearchPaths && first.systemIncludeSearchPaths == second.systemIncludeSearchPaths
&& first.projectIncludeSearchPaths == second.projectIncludeSearchPaths && first.projectIncludeSearchPaths == second.projectIncludeSearchPaths
&& first.toolChainArguments == second.toolChainArguments && first.toolChainArguments == second.toolChainArguments
@@ -109,13 +106,13 @@ public:
FilePathIds includes; FilePathIds includes;
FilePathIds allIncludes; FilePathIds allIncludes;
CompilerMacros compilerMacros; CompilerMacros compilerMacros;
UsedMacros usedMacros;
IncludeSearchPaths systemIncludeSearchPaths; IncludeSearchPaths systemIncludeSearchPaths;
IncludeSearchPaths projectIncludeSearchPaths; IncludeSearchPaths projectIncludeSearchPaths;
Utils::SmallStringVector toolChainArguments; Utils::SmallStringVector toolChainArguments;
Utils::Language language = Utils::Language::Cxx; Utils::Language language = Utils::Language::Cxx;
Utils::LanguageVersion languageVersion = Utils::LanguageVersion::CXX98; Utils::LanguageVersion languageVersion = Utils::LanguageVersion::CXX98;
Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None; Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None;
bool isMerged = false;
}; };
class PchTaskSet class PchTaskSet

View File

@@ -42,9 +42,9 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts,
for (auto &projectPart : projectParts) { for (auto &projectPart : projectParts) {
BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart); BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart);
UsedMacroFilter filter{buildDependency.includes, buildDependency.usedMacros}; UsedMacroFilter filter{buildDependency.includes,
buildDependency.usedMacros,
filter.filter(projectPart.compilerMacros); projectPart.compilerMacros};
pchTaskSets.emplace_back(PchTask{projectPart.projectPartId.clone(), pchTaskSets.emplace_back(PchTask{projectPart.projectPartId.clone(),
std::move(filter.topSystemIncludes), std::move(filter.topSystemIncludes),
@@ -53,7 +53,7 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts,
std::move(filter.systemUsedMacros), std::move(filter.systemUsedMacros),
projectPart.toolChainArguments, projectPart.toolChainArguments,
projectPart.systemIncludeSearchPaths, projectPart.systemIncludeSearchPaths,
projectPart.projectIncludeSearchPaths, {},
projectPart.language, projectPart.language,
projectPart.languageVersion, projectPart.languageVersion,
projectPart.languageExtension}, projectPart.languageExtension},

View File

@@ -30,20 +30,10 @@
namespace ClangBackEnd { namespace ClangBackEnd {
void PchTasksMerger::mergeTasks(PchTaskSets &&taskSets, void PchTasksMerger::mergeTasks(PchTaskSets &&taskSets,
Utils::SmallStringVector &&/*toolChainArguments*/) Utils::SmallStringVector && /*toolChainArguments*/)
{ {
PchTasks systemTasks; mergeSystemTasks(taskSets);
systemTasks.reserve(taskSets.size()); addProjectTasksToQueue(taskSets);
PchTasks projectTasks;
projectTasks.reserve(taskSets.size());
for (PchTaskSet &taskSet : taskSets) {
projectTasks.push_back(std::move(taskSet.project));
systemTasks.push_back(std::move(taskSet.system));
}
m_pchTaskQueue.addSystemPchTasks(std::move(systemTasks));
m_pchTaskQueue.addProjectPchTasks(std::move(projectTasks));
m_pchTaskQueue.processEntries(); m_pchTaskQueue.processEntries();
} }
@@ -52,4 +42,117 @@ void PchTasksMerger::removePchTasks(const Utils::SmallStringVector &projectPartI
m_pchTaskQueue.removePchTasks(projectPartIds); m_pchTaskQueue.removePchTasks(projectPartIds);
} }
template<typename Container, typename Result = std::remove_const_t<std::remove_reference_t<Container>>>
Result merge(Container &&first, Container &&second)
{
Result result;
result.reserve(first.size() + second.size());
std::set_union(std::make_move_iterator(first.begin()),
std::make_move_iterator(first.end()),
std::make_move_iterator(second.begin()),
std::make_move_iterator(second.end()),
std::back_inserter(result));
return result;
}
CompilerMacros PchTasksMerger::mergeMacros(const CompilerMacros &firstCompilerMacros,
const CompilerMacros &secondCompilerMacros)
{
return merge(firstCompilerMacros, secondCompilerMacros);
}
bool PchTasksMerger::hasDuplicates(const CompilerMacros &compilerMacros)
{
auto found = std::adjacent_find(compilerMacros.begin(),
compilerMacros.end(),
[](const CompilerMacro &first, const CompilerMacro &second) {
return first.key == second.key;
});
return found == compilerMacros.end();
}
IncludeSearchPaths mergeIncludeSearchPaths(IncludeSearchPaths &&first, IncludeSearchPaths &&second)
{
if (first.size() > second.size())
return merge(first, second);
return merge(first, second);
}
bool PchTasksMerger::mergePchTasks(PchTask &firstTask, PchTask &secondTask)
{
if (firstTask.language != secondTask.language || firstTask.isMerged || secondTask.isMerged)
return false;
CompilerMacros macros = mergeMacros(firstTask.compilerMacros, secondTask.compilerMacros);
secondTask.isMerged = hasDuplicates(macros);
if (secondTask.isMerged && firstTask.language == secondTask.language) {
firstTask.projectPartIds = merge(std::move(firstTask.projectPartIds),
std::move(secondTask.projectPartIds));
firstTask.includes = merge(std::move(firstTask.includes), std::move(secondTask.includes));
firstTask.allIncludes = merge(std::move(firstTask.allIncludes),
std::move(secondTask.allIncludes));
firstTask.compilerMacros = std::move(macros);
firstTask.systemIncludeSearchPaths = mergeIncludeSearchPaths(
std::move(firstTask.systemIncludeSearchPaths),
std::move(secondTask.systemIncludeSearchPaths));
firstTask.languageVersion = std::max(firstTask.languageVersion, secondTask.languageVersion);
firstTask.languageExtension = firstTask.languageExtension | secondTask.languageExtension;
}
return secondTask.isMerged;
}
void PchTasksMerger::mergePchTasks(PchTasks &tasks)
{
auto begin = tasks.begin();
while (begin != tasks.end()) {
begin = std::find_if(begin, tasks.end(), [](const auto &task) { return !task.isMerged; });
if (begin != tasks.end()) {
PchTask &baseTask = *begin;
++begin;
std::for_each(begin, tasks.end(), [&](PchTask &currentTask) {
mergePchTasks(baseTask, currentTask);
});
}
}
}
void PchTasksMerger::addProjectTasksToQueue(PchTaskSets &taskSets)
{
PchTasks projectTasks;
projectTasks.reserve(taskSets.size());
for (PchTaskSet &taskSet : taskSets)
projectTasks.push_back(std::move(taskSet.project));
m_pchTaskQueue.addProjectPchTasks(std::move(projectTasks));
}
void PchTasksMerger::mergeSystemTasks(PchTaskSets &taskSets)
{
PchTasks systemTasks;
systemTasks.reserve(taskSets.size());
for (PchTaskSet &taskSet : taskSets)
systemTasks.push_back(std::move(taskSet.system));
mergePchTasks(systemTasks);
systemTasks.erase(std::remove_if(systemTasks.begin(),
systemTasks.end(),
[](const PchTask &task) { return task.isMerged; }),
systemTasks.end());
m_pchTaskQueue.addSystemPchTasks(std::move(systemTasks));
}
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -32,7 +32,7 @@ namespace ClangBackEnd {
class PchTaskQueueInterface; class PchTaskQueueInterface;
class PchTasksMerger : public PchTasksMergerInterface class PchTasksMerger final : public PchTasksMergerInterface
{ {
public: public:
PchTasksMerger(PchTaskQueueInterface &pchTaskQueue) PchTasksMerger(PchTaskQueueInterface &pchTaskQueue)
@@ -42,6 +42,18 @@ public:
void mergeTasks(PchTaskSets &&taskSets, Utils::SmallStringVector &&toolChainArguments) override; void mergeTasks(PchTaskSets &&taskSets, Utils::SmallStringVector &&toolChainArguments) override;
void removePchTasks(const Utils::SmallStringVector &projectPartIds) override; void removePchTasks(const Utils::SmallStringVector &projectPartIds) override;
static CompilerMacros mergeMacros(const CompilerMacros &firstCompilerMacros,
const CompilerMacros &secondCompilerMacros);
static bool hasDuplicates(const CompilerMacros &compilerMacros);
static bool mergePchTasks(PchTask &first, PchTask &second);
static void mergePchTasks(PchTasks &tasks);
private:
void addProjectTasksToQueue(PchTaskSets &taskSets);
void mergeSystemTasks(PchTaskSets &taskSets);
private: private:
PchTaskQueueInterface &m_pchTaskQueue; PchTaskQueueInterface &m_pchTaskQueue;
}; };

View File

@@ -80,6 +80,11 @@ public:
, m_callDoInMainThreadAfterFinished(callDoInMainThreadAfterFinished) , m_callDoInMainThreadAfterFinished(callDoInMainThreadAfterFinished)
{} {}
~TaskScheduler()
{
syncTasks();
}
void addTasks(std::vector<Task> &&tasks) void addTasks(std::vector<Task> &&tasks)
{ {
for (auto &task : tasks) { for (auto &task : tasks) {

View File

@@ -32,6 +32,27 @@
namespace ClangBackEnd { namespace ClangBackEnd {
template<typename InputIterator1, typename InputIterator2, typename OutputIterator, typename Compare>
inline OutputIterator set_greedy_intersection(InputIterator1 first1,
InputIterator1 last1,
InputIterator2 first2,
InputIterator2 last2,
OutputIterator result,
Compare comp)
{
while (first1 != last1 && first2 != last2)
if (comp(*first1, *first2))
++first1;
else if (comp(*first2, *first1))
++first2;
else {
*result = *first1;
++first1;
++result;
}
return result;
}
class UsedMacroFilter class UsedMacroFilter
{ {
public: public:
@@ -41,11 +62,14 @@ public:
FilePathIds system; FilePathIds system;
}; };
UsedMacroFilter(const SourceEntries &includes, const UsedMacros &usedMacros) UsedMacroFilter(const SourceEntries &includes,
const UsedMacros &usedMacros,
const CompilerMacros &compilerMacros)
{ {
filterIncludes(includes); filterIncludes(includes);
systemUsedMacros = filterUsedMarcos(usedMacros, systemIncludes); systemUsedMacros = filterUsedMarcos(usedMacros, systemIncludes);
projectUsedMacros = filterUsedMarcos(usedMacros, projectIncludes); projectUsedMacros = filterUsedMarcos(usedMacros, projectIncludes);
filter(compilerMacros);
} }
void filterIncludes(const SourceEntries &includes) void filterIncludes(const SourceEntries &includes)
@@ -98,7 +122,8 @@ private:
allIncludes.emplace_back(include.sourceId); allIncludes.emplace_back(include.sourceId);
} }
static UsedMacros filterUsedMarcos(const UsedMacros &usedMacros, const FilePathIds &filePathId) static Utils::SmallStringVector filterUsedMarcos(const UsedMacros &usedMacros,
const FilePathIds &filePathId)
{ {
struct Compare struct Compare
{ {
@@ -113,52 +138,57 @@ private:
} }
}; };
UsedMacros filtertedMacros; Utils::SmallStringVector filtertedMacros;
filtertedMacros.reserve(usedMacros.size()); filtertedMacros.reserve(usedMacros.size());
std::set_intersection(usedMacros.begin(), set_greedy_intersection(usedMacros.begin(),
usedMacros.end(), usedMacros.end(),
filePathId.begin(), filePathId.begin(),
filePathId.end(), filePathId.end(),
std::back_inserter(filtertedMacros), std::back_inserter(filtertedMacros),
Compare{}); Compare{});
std::sort(filtertedMacros.begin(), std::sort(filtertedMacros.begin(), filtertedMacros.end());
filtertedMacros.end(),
[](const UsedMacro &first, const UsedMacro &second) {
return first.macroName < second.macroName;
});
return filtertedMacros; return filtertedMacros;
} }
static CompilerMacros filtercompilerMacros(const CompilerMacros &indexedCompilerMacro, static CompilerMacros filtercompilerMacros(const CompilerMacros &indexedCompilerMacro,
const UsedMacros &usedMacros) const Utils::SmallStringVector &usedMacros)
{ {
CompilerMacros filtertedCompilerMacros;
filtertedCompilerMacros.reserve(indexedCompilerMacro.size() + usedMacros.size());
struct Compare struct Compare
{ {
bool operator()(const UsedMacro &usedMacro, bool operator()(const CompilerMacro &compilerMacro, Utils::SmallStringView usedMacro)
const CompilerMacro &compileMacro)
{ {
return usedMacro.macroName < compileMacro.key; return compilerMacro.key < usedMacro;
} }
bool operator()(const CompilerMacro &compileMacro, bool operator()(Utils::SmallStringView usedMacro, const CompilerMacro &compilerMacro)
const UsedMacro &usedMacro)
{ {
return compileMacro.key < usedMacro.macroName; return usedMacro < compilerMacro.key;
} }
}; };
CompilerMacros filtertedCompilerMacros; set_greedy_intersection(indexedCompilerMacro.begin(),
filtertedCompilerMacros.reserve(indexedCompilerMacro.size()); indexedCompilerMacro.end(),
usedMacros.begin(),
usedMacros.end(),
std::back_inserter(filtertedCompilerMacros),
Compare{});
std::set_intersection(indexedCompilerMacro.begin(), auto split = filtertedCompilerMacros.end();
indexedCompilerMacro.end(),
usedMacros.begin(), std::set_difference(usedMacros.begin(),
usedMacros.end(), usedMacros.end(),
std::back_inserter(filtertedCompilerMacros), filtertedCompilerMacros.begin(),
Compare{}); filtertedCompilerMacros.end(),
std::back_inserter(filtertedCompilerMacros),
Compare{});
std::inplace_merge(filtertedCompilerMacros.begin(), split, filtertedCompilerMacros.end());
return filtertedCompilerMacros; return filtertedCompilerMacros;
} }
@@ -169,8 +199,8 @@ public:
FilePathIds systemIncludes; FilePathIds systemIncludes;
FilePathIds topProjectIncludes; FilePathIds topProjectIncludes;
FilePathIds topSystemIncludes; FilePathIds topSystemIncludes;
UsedMacros projectUsedMacros; Utils::SmallStringVector projectUsedMacros;
UsedMacros systemUsedMacros; Utils::SmallStringVector systemUsedMacros;
CompilerMacros projectCompilerMacros; CompilerMacros projectCompilerMacros;
CompilerMacros systemCompilerMacros; CompilerMacros systemCompilerMacros;
}; };

View File

@@ -39,6 +39,7 @@
#include <sqliteexception.h> #include <sqliteexception.h>
#include <chrono> #include <chrono>
#include <iostream>
using namespace std::chrono_literals; using namespace std::chrono_literals;
@@ -93,12 +94,24 @@ struct Data // because we have a cycle dependency
RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database}; RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database};
FilePathCaching filePathCache{database}; FilePathCaching filePathCache{database};
GeneratedFiles generatedFiles; GeneratedFiles generatedFiles;
SymbolIndexing symbolIndexing{database, filePathCache, generatedFiles, [&] (int progress, int total) { clangCodeModelServer.setProgress(progress, total); }};
RefactoringServer clangCodeModelServer{symbolIndexing, filePathCache, generatedFiles}; RefactoringServer clangCodeModelServer{symbolIndexing, filePathCache, generatedFiles};
SymbolIndexing symbolIndexing{database, filePathCache, generatedFiles, [&] (int progress, int total) { clangCodeModelServer.setProgress(progress, total); }};
}; };
#ifdef Q_OS_WIN
static void messageOutput(QtMsgType type, const QMessageLogContext &, const QString &msg)
{
std::wcout << msg.toStdWString() << std::endl;
if (type == QtFatalMsg)
abort();
}
#endif
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
#ifdef Q_OS_WIN
qInstallMessageHandler(messageOutput);
#endif
try { try {
QCoreApplication::setOrganizationName(QStringLiteral("QtProject")); QCoreApplication::setOrganizationName(QStringLiteral("QtProject"));
QCoreApplication::setOrganizationDomain(QStringLiteral("qt-project.org")); QCoreApplication::setOrganizationDomain(QStringLiteral("qt-project.org"));

View File

@@ -95,8 +95,6 @@ public:
bool isClean() const; bool isClean() const;
private: private:
RefactoringCompilationDatabase m_compilationDatabase; RefactoringCompilationDatabase m_compilationDatabase;
std::vector<FileContent> m_fileContents; std::vector<FileContent> m_fileContents;

View File

@@ -45,6 +45,8 @@ bool CollectMacrosSourceFileCallbacks::handleBeginSource(clang::CompilerInstance
compilerInstance.getPreprocessorPtr(), compilerInstance.getPreprocessorPtr(),
m_sourcesManager); m_sourcesManager);
compilerInstance.getLangOpts().DelayedTemplateParsing = false;
compilerInstance.getPreprocessorPtr()->SetSuppressIncludeNotFoundError(true);
compilerInstance.getPreprocessorPtr()->addPPCallbacks(std::move(callbacks)); compilerInstance.getPreprocessorPtr()->addPPCallbacks(std::move(callbacks));
return true; return true;

View File

@@ -124,8 +124,6 @@ private:
FileStatusCache m_fileStatusCache{m_filePathCache}; FileStatusCache m_fileStatusCache{m_filePathCache};
SymbolsCollectorManager m_collectorManger; SymbolsCollectorManager m_collectorManger;
ProgressCounter m_progressCounter; ProgressCounter m_progressCounter;
SymbolIndexerTaskScheduler m_indexerScheduler;
SymbolIndexerTaskQueue m_indexerQueue{m_indexerScheduler, m_progressCounter};
SymbolIndexer m_indexer{m_indexerQueue, SymbolIndexer m_indexer{m_indexerQueue,
m_symbolStorage, m_symbolStorage,
m_buildDependencyStorage, m_buildDependencyStorage,
@@ -133,6 +131,8 @@ private:
m_filePathCache, m_filePathCache,
m_fileStatusCache, m_fileStatusCache,
m_symbolStorage.m_database}; m_symbolStorage.m_database};
SymbolIndexerTaskQueue m_indexerQueue{m_indexerScheduler, m_progressCounter};
SymbolIndexerTaskScheduler m_indexerScheduler;
}; };
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -341,12 +341,14 @@ public:
m_database}; m_database};
mutable ReadStatement m_getProjectPartArtefactsBySourceId{ mutable ReadStatement m_getProjectPartArtefactsBySourceId{
"SELECT toolChainArguments, compilerMacros, systemIncludeSearchPaths, " "SELECT toolChainArguments, compilerMacros, systemIncludeSearchPaths, "
"projectIncludeSearchPaths, projectPartId FROM projectParts WHERE projectPartId = (SELECT " "projectIncludeSearchPaths, projectPartId, language, languageVersion, languageExtension "
"FROM projectParts WHERE projectPartId = (SELECT "
"projectPartId FROM projectPartsSources WHERE sourceId = ?)", "projectPartId FROM projectPartsSources WHERE sourceId = ?)",
m_database}; m_database};
mutable ReadStatement m_getProjectPartArtefactsByProjectPartName{ mutable ReadStatement m_getProjectPartArtefactsByProjectPartName{
"SELECT toolChainArguments, compilerMacros, systemIncludeSearchPaths, " "SELECT toolChainArguments, compilerMacros, systemIncludeSearchPaths, "
"projectIncludeSearchPaths, projectPartId FROM projectParts WHERE projectPartName = ?", "projectIncludeSearchPaths, projectPartId, language, languageVersion, languageExtension "
"FROM projectParts WHERE projectPartName = ?",
m_database}; m_database};
mutable ReadStatement m_getPrecompiledHeader{ mutable ReadStatement m_getPrecompiledHeader{
"SELECT projectPchPath, projectPchBuildTime FROM precompiledHeaders WHERE projectPartId = ?", "SELECT projectPchPath, projectPchBuildTime FROM precompiledHeaders WHERE projectPartId = ?",

View File

@@ -68,7 +68,8 @@ public:
bool isAlreadyParsed(clang::FileID fileId) bool isAlreadyParsed(clang::FileID fileId)
{ {
const clang::FileEntry *fileEntry = m_sourceManager->getFileEntryForID(fileId); const clang::FileEntry *fileEntry = m_sourceManager->getFileEntryForID(fileId);
if (!fileEntry)
return false;
return m_sourcesManager.alreadyParsed(filePathId(fileEntry), return m_sourcesManager.alreadyParsed(filePathId(fileEntry),
fileEntry->getModificationTime()); fileEntry->getModificationTime());
} }

View File

@@ -62,6 +62,10 @@ public:
{ {
return !(first == second); return !(first == second);
} }
operator Utils::SmallStringView() const { return macroName; }
operator const Utils::SmallString &() const { return macroName; }
public: public:
Utils::SmallString macroName; Utils::SmallString macroName;
FilePathId filePathId; FilePathId filePathId;

View File

@@ -103,7 +103,7 @@ def performTest(workingDir, projectName, availableConfigs):
compareEventsTab(model, "events_qt%s.tsv" % qtVersion) compareEventsTab(model, "events_qt%s.tsv" % qtVersion)
test.compare(dumpItems(model, column=colPercent)[0], '100 %') test.compare(dumpItems(model, column=colPercent)[0], '100 %')
# cannot run following test on colShortest (unstable) # cannot run following test on colShortest (unstable)
for i in [colTotal, colMean, colMedian, colLongest]: for i in [colMean, colMedian, colLongest]:
for item in dumpItems(model, column=i)[2:5]: for item in dumpItems(model, column=i)[2:5]:
test.verify(item.endswith('ms'), "Verify that '%s' ends with 'ms'" % item) test.verify(item.endswith('ms'), "Verify that '%s' ends with 'ms'" % item)
for i in [colTotal, colMean, colMedian, colLongest, colShortest]: for i in [colTotal, colMean, colMedian, colLongest, colShortest]:

View File

@@ -435,9 +435,7 @@ TEST_F(BuildDependencyCollector, CollectUsedMacrosWithExternalDefine)
ElementsAre(Eq(UsedMacro{"DEFINED", fileId}), ElementsAre(Eq(UsedMacro{"DEFINED", fileId}),
Eq(UsedMacro{"IF_DEFINE", fileId}), Eq(UsedMacro{"IF_DEFINE", fileId}),
Eq(UsedMacro{"__clang__", fileId}), Eq(UsedMacro{"__clang__", fileId}),
Eq(UsedMacro{"CLASS_EXPORT", fileId}),
Eq(UsedMacro{"IF_NOT_DEFINE", fileId}), Eq(UsedMacro{"IF_NOT_DEFINE", fileId}),
Eq(UsedMacro{"MACRO_EXPANSION", fileId}),
Eq(UsedMacro{"COMPILER_ARGUMENT", fileId}))); Eq(UsedMacro{"COMPILER_ARGUMENT", fileId})));
} }
@@ -452,9 +450,7 @@ TEST_F(BuildDependencyCollector, CollectUsedMacrosWithoutExternalDefine)
ElementsAre(Eq(UsedMacro{"DEFINED", fileId}), ElementsAre(Eq(UsedMacro{"DEFINED", fileId}),
Eq(UsedMacro{"IF_DEFINE", fileId}), Eq(UsedMacro{"IF_DEFINE", fileId}),
Eq(UsedMacro{"__clang__", fileId}), Eq(UsedMacro{"__clang__", fileId}),
Eq(UsedMacro{"CLASS_EXPORT", fileId}),
Eq(UsedMacro{"IF_NOT_DEFINE", fileId}), Eq(UsedMacro{"IF_NOT_DEFINE", fileId}),
Eq(UsedMacro{"MACRO_EXPANSION", fileId}),
Eq(UsedMacro{"COMPILER_ARGUMENT", fileId}))); Eq(UsedMacro{"COMPILER_ARGUMENT", fileId})));
} }
@@ -639,7 +635,6 @@ TEST_F(BuildDependencyCollector, Create)
SourceType::TopProjectInclude))), SourceType::TopProjectInclude))),
Field(&BuildDependency::usedMacros, Field(&BuildDependency::usedMacros,
UnorderedElementsAre( UnorderedElementsAre(
UsedMacro{"DEFINE", id(TESTDATA_DIR "/builddependencycollector/project/macros.h")},
UsedMacro{"IFDEF", id(TESTDATA_DIR "/builddependencycollector/project/macros.h")}, UsedMacro{"IFDEF", id(TESTDATA_DIR "/builddependencycollector/project/macros.h")},
UsedMacro{"DEFINED", UsedMacro{"DEFINED",
id(TESTDATA_DIR "/builddependencycollector/project/macros.h")})), id(TESTDATA_DIR "/builddependencycollector/project/macros.h")})),

View File

@@ -51,12 +51,27 @@ public:
} }
}; };
class ClangFormatExtendedIndenter : public ClangFormatIndenter
{
public:
ClangFormatExtendedIndenter(QTextDocument *doc)
: ClangFormatIndenter(doc)
{}
bool formatWhileTyping() const override
{
return true;
}
};
class ClangFormat : public ::testing::Test class ClangFormat : public ::testing::Test
{ {
protected: protected:
void SetUp() final void SetUp() final
{ {
indenter.setFileName(Utils::FileName::fromString(TESTDATA_DIR "/clangformat/test.cpp")); indenter.setFileName(Utils::FileName::fromString(TESTDATA_DIR "/clangformat/test.cpp"));
extendedIndenter.setFileName(
Utils::FileName::fromString(TESTDATA_DIR "/clangformat/test.cpp"));
} }
void insertLines(const std::vector<QString> &lines) void insertLines(const std::vector<QString> &lines)
@@ -85,6 +100,7 @@ protected:
QTextDocument doc; QTextDocument doc;
ClangFormatIndenter indenter{&doc}; ClangFormatIndenter indenter{&doc};
ClangFormatExtendedIndenter extendedIndenter{&doc};
QTextCursor cursor{&doc}; QTextCursor cursor{&doc};
}; };
@@ -315,6 +331,83 @@ TEST_F(ClangFormat, NoExtraIndentAfterBraceInitialization)
"return 0;")); "return 0;"));
} }
TEST_F(ClangFormat, IndentFunctionBodyAndFormatBeforeIt)
{
insertLines({"int foo(int a, int b,",
" int c, int d",
" ) {",
"",
"}"});
extendedIndenter.indentBlock(doc.findBlockByNumber(3), QChar::Null, TextEditor::TabSettings());
ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b, int c, int d)",
"{",
" ",
"}"));
}
TEST_F(ClangFormat, IndentAfterFunctionBodyAndNotFormatBefore)
{
insertLines({"int foo(int a, int b, int c, int d)",
"{",
" ",
"}"});
extendedIndenter.indentBlock(doc.findBlockByNumber(3),
QChar::Null,
TextEditor::TabSettings(),
doc.characterCount() - 3);
ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b, int c, int d)",
"{",
" ",
"}"));
}
TEST_F(ClangFormat, ReformatToEmptyFunction)
{
insertLines({"int foo(int a, int b, int c, int d)",
"{",
" ",
"}",
""});
extendedIndenter.indentBlock(doc.findBlockByNumber(4), QChar::Null, TextEditor::TabSettings());
ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b, int c, int d) {}",
""));
}
TEST_F(ClangFormat, ReformatToNonEmptyFunction)
{
insertLines({"int foo(int a, int b) {",
"",
"}"});
extendedIndenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings());
ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b)",
"{",
" ",
"}"));
}
TEST_F(ClangFormat, IndentIfBodyAndFormatBeforeIt)
{
insertLines({"if(a && b",
" &&c && d",
" ) {",
"",
"}"});
extendedIndenter.indentBlock(doc.findBlockByNumber(3), QChar::Null, TextEditor::TabSettings());
ASSERT_THAT(documentLines(), ElementsAre("if (a && b && c && d) {",
" ",
"}"));
}
TEST_F(ClangFormat, FormatBasicFile) TEST_F(ClangFormat, FormatBasicFile)
{ {
insertLines({"int main()", insertLines({"int main()",

View File

@@ -136,7 +136,7 @@ TYPED_TEST(CommandLineBuilder, CTask)
ASSERT_THAT( ASSERT_THAT(
builder.commandLine, builder.commandLine,
ElementsAre("clang", "-x", "c-header", "-std=c11", "-nostdinc", "-nostdlibinc", "/source/file.c")); ElementsAre("clang", "-x", "c-header", "-std=c11", "-nostdinc", "-nostdinc++", "/source/file.c"));
} }
TYPED_TEST(CommandLineBuilder, ObjectiveCTask) TYPED_TEST(CommandLineBuilder, ObjectiveCTask)
@@ -153,7 +153,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCTask)
"objective-c-header", "objective-c-header",
"-std=c11", "-std=c11",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"/source/file.c")); "/source/file.c"));
} }
@@ -170,7 +170,7 @@ TYPED_TEST(CommandLineBuilder, CppTask)
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"/source/file.cpp")); "/source/file.cpp"));
} }
@@ -188,7 +188,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCppTask)
"objective-c++-header", "objective-c++-header",
"-std=c++98", "-std=c++98",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"/source/file.cpp")); "/source/file.cpp"));
} }
@@ -420,7 +420,7 @@ TYPED_TEST(CommandLineBuilder, IncludesOrder)
"c++-header", "c++-header",
"-std=c++11", "-std=c++11",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"-I", "-I",
"/include/foo", "/include/foo",
"-I", "-I",
@@ -441,7 +441,7 @@ TYPED_TEST(CommandLineBuilder, EmptySourceFile)
Builder<TypeParam> builder{this->emptyProjectInfo, {}, {}}; Builder<TypeParam> builder{this->emptyProjectInfo, {}, {}};
ASSERT_THAT(builder.commandLine, ASSERT_THAT(builder.commandLine,
ElementsAre("clang++", "-x", "c++-header", "-std=c++98", "-nostdinc", "-nostdlibinc")); ElementsAre("clang++", "-x", "c++-header", "-std=c++98", "-nostdinc", "-nostdinc++"));
} }
TYPED_TEST(CommandLineBuilder, SourceFile) TYPED_TEST(CommandLineBuilder, SourceFile)
@@ -454,7 +454,7 @@ TYPED_TEST(CommandLineBuilder, SourceFile)
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"/source/file.cpp")); "/source/file.cpp"));
} }
@@ -469,7 +469,7 @@ TYPED_TEST(CommandLineBuilder, EmptyOutputFile)
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"/source/file.cpp")); "/source/file.cpp"));
} }
@@ -483,7 +483,7 @@ TYPED_TEST(CommandLineBuilder, OutputFile)
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"-o", "-o",
"/output/file.o", "/output/file.o",
"/source/file.cpp")); "/source/file.cpp"));
@@ -499,7 +499,7 @@ TYPED_TEST(CommandLineBuilder, IncludePchPath)
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"-Xclang", "-Xclang",
"-include-pch", "-include-pch",
"-Xclang", "-Xclang",
@@ -511,7 +511,7 @@ TYPED_TEST(CommandLineBuilder, IncludePchPath)
TYPED_TEST(CommandLineBuilder, CompilerMacros) TYPED_TEST(CommandLineBuilder, CompilerMacros)
{ {
this->emptyProjectInfo.compilerMacros = {{"YI", "1", 2}, {"ER", "2", 1}}; this->emptyProjectInfo.compilerMacros = {{"YI", "1", 2}, {"ER", "2", 1}, {"SAN"}};
Builder<TypeParam> builder{this->emptyProjectInfo}; Builder<TypeParam> builder{this->emptyProjectInfo};
@@ -521,7 +521,7 @@ TYPED_TEST(CommandLineBuilder, CompilerMacros)
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"-DER=2", "-DER=2",
"-DYI=1")); "-DYI=1"));
} }

View File

@@ -1157,10 +1157,9 @@ std::ostream &operator<<(std::ostream &out, const PchCreatorIncludes &includes)
std::ostream &operator<<(std::ostream &out, const PchTask &task) std::ostream &operator<<(std::ostream &out, const PchTask &task)
{ {
return out << "(" << task.projectPartIds << ", " << task.includes << ", " << task.compilerMacros return out << "(" << task.projectPartIds << ", " << task.includes << ", " << task.compilerMacros
<< ", " << task.usedMacros << ", " << toText(task.language) << ", " << toText(task.language) << ", " << task.systemIncludeSearchPaths << ", "
<< task.systemIncludeSearchPaths << ", " << task.projectIncludeSearchPaths << ", " << task.projectIncludeSearchPaths << ", " << task.toolChainArguments << ", "
<< task.toolChainArguments << ", " << toText(task.languageVersion) << ", " << toText(task.languageVersion) << ", " << toText(task.languageExtension) << ")";
<< toText(task.languageExtension) << ")";
} }
std::ostream &operator<<(std::ostream &out, const PchTaskSet &taskSet) std::ostream &operator<<(std::ostream &out, const PchTaskSet &taskSet)

View File

@@ -157,7 +157,7 @@ TEST_F(PchCreator, CreateProjectPartClangCompilerArguments)
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"-I", "-I",
TESTDATA_DIR "/builddependencycollector/project", TESTDATA_DIR "/builddependencycollector/project",
"-isystem", "-isystem",
@@ -183,7 +183,7 @@ TEST_F(PchCreator, CreateProjectPartClangCompilerArgumentsWithSystemPch)
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"-I", "-I",
TESTDATA_DIR "/builddependencycollector/project", TESTDATA_DIR "/builddependencycollector/project",
"-isystem", "-isystem",

View File

@@ -47,6 +47,7 @@ using Utils::SmallString;
using ClangBackEnd::V2::FileContainer; using ClangBackEnd::V2::FileContainer;
using ClangBackEnd::V2::FileContainers; using ClangBackEnd::V2::FileContainers;
using ClangBackEnd::ProjectPartContainer; using ClangBackEnd::ProjectPartContainer;
using ClangBackEnd::ProjectPartContainers;
class PchManagerServer : public ::testing::Test class PchManagerServer : public ::testing::Test
{ {
@@ -198,8 +199,11 @@ TEST_F(PchManagerServer, DontGeneratePchIfGeneratedFilesAreNotValid)
{ {
InSequence s; InSequence s;
EXPECT_CALL(mockProjectParts, update(ElementsAre(projectPart1)))
.WillOnce(Return(ProjectPartContainers{projectPart1}));
EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(false)); EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(false));
EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)).Times(0); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)).Times(0);
EXPECT_CALL(mockProjectParts, updateDeferred(ElementsAre(projectPart1)));
server.updateProjectParts( server.updateProjectParts(
ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}}); ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}});
@@ -209,8 +213,11 @@ TEST_F(PchManagerServer, GeneratePchIfGeneratedFilesAreValid)
{ {
InSequence s; InSequence s;
EXPECT_CALL(mockProjectParts, update(ElementsAre(projectPart1)))
.WillOnce(Return(ProjectPartContainers{projectPart1}));
EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(true)); EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(true));
EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _));
EXPECT_CALL(mockProjectParts, updateDeferred(_)).Times(0);
server.updateProjectParts( server.updateProjectParts(
ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}}); ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}});

View File

@@ -99,7 +99,6 @@ TEST_F(PchTaskGenerator, AddProjectParts)
Field(&PchTask::allIncludes, IsEmpty()), Field(&PchTask::allIncludes, IsEmpty()),
Field(&PchTask::compilerMacros, Field(&PchTask::compilerMacros,
ElementsAre(CompilerMacro{"SE", "4", 4}, CompilerMacro{"WU", "5", 5})), ElementsAre(CompilerMacro{"SE", "4", 4}, CompilerMacro{"WU", "5", 5})),
Field(&PchTask::usedMacros, ElementsAre(UsedMacro{"SE", 4}, UsedMacro{"WU", 5})),
Field(&PchTask::systemIncludeSearchPaths, Field(&PchTask::systemIncludeSearchPaths,
ElementsAre( ElementsAre(
IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System},
@@ -120,7 +119,6 @@ TEST_F(PchTaskGenerator, AddProjectParts)
Field(&PchTask::allIncludes, ElementsAre(1, 2, 3, 4, 5)), Field(&PchTask::allIncludes, ElementsAre(1, 2, 3, 4, 5)),
Field(&PchTask::compilerMacros, Field(&PchTask::compilerMacros,
ElementsAre(CompilerMacro{"YI", "1", 1}, CompilerMacro{"SAN", "3", 3})), ElementsAre(CompilerMacro{"YI", "1", 1}, CompilerMacro{"SAN", "3", 3})),
Field(&PchTask::usedMacros, ElementsAre(UsedMacro{"YI", 1}, UsedMacro{"SAN", 3})),
Field(&PchTask::systemIncludeSearchPaths, Field(&PchTask::systemIncludeSearchPaths,
ElementsAre( ElementsAre(
IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System},

View File

@@ -31,11 +31,14 @@
namespace { namespace {
using ClangBackEnd::CompilerMacro;
using ClangBackEnd::CompilerMacros;
using ClangBackEnd::IncludeSearchPath; using ClangBackEnd::IncludeSearchPath;
using ClangBackEnd::IncludeSearchPathType; using ClangBackEnd::IncludeSearchPathType;
using ClangBackEnd::PchTask; using ClangBackEnd::PchTask;
using ClangBackEnd::PchTaskSet; using ClangBackEnd::PchTaskSet;
using Merger = ClangBackEnd::PchTasksMerger;
using Id = ClangBackEnd::FilePathId;
class PchTasksMerger : public testing::Test class PchTasksMerger : public testing::Test
{ {
protected: protected:
@@ -51,48 +54,58 @@ protected:
ClangBackEnd::PchTasksMerger merger{mockPchTaskQueue}; ClangBackEnd::PchTasksMerger merger{mockPchTaskQueue};
PchTask systemTask1{"ProjectPart1", PchTask systemTask1{"ProjectPart1",
{1, 2}, {1, 2},
{1, 2}, {1, 2, 3},
{{"YI", "1", 1}, {"SAN", "3", 3}}, {{"YI", "1", 1}, {"SAN", "3", 3}},
{{"LIANG", 0}, {"YI", 1}}, {"YI", "LIANG"},
{"--yi"}, {"--yi"},
{IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, {{"/system/path", 2, IncludeSearchPathType::System},
IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, {"/builtin/path2", 3, IncludeSearchPathType::BuiltIn},
IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, {"/framework/path", 1, IncludeSearchPathType::System}},
{IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, {{"/to/path1", 1, IncludeSearchPathType::User},
IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}}; {"/to/path2", 2, IncludeSearchPathType::User}}};
PchTask projectTask1{"ProjectPart1", PchTask projectTask1{"ProjectPart1",
{11, 12}, {11, 12},
{11, 12}, {11, 12},
{{"SE", "4", 4}, {"WU", "5", 5}}, {{"SE", "4", 4}, {"WU", "5", 5}},
{{"ER", 2}, {"SAN", 3}}, {"ER", "SAN"},
{"--yi"}, {"--yi"},
{IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, {{"/system/path", 1, IncludeSearchPathType::System},
IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, {"/builtin/path", 2, IncludeSearchPathType::BuiltIn}},
IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, {{"/to/path1", 1, IncludeSearchPathType::User},
{IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, {"/to/path2", 2, IncludeSearchPathType::User}}};
IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}};
PchTask systemTask2{"ProjectPart2", PchTask systemTask2{"ProjectPart2",
{1, 2}, {11, 12},
{1, 2}, {11, 12, 13},
{{"YI", "1", 1}, {"SAN", "3", 3}}, {{"SE", "4", 4}, {"WU", "5", 5}},
{{"LIANG", 0}, {"YI", 1}}, {"ER", "SAN"},
{"--yi"}, {"--yi"},
{IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, {{"/system/path", 2, IncludeSearchPathType::System},
IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, {"/builtin/path", 3, IncludeSearchPathType::BuiltIn},
IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, {"/framework/path", 1, IncludeSearchPathType::System}},
{IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, {{"/to/path1", 1, IncludeSearchPathType::User},
IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}}; {"/to/path2", 2, IncludeSearchPathType::User}}};
PchTask projectTask2{"ProjectPart2", PchTask projectTask2{"ProjectPart2",
{11, 12}, {11, 12},
{11, 12}, {11, 12},
{{"SE", "4", 4}, {"WU", "5", 5}}, {{"SE", "4", 4}, {"WU", "5", 5}},
{{"ER", 2}, {"SAN", 3}}, {"ER", "SAN"},
{"--yi"}, {"--yi"},
{IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, {{"/system/path", 2, IncludeSearchPathType::System},
IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, {"/builtin/path", 3, IncludeSearchPathType::BuiltIn},
IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, {"/framework/path", 1, IncludeSearchPathType::System}},
{IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, {{"/to/path1", 1, IncludeSearchPathType::User},
IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}}; {"/to/path2", 2, IncludeSearchPathType::User}}};
PchTask systemTask3{"ProjectPart3",
{1, 2},
{1, 2},
{{"YI", "2", 1}, {"SAN", "3", 3}},
{"YI", "LIANG"},
{"--yi"},
{{"/system/path", 2, IncludeSearchPathType::System},
{"/builtin/path", 3, IncludeSearchPathType::BuiltIn},
{"/framework/path", 1, IncludeSearchPathType::System}},
{{"/to/path1", 1, IncludeSearchPathType::User},
{"/to/path2", 2, IncludeSearchPathType::User}}};
Utils::SmallStringVector toolChainArguments = {"toolChainArguments"}; Utils::SmallStringVector toolChainArguments = {"toolChainArguments"};
}; };
@@ -103,21 +116,33 @@ TEST_F(PchTasksMerger, AddProjectTasks)
EXPECT_CALL(mockPchTaskQueue, addProjectPchTasks(ElementsAre(projectTask1, projectTask2))); EXPECT_CALL(mockPchTaskQueue, addProjectPchTasks(ElementsAre(projectTask1, projectTask2)));
EXPECT_CALL(mockPchTaskQueue, processEntries()); EXPECT_CALL(mockPchTaskQueue, processEntries());
merger.mergeTasks( merger.mergeTasks({{clone(systemTask1), clone(projectTask1)},
{{clone(systemTask1), clone(projectTask1)}, {clone(systemTask1), clone(projectTask2)}}, {clone(systemTask1), clone(projectTask2)}},
std::move(toolChainArguments)); std::move(toolChainArguments));
} }
TEST_F(PchTasksMerger, AddSystemTasks) TEST_F(PchTasksMerger, AddSystemTasks)
{ {
InSequence s; InSequence s;
EXPECT_CALL(mockPchTaskQueue, addSystemPchTasks(ElementsAre(systemTask1, systemTask2))); EXPECT_CALL(mockPchTaskQueue, addSystemPchTasks(ElementsAre(_, systemTask3)));
EXPECT_CALL(mockPchTaskQueue, processEntries()); EXPECT_CALL(mockPchTaskQueue, processEntries());
merger.mergeTasks( merger.mergeTasks({{clone(systemTask1), clone(projectTask1)},
{{clone(systemTask1), clone(projectTask1)}, {clone(systemTask2), clone(projectTask2)}}, {clone(systemTask2), clone(projectTask2)},
std::move(toolChainArguments)); {clone(systemTask3), clone(projectTask2)}},
std::move(toolChainArguments));
}
TEST_F(PchTasksMerger, AddSystemOnlyOneTask)
{
InSequence s;
EXPECT_CALL(mockPchTaskQueue, addSystemPchTasks(ElementsAre(systemTask1)));
EXPECT_CALL(mockPchTaskQueue, processEntries());
merger.mergeTasks({{clone(systemTask1), clone(projectTask1)}},
std::move(toolChainArguments));
} }
TEST_F(PchTasksMerger, RemoveTasks) TEST_F(PchTasksMerger, RemoveTasks)
@@ -126,4 +151,233 @@ TEST_F(PchTasksMerger, RemoveTasks)
merger.removePchTasks({"project1", "project2"}); merger.removePchTasks({"project1", "project2"});
} }
TEST_F(PchTasksMerger, MergeMacros)
{
CompilerMacros compilerMacros1{{"ER", "2", 2}, {"SE", "4", 1}, {"YI"}, {"SAN", "3", 3}};
CompilerMacros compilerMacros2{{"BA"}, {"ER", "2", 2}, {"YI", "1", 1}, {"SAN", "3", 3}};
auto macros = Merger::mergeMacros(compilerMacros1, compilerMacros2);
ASSERT_THAT(macros,
ElementsAre(CompilerMacro{"BA"},
CompilerMacro{"ER", "2", 2},
CompilerMacro{"SE", "4", 1},
CompilerMacro{"YI", "1", 1},
CompilerMacro{"YI"},
CompilerMacro{"SAN", "3", 3}));
} }
TEST_F(PchTasksMerger, MacrosCanBeMerged)
{
CompilerMacros compilerMacros1{{"ER", "2", 2}, {"QI"}, {"SE", "4", 1}, {"SAN", "3", 3}};
CompilerMacros compilerMacros2{{"BA"}, {"ER", "2", 2}, {"YI", "1", 1}, {"SAN", "3", 3}};
auto canBeMerged = Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2));
ASSERT_TRUE(canBeMerged);
}
TEST_F(PchTasksMerger, MacrosCannotBeMergedBecauseDifferentValue)
{
CompilerMacros compilerMacros1{{"ER", "2", 2}, {"SE", "4", 1}, {"SAN", "3", 3}};
CompilerMacros compilerMacros2{{"ER", "1", 2}, {"YI", "1", 1}, {"SAN", "3", 3}};
auto canBeMerged = Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2));
ASSERT_FALSE(canBeMerged);
}
TEST_F(PchTasksMerger, MacrosCannotBeMergedBecauseUndefinedMacro)
{
CompilerMacros compilerMacros1{{"ER", "2", 2}, {"SE", "4", 1}, {"YI"}, {"SAN", "3", 3}};
CompilerMacros compilerMacros2{{"ER", "2", 2}, {"YI", "1", 1}, {"SAN", "3", 3}};
auto canBeMerged = Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2));
ASSERT_FALSE(canBeMerged);
}
TEST_F(PchTasksMerger, CanMergePchTasks)
{
auto canBeMerged = Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_TRUE(canBeMerged);
}
TEST_F(PchTasksMerger, CannotMergePchTasks)
{
auto canBeMerged = Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_FALSE(canBeMerged);
}
TEST_F(PchTasksMerger, IsMergedIsSet)
{
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_TRUE(systemTask2.isMerged);
}
TEST_F(PchTasksMerger, IsMergedIsNotSet)
{
Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_FALSE(systemTask3.isMerged);
}
TEST_F(PchTasksMerger, DontMergeLanguage)
{
systemTask2.language = Utils::Language::C;
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_FALSE(systemTask2.isMerged);
}
TEST_F(PchTasksMerger, MergeCompilerMacros)
{
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.compilerMacros,
ElementsAre(CompilerMacro{"SE", "4", 4},
CompilerMacro{"WU", "5", 5},
CompilerMacro{"YI", "1", 1},
CompilerMacro{"SAN", "3", 3}));
}
TEST_F(PchTasksMerger, DontMergeCompilerMacros)
{
Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_THAT(systemTask1.compilerMacros,
ElementsAre(CompilerMacro{"YI", "1", 1}, CompilerMacro{"SAN", "3", 3}));
}
TEST_F(PchTasksMerger, MergeIncludes)
{
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.includes, ElementsAre(1, 2, 11, 12));
}
TEST_F(PchTasksMerger, DontMergeIncludes)
{
Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_THAT(systemTask1.includes, ElementsAre(1, 2));
}
TEST_F(PchTasksMerger, MergeAllIncludes)
{
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.allIncludes, ElementsAre(1, 2, 3, 11, 12, 13));
}
TEST_F(PchTasksMerger, DontAllMergeIncludes)
{
Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_THAT(systemTask1.allIncludes, ElementsAre(1, 2, 3));
}
TEST_F(PchTasksMerger, MergeProjectIds)
{
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.projectPartIds, ElementsAre("ProjectPart1", "ProjectPart2"));
}
TEST_F(PchTasksMerger, DontMergeProjectIds)
{
Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_THAT(systemTask1.projectPartIds, ElementsAre("ProjectPart1"));
}
TEST_F(PchTasksMerger, MergeIncludeSearchPaths)
{
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.systemIncludeSearchPaths,
ElementsAre(IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System},
IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn},
IncludeSearchPath{"/builtin/path2", 3, IncludeSearchPathType::BuiltIn},
IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}));
}
TEST_F(PchTasksMerger, DontMergeIncludeSearchPaths)
{
Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_THAT(systemTask1.systemIncludeSearchPaths,
ElementsAre(IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System},
IncludeSearchPath{"/builtin/path2", 3, IncludeSearchPathType::BuiltIn},
IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}));
}
TEST_F(PchTasksMerger, ChooseLanguageVersionFromFirstTask)
{
systemTask2.languageVersion = Utils::LanguageVersion::CXX17;
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.languageVersion, Utils::LanguageVersion::CXX17);
}
TEST_F(PchTasksMerger, ChooseLanguageVersionFromSecondTask)
{
systemTask1.languageVersion = Utils::LanguageVersion::CXX17;
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.languageVersion, Utils::LanguageVersion::CXX17);
}
TEST_F(PchTasksMerger, DontChooseLanguageVersion)
{
systemTask3.languageVersion = Utils::LanguageVersion::CXX17;
Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_THAT(systemTask1.languageVersion, Utils::LanguageVersion::CXX98);
}
TEST_F(PchTasksMerger, FirstTaskIsNotMergedAgain)
{
systemTask1.isMerged = true;
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_FALSE(systemTask2.isMerged);
}
TEST_F(PchTasksMerger, DontMergeAlreadyMergedFirstTask)
{
systemTask1.isMerged = true;
bool isMerged = Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_FALSE(isMerged);
}
TEST_F(PchTasksMerger, SecondTaskIsNotMergedAgain)
{
systemTask2.isMerged = true;
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.includes, ElementsAre(1, 2));
}
TEST_F(PchTasksMerger, DontMergeAlreadyMergedSecondTask)
{
systemTask2.isMerged = true;
bool isMerged = Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_FALSE(isMerged);
}
} // namespace

View File

@@ -241,12 +241,6 @@ protected:
Manager collectorManger{generatedFiles}; Manager collectorManger{generatedFiles};
NiceMock<MockFunction<void(int, int)>> mockSetProgressCallback; NiceMock<MockFunction<void(int, int)>> mockSetProgressCallback;
ClangBackEnd::ProgressCounter progressCounter{mockSetProgressCallback.AsStdFunction()}; ClangBackEnd::ProgressCounter progressCounter{mockSetProgressCallback.AsStdFunction()};
Scheduler indexerScheduler{collectorManger,
indexerQueue,
progressCounter,
1,
ClangBackEnd::CallDoInMainThreadAfterFinished::Yes};
SymbolIndexerTaskQueue indexerQueue{indexerScheduler, progressCounter};
ClangBackEnd::SymbolIndexer indexer{indexerQueue, ClangBackEnd::SymbolIndexer indexer{indexerQueue,
mockSymbolStorage, mockSymbolStorage,
mockBuildDependenciesStorage, mockBuildDependenciesStorage,
@@ -254,6 +248,12 @@ protected:
filePathCache, filePathCache,
fileStatusCache, fileStatusCache,
mockSqliteTransactionBackend}; mockSqliteTransactionBackend};
SymbolIndexerTaskQueue indexerQueue{indexerScheduler, progressCounter};
Scheduler indexerScheduler{collectorManger,
indexerQueue,
progressCounter,
1,
ClangBackEnd::CallDoInMainThreadAfterFinished::Yes};
MockSymbolsCollector &mockCollector{static_cast<MockSymbolsCollector&>(collectorManger.unusedProcessor())}; MockSymbolsCollector &mockCollector{static_cast<MockSymbolsCollector&>(collectorManger.unusedProcessor())};
}; };
@@ -269,7 +269,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesInCollector)
"c++-header", "c++-header",
"-std=c++14", "-std=c++14",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"-DBAR=1", "-DBAR=1",
"-DFOO=1", "-DFOO=1",
"-I", "-I",
@@ -299,7 +299,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithPrecompiledHeaderInColl
"c++-header", "c++-header",
"-std=c++14", "-std=c++14",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"-DBAR=1", "-DBAR=1",
"-DFOO=1", "-DFOO=1",
"-I", "-I",
@@ -332,7 +332,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithoutPrecompiledHeaderInC
"c++-header", "c++-header",
"-std=c++14", "-std=c++14",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"-DBAR=1", "-DBAR=1",
"-DFOO=1", "-DFOO=1",
"-I", "-I",
@@ -512,7 +512,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithoutProjectPartArtifact)
"c++-header", "c++-header",
"-std=c++14", "-std=c++14",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"-DBAR=1", "-DBAR=1",
"-DFOO=1", "-DFOO=1",
"-I", "-I",
@@ -564,7 +564,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithProjectPartArtifact)
"c++-header", "c++-header",
"-std=c++14", "-std=c++14",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"-DBAR=1", "-DBAR=1",
"-DFOO=1", "-DFOO=1",
"-I", "-I",
@@ -620,7 +620,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrder)
"c++-header", "c++-header",
"-std=c++14", "-std=c++14",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"-DBAR=1", "-DBAR=1",
"-DFOO=1", "-DFOO=1",
"-I", "-I",
@@ -682,7 +682,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathIsUsingPrecompiledHeader)
"c++-header", "c++-header",
"-std=c++14", "-std=c++14",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"-DBAR=1", "-DBAR=1",
"-DFOO=1", "-DFOO=1",
"-I", "-I",
@@ -717,7 +717,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathIsNotUsingPrecompiledHeaderIfItNotExists)
"c++-header", "c++-header",
"-std=c++14", "-std=c++14",
"-nostdinc", "-nostdinc",
"-nostdlibinc", "-nostdinc++",
"-DBAR=1", "-DBAR=1",
"-DFOO=1", "-DFOO=1",
"-I", "-I",

View File

@@ -46,7 +46,7 @@ protected:
{3, SourceType::ProjectInclude, 0}, {3, SourceType::ProjectInclude, 0},
{4, SourceType::TopSystemInclude, 0}, {4, SourceType::TopSystemInclude, 0},
{5, SourceType::TopProjectInclude, 0}}; {5, SourceType::TopProjectInclude, 0}};
UsedMacros usedMacros{{"YI", 1}, {"ER", 2}, {"SAN", 3}, {"SE", 4}, {"WU", 5}}; UsedMacros usedMacros{{"YI", 1}, {"ER", 2}, {"LIU", 2}, {"QI", 3}, {"SAN", 3}, {"SE", 4}, {"WU", 5}};
CompilerMacros compileMacros{{"YI", "1", 1}, CompilerMacros compileMacros{{"YI", "1", 1},
{"ER", "2", 2}, {"ER", "2", 2},
{"SAN", "3", 3}, {"SAN", "3", 3},
@@ -57,36 +57,35 @@ protected:
TEST_F(UsedMacroFilter, SystemIncludes) TEST_F(UsedMacroFilter, SystemIncludes)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.systemIncludes, ElementsAre(FilePathId{2}, FilePathId{4})); ASSERT_THAT(filter.systemIncludes, ElementsAre(FilePathId{2}, FilePathId{4}));
} }
TEST_F(UsedMacroFilter, ProjectIncludes) TEST_F(UsedMacroFilter, ProjectIncludes)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.projectIncludes, ElementsAre(FilePathId{3}, FilePathId{5})); ASSERT_THAT(filter.projectIncludes, ElementsAre(FilePathId{3}, FilePathId{5}));
} }
TEST_F(UsedMacroFilter, TopSystemIncludes) TEST_F(UsedMacroFilter, TopSystemIncludes)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.topSystemIncludes, ElementsAre(FilePathId{4})); ASSERT_THAT(filter.topSystemIncludes, ElementsAre(FilePathId{4}));
} }
TEST_F(UsedMacroFilter, TopProjectIncludes) TEST_F(UsedMacroFilter, TopProjectIncludes)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.topProjectIncludes, ElementsAre(FilePathId{5})); ASSERT_THAT(filter.topProjectIncludes, ElementsAre(FilePathId{5}));
} }
TEST_F(UsedMacroFilter, AllIncludes) TEST_F(UsedMacroFilter, AllIncludes)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.allIncludes, ASSERT_THAT(filter.allIncludes,
ElementsAre(FilePathId{1}, FilePathId{2}, FilePathId{3}, FilePathId{4}, FilePathId{5})); ElementsAre(FilePathId{1}, FilePathId{2}, FilePathId{3}, FilePathId{4}, FilePathId{5}));
@@ -94,36 +93,36 @@ TEST_F(UsedMacroFilter, AllIncludes)
TEST_F(UsedMacroFilter, SystemUsedMacros) TEST_F(UsedMacroFilter, SystemUsedMacros)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.systemUsedMacros, ElementsAre(UsedMacro{"ER", 2}, UsedMacro{"SE", 4})); ASSERT_THAT(filter.systemUsedMacros, ElementsAre("ER", "SE", "LIU"));
} }
TEST_F(UsedMacroFilter, ProjectUsedMacros) TEST_F(UsedMacroFilter, ProjectUsedMacros)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.projectUsedMacros, ElementsAre(UsedMacro{"WU", 5}, UsedMacro{"SAN", 3})); ASSERT_THAT(filter.projectUsedMacros, ElementsAre("QI", "WU", "SAN"));
} }
TEST_F(UsedMacroFilter, SystemCompileMacros) TEST_F(UsedMacroFilter, SystemCompileMacros)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
filter.filter(compileMacros);
ASSERT_THAT(filter.systemCompilerMacros, ASSERT_THAT(filter.systemCompilerMacros,
ElementsAre(CompilerMacro{"ER", "2", 2}, CompilerMacro{"SE", "4", 4})); ElementsAre(CompilerMacro{"ER", "2", 2},
CompilerMacro{"SE", "4", 4},
CompilerMacro{"LIU"}));
} }
TEST_F(UsedMacroFilter, ProjectCompileMacros) TEST_F(UsedMacroFilter, ProjectCompileMacros)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
filter.filter(compileMacros);
ASSERT_THAT(filter.projectCompilerMacros, ASSERT_THAT(filter.projectCompilerMacros,
ElementsAre(CompilerMacro{"WU", "5", 5}, CompilerMacro{"SAN", "3", 3})); ElementsAre(CompilerMacro{"QI"},
CompilerMacro{"WU", "5", 5},
CompilerMacro{"SAN", "3", 3}));
} }
} // namespace } // namespace