diff --git a/src/app/app-Info.plist b/src/app/app-Info.plist
index 3d5a8be7a59..5d7142a863b 100644
--- a/src/app/app-Info.plist
+++ b/src/app/app-Info.plist
@@ -254,5 +254,23 @@
@SHORT_VERSION@
LSMinimumSystemVersion
@MACOSX_DEPLOYMENT_TARGET@
-
-
+ NSAppleEventsUsageDescription
+ This application wants to run AppleScript.
+ NSBluetoothPeripheralUsageDescription
+ A user application wants to access bluetooth.
+ NSCalendarsUsageDescription
+ A user application wants to access calendars.
+ NSCameraUsageDescription
+ A user application wants to access the camera.
+ NSContactsUsageDescription
+ A user application wants to access contacts.
+ NSLocationWhenInUseUsageDescription
+ A user application wants to access location information.
+ NSMicrophoneUsageDescription
+ A user application wants to access the microphone.
+ NSPhotoLibraryAddUsageDescription
+ A user application wants write access to the photo library.
+ NSPhotoLibraryUsageDescription
+ A user application wants to access the photo library.
+ NSRemindersUsageDescription
+ A user application wants to access the reminders.
diff --git a/src/libs/clangsupport/commandlinebuilder.h b/src/libs/clangsupport/commandlinebuilder.h
index 6a9975a3ac9..9b5bced9328 100644
--- a/src/libs/clangsupport/commandlinebuilder.h
+++ b/src/libs/clangsupport/commandlinebuilder.h
@@ -182,6 +182,13 @@ public:
{
CompilerMacros macros = compilerMacros;
+ macros.erase(std::remove_if(macros.begin(),
+ macros.end(),
+ [](const auto ¯o) {
+ return macro.type == CompilerMacroType::NotDefined;
+ }),
+ macros.end());
+
std::sort(macros.begin(),
macros.end(),
[](const CompilerMacro &first, const CompilerMacro &second) {
@@ -263,7 +270,7 @@ public:
void addNoStdIncAndNoStdLibInc()
{
commandLine.emplace_back("-nostdinc");
- commandLine.emplace_back("-nostdlibinc");
+ commandLine.emplace_back("-nostdinc++");
}
public:
diff --git a/src/libs/clangsupport/compilermacro.h b/src/libs/clangsupport/compilermacro.h
index ddba1a40762..798bab2ebd7 100644
--- a/src/libs/clangsupport/compilermacro.h
+++ b/src/libs/clangsupport/compilermacro.h
@@ -31,6 +31,8 @@
namespace ClangBackEnd {
+enum class CompilerMacroType : unsigned char { Define, NotDefined };
+
class CompilerMacro
{
public:
@@ -40,39 +42,57 @@ public:
: key(std::move(key))
, value(std::move(value))
, 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)
{
out << compilerMacro.key;
out << compilerMacro.value;
+ out << compilerMacro.index;
+ out << static_cast(compilerMacro.type);
return out;
}
friend QDataStream &operator>>(QDataStream &in, CompilerMacro &compilerMacro)
{
+ unsigned char type;
+
in >> compilerMacro.key;
in >> compilerMacro.value;
+ in >> compilerMacro.index;
+ in >> type;
+
+ compilerMacro.type = static_cast(type);
return in;
}
friend bool operator==(const CompilerMacro &first, const CompilerMacro &second)
{
- return first.key == second.key
- && first.value == second.value;
+ return first.key == second.key && first.value == second.value && first.type == second.type;
}
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:
Utils::SmallString key;
Utils::SmallString value;
- int index = 0;
+ int index = -1;
+ CompilerMacroType type = CompilerMacroType::NotDefined;
};
using CompilerMacros = std::vector;
diff --git a/src/libs/clangsupport/projectpartcontainer.h b/src/libs/clangsupport/projectpartcontainer.h
index 41ae071961d..06065911372 100644
--- a/src/libs/clangsupport/projectpartcontainer.h
+++ b/src/libs/clangsupport/projectpartcontainer.h
@@ -161,5 +161,6 @@ public:
using ProjectPartContainers = std::vector;
-QDebug operator<<(QDebug debug, const ProjectPartContainer &container);
+CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const ProjectPartContainer &container);
+
} // namespace ClangBackEnd
diff --git a/src/plugins/autotest/testresultspane.cpp b/src/plugins/autotest/testresultspane.cpp
index 0c4b9eac652..c036ad431a3 100644
--- a/src/plugins/autotest/testresultspane.cpp
+++ b/src/plugins/autotest/testresultspane.cpp
@@ -471,7 +471,9 @@ void TestResultsPane::updateSummaryLabel()
if (count)
labelText += ", " + QString::number(count) + ' ' + tr("fatals");
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)
labelText += ", " + QString::number(count) + ' ' + tr("blacklisted");
count = m_model->resultTypeCount(Result::Skip);
diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp
index d69498d0473..f5bc876020a 100644
--- a/src/plugins/clangformat/clangformatbaseindenter.cpp
+++ b/src/plugins/clangformat/clangformatbaseindenter.cpp
@@ -27,6 +27,7 @@
#include
+#include
#include
#include
#include
@@ -57,20 +58,29 @@ static llvm::StringRef clearExtraNewline(llvm::StringRef text)
static clang::tooling::Replacements filteredReplacements(
const clang::tooling::Replacements &replacements,
int offset,
- int extraOffsetToAdd,
- bool onlyIndention)
+ int utf8LineLengthBeforeCursor,
+ int extraOffsetFromStartOfFile,
+ int extraEmptySpaceOffset,
+ ReplacementsToKeep replacementsToKeep)
{
clang::tooling::Replacements filtered;
for (const clang::tooling::Replacement &replacement : replacements) {
int replacementOffset = static_cast(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;
- if (replacementOffset + 1 >= offset)
- replacementOffset += extraOffsetToAdd;
+ if (replacementOffset >= offset - 1)
+ replacementOffset += extraEmptySpaceOffset;
+ replacementOffset += extraOffsetFromStartOfFile;
- llvm::StringRef text = onlyIndention ? clearExtraNewline(replacement.getReplacementText())
- : replacement.getReplacementText();
+ llvm::StringRef text = replacementsToKeep == ReplacementsToKeep::OnlyIndent
+ ? clearExtraNewline(replacement.getReplacementText())
+ : replacement.getReplacementText();
llvm::Error error = filtered.add(
clang::tooling::Replacement(replacement.getFilePath(),
@@ -78,8 +88,14 @@ static clang::tooling::Replacements filteredReplacements(
replacement.getLength(),
text));
// 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;
+ }
}
return filtered;
}
@@ -140,9 +156,16 @@ static int previousEmptyLinesLength(const QTextBlock ¤tBlock)
static void modifyToIndentEmptyLines(
QByteArray &buffer, int offset, int &length, const QTextBlock &block, bool secondTry)
{
- const QString blockText = block.text().trimmed();
- const bool closingParenBlock = blockText.startsWith(')');
- if (blockText.isEmpty() || closingParenBlock) {
+ const QString blockText = block.text();
+ int firstNonWhitespace = Utils::indexOf(blockText,
+ [](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.
QByteArray dummyText("a;");
@@ -153,15 +176,8 @@ static void modifyToIndentEmptyLines(
prevBlock = prevBlock.previous();
prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty();
}
- if (prevBlock.text().endsWith(','))
- dummyText = "int a";
-
- if (closingParenBlock) {
- if (prevBlock.text().endsWith(','))
- dummyText = "int a";
- else
- dummyText = "&& a";
- }
+ if (closingParenBlock || prevBlock.text().endsWith(','))
+ dummyText = "&& a";
length += dummyText.length();
buffer.insert(offset, dummyText);
@@ -169,6 +185,9 @@ static void modifyToIndentEmptyLines(
if (secondTry) {
int nextLinePos = buffer.indexOf('\n', offset);
+ if (nextLinePos < 0)
+ nextLinePos = buffer.size() - 1;
+
if (nextLinePos > 0) {
// If first try was not successful try to put ')' in the end of the line to close possibly
// unclosed parentheses.
@@ -187,7 +206,9 @@ static Utils::LineColumn utf16LineColumn(const QTextBlock &block,
int utf8Offset)
{
// 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.
if (utf8Offset < blockOffsetUtf8) {
@@ -299,8 +320,10 @@ void ClangFormatBaseIndenter::indent(const QTextCursor &cursor,
if (currentBlock.isValid()) {
const int blocksAmount = m_doc->blockCount();
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 {
@@ -328,24 +351,30 @@ TextEditor::Replacements ClangFormatBaseIndenter::format(const QTextCursor &curs
{
int utf8Offset;
int utf8Length;
+ QTextBlock block;
+
const QByteArray buffer = m_doc->toPlainText().toUtf8();
- QTextBlock block = cursor.block();
if (cursor.hasSelection()) {
block = m_doc->findBlock(cursor.selectionStart());
const QTextBlock end = m_doc->findBlock(cursor.selectionEnd());
utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return TextEditor::Replacements(););
utf8Length = selectedLines(m_doc, block, end).toUtf8().size();
-
} else {
- const QTextBlock block = cursor.block();
+ block = cursor.block();
utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return TextEditor::Replacements(););
+
utf8Length = block.text().toUtf8().size();
}
- const TextEditor::Replacements toReplace
- = replacements(buffer, utf8Offset, utf8Length, block, QChar::Null, false);
+ const TextEditor::Replacements toReplace = replacements(buffer,
+ utf8Offset,
+ utf8Length,
+ block,
+ cursorPositionInEditor,
+ ReplacementsToKeep::All,
+ QChar::Null);
applyReplacements(block, toReplace);
return toReplace;
@@ -359,17 +388,62 @@ TextEditor::Replacements ClangFormatBaseIndenter::format(
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,
const QChar &typedChar,
- int /*cursorPositionInEditor*/)
+ int cursorPositionInEditor)
{
- trimFirstNonEmptyBlock(block);
- trimCurrentBlock(block);
+ QTextBlock currentBlock = 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 int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
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,
@@ -380,7 +454,7 @@ void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
indentBlock(block, typedChar, cursorPositionInEditor);
}
-int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, int /*cursorPositionInEditor*/)
+int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, int cursorPositionInEditor)
{
trimFirstNonEmptyBlock(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);
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())
return -1;
@@ -447,12 +526,30 @@ clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const
return clang::format::getLLVMStyle();
}
+static int formattingRangeStart(const QTextBlock ¤tBlock,
+ 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,
int utf8Offset,
int utf8Length,
const QTextBlock &block,
+ int cursorPositionInEditor,
+ ReplacementsToKeep replacementsToKeep,
const QChar &typedChar,
- bool onlyIndention,
bool secondTry) const
{
clang::format::FormatStyle style = styleForFile();
@@ -461,13 +558,22 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer
int originalLengthUtf8 = utf8Length;
QByteArray originalBuffer = buffer;
- int extraOffset = 0;
- if (onlyIndention) {
+ int utf8LineLengthBeforeCursor = 0;
+ 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) {
- extraOffset = Utils::Text::utf8NthLineOffset(block.document(),
- buffer,
- block.blockNumber()
- - kMaxLinesFromCurrentBlock);
+ extraOffsetFromStartOfFile
+ = Utils::Text::utf8NthLineOffset(block.document(),
+ buffer,
+ block.blockNumber() - kMaxLinesFromCurrentBlock);
}
int endOffset = Utils::Text::utf8NthLineOffset(block.document(),
buffer,
@@ -476,22 +582,30 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer
if (endOffset == -1)
endOffset = buffer.size();
- buffer = buffer.mid(extraOffset, endOffset - extraOffset);
- utf8Offset -= extraOffset;
- const int emptySpaceLength = previousEmptyLinesLength(block);
- utf8Offset -= emptySpaceLength;
- buffer.remove(utf8Offset, emptySpaceLength);
+ if (replacementsToKeep == ReplacementsToKeep::OnlyBeforeIndent)
+ rangeStart = formattingRangeStart(block, buffer, lastSaveRevision());
- extraOffset += emptySpaceLength;
+ buffer = buffer.mid(extraOffsetFromStartOfFile, endOffset - extraOffsetFromStartOfFile);
+ utf8Offset -= extraOffsetFromStartOfFile;
+ rangeStart -= extraOffsetFromStartOfFile;
- adjustFormatStyleForLineBreak(style);
- if (typedChar == QChar::Null)
- modifyToIndentEmptyLines(buffer, utf8Offset, utf8Length, block, secondTry);
+ extraEmptySpaceOffset = previousEmptyLinesLength(block);
+ utf8Offset -= extraEmptySpaceOffset;
+ buffer.remove(utf8Offset, extraEmptySpaceOffset);
+
+ if (replacementsToKeep == ReplacementsToKeep::OnlyIndent)
+ adjustFormatStyleForLineBreak(style);
+ modifyToIndentEmptyLines(buffer, utf8Offset, utf8Length, block, secondTry);
}
- std::vector ranges{
- {static_cast(utf8Offset), static_cast(utf8Length)}};
+ if (replacementsToKeep != ReplacementsToKeep::OnlyBeforeIndent || utf8Offset < rangeStart)
+ rangeStart = utf8Offset;
+
+ unsigned int rangeLength = static_cast(utf8Offset + utf8Length - rangeStart);
+
+ std::vector ranges{{static_cast(rangeStart), rangeLength}};
+
clang::format::FormattingAttemptStatus status;
clang::tooling::Replacements clangReplacements = reformat(style,
@@ -500,21 +614,25 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer
m_fileName.toString().toStdString(),
&status);
- if (!status.FormatComplete)
- return TextEditor::Replacements();
-
- const clang::tooling::Replacements filtered = filteredReplacements(clangReplacements,
- utf8Offset,
- extraOffset,
- onlyIndention);
- const bool canTryAgain = onlyIndention && typedChar == QChar::Null && !secondTry;
+ clang::tooling::Replacements filtered;
+ if (status.FormatComplete) {
+ filtered = filteredReplacements(clangReplacements,
+ utf8Offset,
+ utf8LineLengthBeforeCursor,
+ extraOffsetFromStartOfFile,
+ extraEmptySpaceOffset,
+ replacementsToKeep);
+ }
+ const bool canTryAgain = replacementsToKeep == ReplacementsToKeep::OnlyIndent
+ && typedChar == QChar::Null && !secondTry;
if (canTryAgain && filtered.empty()) {
return replacements(originalBuffer,
originalOffsetUtf8,
originalLengthUtf8,
block,
+ cursorPositionInEditor,
+ replacementsToKeep,
typedChar,
- onlyIndention,
true);
}
diff --git a/src/plugins/clangformat/clangformatbaseindenter.h b/src/plugins/clangformat/clangformatbaseindenter.h
index 4071422cfde..1a73d9bfbcf 100644
--- a/src/plugins/clangformat/clangformatbaseindenter.h
+++ b/src/plugins/clangformat/clangformatbaseindenter.h
@@ -31,6 +31,8 @@
namespace ClangFormat {
+enum class ReplacementsToKeep { OnlyIndent, OnlyBeforeIndent, All };
+
class ClangFormatBaseIndenter : public TextEditor::Indenter
{
public:
@@ -69,18 +71,24 @@ public:
protected:
virtual clang::format::FormatStyle styleForFile() const;
virtual bool formatCodeInsteadOfIndent() const { return false; }
+ virtual bool formatWhileTyping() const { return false; }
+ virtual int lastSaveRevision() const { return 0; }
private:
TextEditor::Replacements format(const QTextCursor &cursor, int cursorPositionInEditor);
void indent(const QTextCursor &cursor, const QChar &typedChar, int cursorPositionInEditor);
void indentBlock(const QTextBlock &block, const QChar &typedChar, int cursorPositionInEditor);
int indentFor(const QTextBlock &block, int cursorPositionInEditor);
+ int indentBeforeCursor(const QTextBlock &block,
+ const QChar &typedChar,
+ int cursorPositionInEditor);
TextEditor::Replacements replacements(QByteArray buffer,
int utf8Offset,
int utf8Length,
const QTextBlock &block,
+ int cursorPositionInEditor,
+ ReplacementsToKeep replacementsToKeep,
const QChar &typedChar = QChar::Null,
- bool onlyIndention = true,
bool secondTry = false) const;
};
diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp
index 3d105f55801..f0d4808cf5c 100644
--- a/src/plugins/clangformat/clangformatconfigwidget.cpp
+++ b/src/plugins/clangformat/clangformatconfigwidget.cpp
@@ -127,12 +127,31 @@ ClangFormatConfigWidget::ClangFormatConfigWidget(ProjectExplorer::Project *proje
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()
{
m_ui->projectHasClangFormat->show();
m_ui->clangFormatOptionsTable->show();
m_ui->applyButton->show();
- m_ui->formatAlways->hide();
+ hideGlobalCheckboxes();
QLayoutItem *lastItem = m_ui->verticalLayout->itemAt(m_ui->verticalLayout->count() - 1);
if (lastItem->spacerItem())
@@ -171,8 +190,7 @@ void ClangFormatConfigWidget::initialize()
"and can be configured in Projects > Code Style > C++."));
}
createStyleFileIfNeeded(true);
- m_ui->formatAlways->setChecked(ClangFormatSettings::instance().formatCodeInsteadOfIndent());
- m_ui->formatAlways->show();
+ showGlobalCheckboxes();
m_ui->applyButton->hide();
}
@@ -186,7 +204,6 @@ void ClangFormatConfigWidget::fillTable()
std::string configText = clang::format::configurationAsText(style);
std::istringstream stream(configText);
readTable(m_ui->clangFormatOptionsTable, stream);
-
}
ClangFormatConfigWidget::~ClangFormatConfigWidget() = default;
@@ -196,6 +213,8 @@ void ClangFormatConfigWidget::apply()
if (!m_project) {
ClangFormatSettings &settings = ClangFormatSettings::instance();
settings.setFormatCodeInsteadOfIndent(m_ui->formatAlways->isChecked());
+ settings.setFormatWhileTyping(m_ui->formatWhileTyping->isChecked());
+ settings.setFormatOnSave(m_ui->formatOnSave->isChecked());
settings.write();
}
diff --git a/src/plugins/clangformat/clangformatconfigwidget.h b/src/plugins/clangformat/clangformatconfigwidget.h
index 5db16e3c967..7d3818b7a52 100644
--- a/src/plugins/clangformat/clangformatconfigwidget.h
+++ b/src/plugins/clangformat/clangformatconfigwidget.h
@@ -51,6 +51,9 @@ private:
void initialize();
void fillTable();
+ void hideGlobalCheckboxes();
+ void showGlobalCheckboxes();
+
ProjectExplorer::Project *m_project;
std::unique_ptr m_ui;
};
diff --git a/src/plugins/clangformat/clangformatconfigwidget.ui b/src/plugins/clangformat/clangformatconfigwidget.ui
index 8fcc87235d8..2094bca1090 100644
--- a/src/plugins/clangformat/clangformatconfigwidget.ui
+++ b/src/plugins/clangformat/clangformatconfigwidget.ui
@@ -33,6 +33,20 @@
+ -
+
+
+ Format while typing
+
+
+
+ -
+
+
+ Format edited code on file save
+
+
+
-
diff --git a/src/plugins/clangformat/clangformatconstants.h b/src/plugins/clangformat/clangformatconstants.h
index aa2389bbfeb..8b7cbcf9bd2 100644
--- a/src/plugins/clangformat/clangformatconstants.h
+++ b/src/plugins/clangformat/clangformatconstants.h
@@ -32,5 +32,7 @@ static const char SETTINGS_FILE_ALT_NAME[] = "_clang-format";
static const char SAMPLE_FILE_NAME[] = "test.cpp";
static const char SETTINGS_ID[] = "ClangFormat";
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 ClangFormat
diff --git a/src/plugins/clangformat/clangformatindenter.cpp b/src/plugins/clangformat/clangformatindenter.cpp
index 1d0400d323f..ef9dbf5d1ca 100644
--- a/src/plugins/clangformat/clangformatindenter.cpp
+++ b/src/plugins/clangformat/clangformatindenter.cpp
@@ -28,6 +28,7 @@
#include "clangformatutils.h"
#include
+#include
using namespace clang;
using namespace format;
@@ -49,6 +50,11 @@ bool ClangFormatIndenter::formatCodeInsteadOfIndent() const
return ClangFormatSettings::instance().formatCodeInsteadOfIndent();
}
+bool ClangFormatIndenter::formatWhileTyping() const
+{
+ return ClangFormatSettings::instance().formatWhileTyping();
+}
+
Utils::optional ClangFormatIndenter::tabSettings() const
{
FormatStyle style = currentProjectStyle();
@@ -76,4 +82,14 @@ Utils::optional ClangFormatIndenter::tabSettings() const
return tabSettings;
}
+int ClangFormatIndenter::lastSaveRevision() const
+{
+ return qobject_cast(m_doc->documentLayout())->lastSaveRevision;
+}
+
+bool ClangFormatIndenter::formatOnSave() const
+{
+ return ClangFormatSettings::instance().formatOnSave();
+}
+
} // namespace ClangFormat
diff --git a/src/plugins/clangformat/clangformatindenter.h b/src/plugins/clangformat/clangformatindenter.h
index 507ea68f415..6d605eb5c91 100644
--- a/src/plugins/clangformat/clangformatindenter.h
+++ b/src/plugins/clangformat/clangformatindenter.h
@@ -36,10 +36,13 @@ class ClangFormatIndenter final : public ClangFormatBaseIndenter
public:
ClangFormatIndenter(QTextDocument *doc);
Utils::optional tabSettings() const override;
+ bool formatOnSave() const override;
private:
bool formatCodeInsteadOfIndent() const override;
+ bool formatWhileTyping() const override;
clang::format::FormatStyle styleForFile() const override;
+ int lastSaveRevision() const override;
};
} // namespace ClangFormat
diff --git a/src/plugins/clangformat/clangformatsettings.cpp b/src/plugins/clangformat/clangformatsettings.cpp
index 0547bde9604..8be2b3cefee 100644
--- a/src/plugins/clangformat/clangformatsettings.cpp
+++ b/src/plugins/clangformat/clangformatsettings.cpp
@@ -42,6 +42,10 @@ ClangFormatSettings::ClangFormatSettings()
settings->beginGroup(QLatin1String(Constants::SETTINGS_ID));
m_formatCodeInsteadOfIndent
= 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();
}
@@ -51,6 +55,8 @@ void ClangFormatSettings::write() const
settings->beginGroup(QLatin1String(Constants::SETTINGS_ID));
settings->setValue(QLatin1String(Constants::FORMAT_CODE_INSTEAD_OF_INDENT_ID),
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();
}
@@ -64,4 +70,24 @@ bool ClangFormatSettings::formatCodeInsteadOfIndent() const
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
diff --git a/src/plugins/clangformat/clangformatsettings.h b/src/plugins/clangformat/clangformatsettings.h
index 06205932286..0ea9ed9747e 100644
--- a/src/plugins/clangformat/clangformatsettings.h
+++ b/src/plugins/clangformat/clangformatsettings.h
@@ -37,8 +37,16 @@ public:
void setFormatCodeInsteadOfIndent(bool enable);
bool formatCodeInsteadOfIndent() const;
+
+ void setFormatWhileTyping(bool enable);
+ bool formatWhileTyping() const;
+
+ void setFormatOnSave(bool enable);
+ bool formatOnSave() const;
private:
bool m_formatCodeInsteadOfIndent = false;
+ bool m_formatWhileTyping = false;
+ bool m_formatOnSave = false;
};
} // namespace ClangFormat
diff --git a/src/plugins/clangtools/clangtoolsdiagnosticview.cpp b/src/plugins/clangtools/clangtoolsdiagnosticview.cpp
index b10d26dd328..07bc7f397f4 100644
--- a/src/plugins/clangtools/clangtoolsdiagnosticview.cpp
+++ b/src/plugins/clangtools/clangtoolsdiagnosticview.cpp
@@ -152,35 +152,38 @@ void DiagnosticView::goBack()
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()) {
- const QModelIndex nextIndex = index.sibling(index.row() + direction, index.column());
- if (nextIndex.isValid())
- return nextIndex;
+ // Use direct sibling for level 2 and 3 items
+ const QModelIndex followingIndex = index.sibling(index.row() + direction, 0);
+ 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
- if (parentIndex.parent().isValid())
- return getIndex(parentIndex, direction);
+ // Skip top level items without children
+ while (!model()->hasChildren(followingTopIndex))
+ followingTopIndex = getTopLevelIndex(followingTopIndex, direction);
- // Find next/previous level 2 item
- QModelIndex nextTopIndex = getTopLevelIndex(parentIndex.isValid() ? parentIndex : index,
- direction);
- while (!model()->hasChildren(nextTopIndex))
- nextTopIndex = getTopLevelIndex(nextTopIndex, direction);
- return model()->index(direction == Next ? 0 : model()->rowCount(nextTopIndex) - 1,
- 0,
- nextTopIndex);
+ // Select first/last level 2 item
+ const int row = direction == Next ? 0 : model()->rowCount(followingTopIndex) - 1;
+ return model()->index(row, 0, followingTopIndex);
}
QModelIndex DiagnosticView::getTopLevelIndex(const QModelIndex &index, Direction direction) const
{
- QModelIndex below = index.sibling(index.row() + direction, 0);
- if (below.isValid())
- return below;
- return model()->index(direction == Next ? 0 : model()->rowCount(index) - 1, 0);
+ QModelIndex following = index.sibling(index.row() + direction, 0);
+ if (following.isValid())
+ return following;
+ const int row = direction == Next ? 0 : model()->rowCount() - 1;
+ return model()->index(row, 0);
}
QList DiagnosticView::customActions() const
diff --git a/src/plugins/clangtools/clangtoolslogfilereader.cpp b/src/plugins/clangtools/clangtoolslogfilereader.cpp
index d1e98fac87b..d2213d3304e 100644
--- a/src/plugins/clangtools/clangtoolslogfilereader.cpp
+++ b/src/plugins/clangtools/clangtoolslogfilereader.cpp
@@ -25,6 +25,8 @@
#include "clangtoolslogfilereader.h"
+#include
+
#include
#include
#include
@@ -147,6 +149,10 @@ static Diagnostic buildDiagnostic(const CXDiagnostic cxDiagnostic,
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) {
CXDiagnostic cxDiagnostic = clang_getDiagnosticInSet(cxChildDiagnostics, i);
Utils::ExecuteOnDestruction cleanUpDiagnostic([&]() {
@@ -156,6 +162,9 @@ static Diagnostic buildDiagnostic(const CXDiagnostic cxDiagnostic,
if (diagnosticStep.isValid())
continue;
+ if (isHeaderFile && diagnosticStep.message.contains("in file included from"))
+ continue;
+
if (isInvalidDiagnosticLocation(diagnostic, diagnosticStep, nativeFilePath))
return diagnostic;
diff --git a/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.cpp b/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.cpp
index 01db2bd56c5..d264f1324f9 100644
--- a/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.cpp
@@ -97,7 +97,7 @@ CMakeKitConfigWidget::~CMakeKitConfigWidget()
QString CMakeKitConfigWidget::displayName() const
{
- return tr("CMake Tool:");
+ return tr("CMake Tool");
}
void CMakeKitConfigWidget::makeReadOnly()
@@ -230,7 +230,7 @@ CMakeGeneratorKitConfigWidget::~CMakeGeneratorKitConfigWidget()
QString CMakeGeneratorKitConfigWidget::displayName() const
{
- return tr("CMake generator:");
+ return tr("CMake generator");
}
void CMakeGeneratorKitConfigWidget::makeReadOnly()
diff --git a/src/plugins/coreplugin/helpitem.cpp b/src/plugins/coreplugin/helpitem.cpp
index ec5ead12e07..268c00ce67b 100644
--- a/src/plugins/coreplugin/helpitem.cpp
+++ b/src/plugins/coreplugin/helpitem.cpp
@@ -173,3 +173,34 @@ const QMap &HelpItem::links() const
}
return *m_helpLinks;
}
+
+static QUrl findBestLink(const QMap &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());
+}
diff --git a/src/plugins/coreplugin/helpitem.h b/src/plugins/coreplugin/helpitem.h
index 794eaca8f31..5468659b2a4 100644
--- a/src/plugins/coreplugin/helpitem.h
+++ b/src/plugins/coreplugin/helpitem.h
@@ -78,6 +78,7 @@ public:
QString extractContent(bool extended) const;
const QMap &links() const;
+ const QUrl bestLink() const;
private:
QUrl m_helpUrl;
diff --git a/src/plugins/coreplugin/infobar.cpp b/src/plugins/coreplugin/infobar.cpp
index 53c0cc4abe5..827f1e8337a 100644
--- a/src/plugins/coreplugin/infobar.cpp
+++ b/src/plugins/coreplugin/infobar.cpp
@@ -48,15 +48,15 @@ QSettings *InfoBar::m_settings = nullptr;
Utils::Theme *InfoBar::m_theme = nullptr;
InfoBarEntry::InfoBarEntry(Id _id, const QString &_infoText, GlobalSuppressionMode _globalSuppression)
- : id(_id)
- , infoText(_infoText)
- , globalSuppression(_globalSuppression)
+ : m_id(_id)
+ , m_infoText(_infoText)
+ , m_globalSuppression(_globalSuppression)
{
}
void InfoBarEntry::setCustomButtonInfo(const QString &_buttonText, CallBack callBack)
{
- buttonText = _buttonText;
+ m_buttonText = _buttonText;
m_buttonCallBack = callBack;
}
@@ -69,14 +69,14 @@ void InfoBarEntry::setCancelButtonInfo(CallBack callBack)
void InfoBarEntry::setCancelButtonInfo(const QString &_cancelButtonText, CallBack callBack)
{
m_useCancelButton = true;
- cancelButtonText = _cancelButtonText;
+ m_cancelButtonText = _cancelButtonText;
m_cancelButtonCallBack = callBack;
}
void InfoBarEntry::removeCancelButton()
{
m_useCancelButton = false;
- cancelButtonText.clear();
+ m_cancelButtonText.clear();
m_cancelButtonCallBack = nullptr;
}
@@ -94,14 +94,14 @@ void InfoBar::addInfo(const InfoBarEntry &info)
void InfoBar::removeInfo(Id id)
{
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())
emit changed();
}
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
@@ -240,7 +240,7 @@ void InfoBarDisplay::update()
vbox->setMargin(0);
vbox->addLayout(hbox);
- QLabel *infoWidgetLabel = new QLabel(info.infoText);
+ QLabel *infoWidgetLabel = new QLabel(info.m_infoText);
infoWidgetLabel->setWordWrap(true);
hbox->addWidget(infoWidgetLabel);
@@ -270,17 +270,17 @@ void InfoBarDisplay::update()
m_isShowingDetailsWidget = false;
}
- if (!info.buttonText.isEmpty()) {
+ if (!info.m_buttonText.isEmpty()) {
auto infoWidgetButton = new QToolButton;
- infoWidgetButton->setText(info.buttonText);
+ infoWidgetButton->setText(info.m_buttonText);
connect(infoWidgetButton, &QAbstractButton::clicked, [info]() { info.m_buttonCallBack(); });
hbox->addWidget(infoWidgetButton);
}
- const Id id = info.id;
+ const Id id = info.m_id;
QToolButton *infoWidgetSuppressButton = nullptr;
- if (info.globalSuppression == InfoBarEntry::GlobalSuppressionEnabled) {
+ if (info.m_globalSuppression == InfoBarEntry::GlobalSuppressionEnabled) {
infoWidgetSuppressButton = new QToolButton;
infoWidgetSuppressButton->setText(tr("Do Not Show Again"));
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) {
infoWidgetCloseButton->setAutoRaise(true);
infoWidgetCloseButton->setIcon(Utils::Icons::CLOSE_FOREGROUND.icon());
@@ -314,7 +314,7 @@ void InfoBarDisplay::update()
if (infoWidgetCloseButton)
hbox->addWidget(infoWidgetCloseButton);
} else {
- infoWidgetCloseButton->setText(info.cancelButtonText);
+ infoWidgetCloseButton->setText(info.m_cancelButtonText);
hbox->addWidget(infoWidgetCloseButton);
if (infoWidgetSuppressButton)
hbox->addWidget(infoWidgetSuppressButton);
diff --git a/src/plugins/coreplugin/infobar.h b/src/plugins/coreplugin/infobar.h
index f3fbea6a024..ccd235cedc9 100644
--- a/src/plugins/coreplugin/infobar.h
+++ b/src/plugins/coreplugin/infobar.h
@@ -67,13 +67,13 @@ public:
void setDetailsWidgetCreator(const DetailsWidgetCreator &creator);
private:
- Id id;
- QString infoText;
- QString buttonText;
+ Id m_id;
+ QString m_infoText;
+ QString m_buttonText;
CallBack m_buttonCallBack;
- QString cancelButtonText;
+ QString m_cancelButtonText;
CallBack m_cancelButtonCallBack;
- GlobalSuppressionMode globalSuppression;
+ GlobalSuppressionMode m_globalSuppression;
DetailsWidgetCreator m_detailsWidgetCreator;
bool m_useCancelButton = true;
friend class InfoBar;
diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp
index c8951c12ebc..d18735c7501 100644
--- a/src/plugins/cppeditor/cppeditordocument.cpp
+++ b/src/plugins/cppeditor/cppeditordocument.cpp
@@ -44,6 +44,7 @@
#include
#include
+#include
#include
#include
@@ -447,5 +448,47 @@ TextEditor::TabSettings CppEditorDocument::tabSettings() const
return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings());
}
+static int formatRange(QTextDocument *doc,
+ TextEditor::Indenter *indenter,
+ std::pair 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(document()->documentLayout());
+ const int documentRevision = layout->lastSaveRevision;
+
+ std::pair 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 CppEditor
diff --git a/src/plugins/cppeditor/cppeditordocument.h b/src/plugins/cppeditor/cppeditordocument.h
index 44fe04becb7..26cff2043aa 100644
--- a/src/plugins/cppeditor/cppeditordocument.h
+++ b/src/plugins/cppeditor/cppeditordocument.h
@@ -69,6 +69,10 @@ public:
QFuture cursorInfo(const CppTools::CursorInfoParams ¶ms);
TextEditor::TabSettings tabSettings() const override;
+ bool save(QString *errorString,
+ const QString &fileName = QString(),
+ bool autoSave = false) override;
+
signals:
void codeWarningsUpdated(unsigned contentsRevision,
const QList selections,
diff --git a/src/plugins/debugger/debuggerkitconfigwidget.cpp b/src/plugins/debugger/debuggerkitconfigwidget.cpp
index 1486e7a08cf..d95a2861ac5 100644
--- a/src/plugins/debugger/debuggerkitconfigwidget.cpp
+++ b/src/plugins/debugger/debuggerkitconfigwidget.cpp
@@ -93,7 +93,7 @@ QString DebuggerKitConfigWidget::toolTip() const
QString DebuggerKitConfigWidget::displayName() const
{
- return tr("Debugger:");
+ return tr("Debugger");
}
void DebuggerKitConfigWidget::makeReadOnly()
diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp
index df16af3101c..ada46f3b3ec 100644
--- a/src/plugins/help/helpplugin.cpp
+++ b/src/plugins/help/helpplugin.cpp
@@ -620,30 +620,6 @@ HelpViewer *HelpPluginPrivate::viewerForContextHelp()
return viewerForHelpViewerLocation(LocalHelpManager::contextHelpOption());
}
-static QUrl findBestLink(const QMap &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()
{
// Find out what to show
@@ -660,9 +636,7 @@ void HelpPluginPrivate::requestContextHelp()
void HelpPluginPrivate::showContextHelp(const HelpItem &contextHelp)
{
- const QMap &links = contextHelp.links();
-
- const QUrl source = findBestLink(links);
+ const QUrl source = contextHelp.bestLink();
if (!source.isValid()) {
// No link found or no context object
HelpViewer *viewer = showHelpUrl(QUrl(Help::Constants::AboutBlank),
diff --git a/src/plugins/projectexplorer/kitinformationconfigwidget.cpp b/src/plugins/projectexplorer/kitinformationconfigwidget.cpp
index b1fcbcb6be4..a366d84646a 100644
--- a/src/plugins/projectexplorer/kitinformationconfigwidget.cpp
+++ b/src/plugins/projectexplorer/kitinformationconfigwidget.cpp
@@ -82,7 +82,7 @@ SysRootInformationConfigWidget::~SysRootInformationConfigWidget()
QString SysRootInformationConfigWidget::displayName() const
{
- return tr("Sysroot:");
+ return tr("Sysroot");
}
QString SysRootInformationConfigWidget::toolTip() const
@@ -177,7 +177,7 @@ ToolChainInformationConfigWidget::~ToolChainInformationConfigWidget()
QString ToolChainInformationConfigWidget::displayName() const
{
- return tr("Compiler:");
+ return tr("Compiler");
}
QString ToolChainInformationConfigWidget::toolTip() const
@@ -285,7 +285,7 @@ QWidget *DeviceTypeInformationConfigWidget::mainWidget() const
QString DeviceTypeInformationConfigWidget::displayName() const
{
- return tr("Device type:");
+ return tr("Device type");
}
QString DeviceTypeInformationConfigWidget::toolTip() const
@@ -358,7 +358,7 @@ QWidget *DeviceInformationConfigWidget::mainWidget() const
QString DeviceInformationConfigWidget::displayName() const
{
- return tr("Device:");
+ return tr("Device");
}
QString DeviceInformationConfigWidget::toolTip() const
@@ -437,7 +437,7 @@ QWidget *KitEnvironmentConfigWidget::mainWidget() const
QString KitEnvironmentConfigWidget::displayName() const
{
- return tr("Environment:");
+ return tr("Environment");
}
QString KitEnvironmentConfigWidget::toolTip() const
diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp
index c9b8391bd90..473c8455e25 100644
--- a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp
+++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp
@@ -216,7 +216,7 @@ void KitManagerConfigWidget::addConfigWidget(KitConfigWidget *widget)
QTC_ASSERT(widget, return);
QTC_ASSERT(!m_widgets.contains(widget), return);
- QString name = widget->displayName();
+ const QString name = widget->displayName() + ':';
QString toolTip = widget->toolTip();
auto action = new QAction(tr("Mark as Mutable"), nullptr);
diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp
index ad79e82975d..d90e3495244 100644
--- a/src/plugins/projectexplorer/projectmodels.cpp
+++ b/src/plugins/projectexplorer/projectmodels.cpp
@@ -398,7 +398,7 @@ bool FlatModel::trimEmptyDirectories(WrapperNode *parent)
Qt::DropActions FlatModel::supportedDragActions() const
{
- return Qt::MoveAction;
+ return Qt::CopyAction;
}
QStringList FlatModel::mimeTypes() const
diff --git a/src/plugins/qmakeprojectmanager/qmakekitconfigwidget.cpp b/src/plugins/qmakeprojectmanager/qmakekitconfigwidget.cpp
index 3cfcfaaa599..ba90baf6f16 100644
--- a/src/plugins/qmakeprojectmanager/qmakekitconfigwidget.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakekitconfigwidget.cpp
@@ -55,7 +55,7 @@ QWidget *QmakeKitConfigWidget::mainWidget() const
QString QmakeKitConfigWidget::displayName() const
{
- return tr("Qt mkspec:");
+ return tr("Qt mkspec");
}
QString QmakeKitConfigWidget::toolTip() const
diff --git a/src/plugins/qtsupport/qtkitconfigwidget.cpp b/src/plugins/qtsupport/qtkitconfigwidget.cpp
index 53c6421038c..8b32ba44ded 100644
--- a/src/plugins/qtsupport/qtkitconfigwidget.cpp
+++ b/src/plugins/qtsupport/qtkitconfigwidget.cpp
@@ -72,7 +72,7 @@ QtKitConfigWidget::~QtKitConfigWidget()
QString QtKitConfigWidget::displayName() const
{
- return tr("Qt version:");
+ return tr("Qt version");
}
QString QtKitConfigWidget::toolTip() const
diff --git a/src/plugins/texteditor/indenter.h b/src/plugins/texteditor/indenter.h
index bb23c9d7ac2..2907ea783ce 100644
--- a/src/plugins/texteditor/indenter.h
+++ b/src/plugins/texteditor/indenter.h
@@ -99,6 +99,8 @@ public:
return Replacements();
}
+ virtual bool formatOnSave() const { return false; }
+
// Expects a list of blocks in order of occurrence in the document.
virtual IndentationForBlock indentationForBlocks(const QVector &blocks,
const TabSettings &tabSettings,
diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp
index 977c224dcef..d8e994b749b 100644
--- a/src/plugins/texteditor/texteditor.cpp
+++ b/src/plugins/texteditor/texteditor.cpp
@@ -692,7 +692,8 @@ public:
QTextCursor m_pendingLinkUpdate;
QTextCursor m_lastLinkUpdate;
- QRegExp m_searchExpr;
+ QRegularExpression m_searchExpr;
+ QString m_findText;
FindFlags m_findFlags;
void highlightSearchResults(const QTextBlock &block, const PaintEventData &data) const;
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
{
- if (m_searchExpr.isEmpty())
+ if (m_searchExpr.pattern().isEmpty())
return;
int blockPosition = block.position();
@@ -3734,10 +3735,11 @@ void TextEditorWidgetPrivate::highlightSearchResults(const QTextBlock &block, co
.toTextCharFormat(C_SEARCH_RESULT).background().color().darker(120);
while (idx < text.length()) {
- idx = m_searchExpr.indexIn(text, idx + l);
- if (idx < 0)
+ const QRegularExpressionMatch match = m_searchExpr.match(text, idx + 1);
+ if (!match.hasMatch())
break;
- l = m_searchExpr.matchedLength();
+ idx = match.capturedStart();
+ l = match.capturedLength();
if (l == 0)
break;
if ((m_findFlags & FindWholeWords)
@@ -4332,7 +4334,7 @@ void TextEditorWidgetPrivate::paintSearchResultOverlay(const PaintEventData &dat
QPainter &painter) const
{
m_searchResultOverlay->clear();
- if (m_searchExpr.isEmpty())
+ if (m_searchExpr.pattern().isEmpty())
return;
const int margin = 5;
@@ -5335,7 +5337,7 @@ void TextEditorWidgetPrivate::slotUpdateRequest(const QRect &r, int dy)
m_extraArea->scroll(0, dy);
} else if (r.width() > 4) { // wider than cursor width, not just cursor blinking
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();
q->viewport()->update(r.adjusted(-m, -m, m, m));
}
@@ -6350,13 +6352,16 @@ void TextEditorWidgetPrivate::clearLink()
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;
- m_searchExpr.setPattern(txt);
- m_searchExpr.setPatternSyntax((findFlags & FindRegularExpression) ?
- QRegExp::RegExp : QRegExp::FixedString);
- m_searchExpr.setCaseSensitivity((findFlags & FindCaseSensitively) ?
- Qt::CaseSensitive : Qt::CaseInsensitive);
+ m_searchExpr.setPattern(pattern);
+ m_searchExpr.setPatternOptions(options);
+ m_findText = txt;
m_findFlags = findFlags;
m_delayedUpdateTimer.start(50);
@@ -6414,7 +6419,7 @@ void TextEditorWidgetPrivate::highlightSearchResultsInScrollBar()
m_searchWatcher = nullptr;
}
- const QString &txt = m_searchExpr.pattern();
+ const QString &txt = m_findText;
if (txt.isEmpty())
return;
@@ -8608,7 +8613,7 @@ void TextEditorLinkLabel::mouseMoveEvent(QMouseEvent *event)
data->addFile(m_link.targetFileName, m_link.targetLine, m_link.targetColumn);
auto drag = new QDrag(this);
drag->setMimeData(data);
- drag->exec(Qt::MoveAction);
+ drag->exec(Qt::CopyAction);
}
void TextEditorLinkLabel::mouseReleaseEvent(QMouseEvent *event)
diff --git a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp
index 3656ebd9dc5..c4e8e085ce2 100644
--- a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp
+++ b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp
@@ -55,6 +55,7 @@
#include
#include
#include
+#include
#include
using namespace std::chrono_literals;
@@ -183,16 +184,6 @@ struct Data // because we have a cycle dependency
PrecompiledHeaderStorage<> preCompiledHeaderStorage{database};
ClangBackEnd::ProgressCounter progressCounter{
[&](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,
projectTaskScheduler,
progressCounter,
@@ -212,10 +203,32 @@ struct Data // because we have a cycle dependency
database};
ClangBackEnd::PchTaskGenerator pchTaskGenerator{buildDependencyProvider, pchTaskMerger};
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[])
{
+#ifdef Q_OS_WIN
+ qInstallMessageHandler(messageOutput);
+#endif
try {
QCoreApplication::setOrganizationName(QStringLiteral("QtProject"));
QCoreApplication::setOrganizationDomain(QStringLiteral("qt-project.org"));
diff --git a/src/tools/clangpchmanagerbackend/source/collectbuilddependencyaction.h b/src/tools/clangpchmanagerbackend/source/collectbuilddependencyaction.h
index ff861f174f0..03d27f9b21e 100644
--- a/src/tools/clangpchmanagerbackend/source/collectbuilddependencyaction.h
+++ b/src/tools/clangpchmanagerbackend/source/collectbuilddependencyaction.h
@@ -58,6 +58,7 @@ public:
auto &preprocessor = compilerInstance.getPreprocessor();
preprocessor.SetSuppressIncludeNotFoundError(true);
+ preprocessor.SetMacroExpansionOnlyInDirectives();
auto macroPreprocessorCallbacks = new CollectBuildDependencyPreprocessorCallbacks(
m_buildDependency,
diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp
index 30b6e566fa5..06adccff5b4 100644
--- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp
+++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp
@@ -66,6 +66,8 @@ void PchManagerServer::updateProjectParts(UpdateProjectPartsMessage &&message)
if (m_generatedFiles.isValid()) {
m_pchTaskGenerator.addProjectParts(std::move(newProjectParts),
std::move(message.toolChainArguments));
+ } else {
+ m_projectParts.updateDeferred(newProjectParts);
}
}
diff --git a/src/tools/clangpchmanagerbackend/source/pchtask.h b/src/tools/clangpchmanagerbackend/source/pchtask.h
index 46c3bf2503f..c94d7ac8164 100644
--- a/src/tools/clangpchmanagerbackend/source/pchtask.h
+++ b/src/tools/clangpchmanagerbackend/source/pchtask.h
@@ -43,7 +43,7 @@ public:
FilePathIds &&includes,
FilePathIds &&allIncludes,
CompilerMacros &&compilerMacros,
- UsedMacros &&usedMacros,
+ Utils::SmallStringVector &&usedMacros,
Utils::SmallStringVector toolChainArguments,
IncludeSearchPaths systemIncludeSearchPaths,
IncludeSearchPaths projectIncludeSearchPaths,
@@ -54,7 +54,6 @@ public:
, includes(includes)
, allIncludes(allIncludes)
, compilerMacros(compilerMacros)
- , usedMacros(usedMacros)
, systemIncludeSearchPaths(std::move(systemIncludeSearchPaths))
, projectIncludeSearchPaths(std::move(projectIncludeSearchPaths))
, toolChainArguments(std::move(toolChainArguments))
@@ -67,7 +66,7 @@ public:
FilePathIds &&includes,
FilePathIds &&allIncludes,
CompilerMacros &&compilerMacros,
- UsedMacros &&usedMacros,
+ Utils::SmallStringVector &&usedMacros,
Utils::SmallStringVector toolChainArguments,
IncludeSearchPaths systemIncludeSearchPaths,
IncludeSearchPaths projectIncludeSearchPaths,
@@ -78,7 +77,6 @@ public:
, includes(includes)
, allIncludes(allIncludes)
, compilerMacros(compilerMacros)
- , usedMacros(usedMacros)
, systemIncludeSearchPaths(std::move(systemIncludeSearchPaths))
, projectIncludeSearchPaths(std::move(projectIncludeSearchPaths))
, toolChainArguments(std::move(toolChainArguments))
@@ -92,7 +90,6 @@ public:
return first.systemPchPath == second.systemPchPath
&& first.projectPartIds == second.projectPartIds && first.includes == second.includes
&& first.compilerMacros == second.compilerMacros
- && first.usedMacros == second.usedMacros
&& first.systemIncludeSearchPaths == second.systemIncludeSearchPaths
&& first.projectIncludeSearchPaths == second.projectIncludeSearchPaths
&& first.toolChainArguments == second.toolChainArguments
@@ -109,13 +106,13 @@ public:
FilePathIds includes;
FilePathIds allIncludes;
CompilerMacros compilerMacros;
- UsedMacros usedMacros;
IncludeSearchPaths systemIncludeSearchPaths;
IncludeSearchPaths projectIncludeSearchPaths;
Utils::SmallStringVector toolChainArguments;
Utils::Language language = Utils::Language::Cxx;
Utils::LanguageVersion languageVersion = Utils::LanguageVersion::CXX98;
Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None;
+ bool isMerged = false;
};
class PchTaskSet
diff --git a/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp b/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp
index 569e4a1d8a3..82584ad1dd8 100644
--- a/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp
+++ b/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp
@@ -42,9 +42,9 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts,
for (auto &projectPart : projectParts) {
BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart);
- UsedMacroFilter filter{buildDependency.includes, buildDependency.usedMacros};
-
- filter.filter(projectPart.compilerMacros);
+ UsedMacroFilter filter{buildDependency.includes,
+ buildDependency.usedMacros,
+ projectPart.compilerMacros};
pchTaskSets.emplace_back(PchTask{projectPart.projectPartId.clone(),
std::move(filter.topSystemIncludes),
@@ -53,7 +53,7 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts,
std::move(filter.systemUsedMacros),
projectPart.toolChainArguments,
projectPart.systemIncludeSearchPaths,
- projectPart.projectIncludeSearchPaths,
+ {},
projectPart.language,
projectPart.languageVersion,
projectPart.languageExtension},
diff --git a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp
index 9ace04e09de..636d9a32364 100644
--- a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp
+++ b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp
@@ -30,20 +30,10 @@
namespace ClangBackEnd {
void PchTasksMerger::mergeTasks(PchTaskSets &&taskSets,
- Utils::SmallStringVector &&/*toolChainArguments*/)
+ Utils::SmallStringVector && /*toolChainArguments*/)
{
- PchTasks systemTasks;
- systemTasks.reserve(taskSets.size());
- 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));
+ mergeSystemTasks(taskSets);
+ addProjectTasksToQueue(taskSets);
m_pchTaskQueue.processEntries();
}
@@ -52,4 +42,117 @@ void PchTasksMerger::removePchTasks(const Utils::SmallStringVector &projectPartI
m_pchTaskQueue.removePchTasks(projectPartIds);
}
+template>>
+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 ¤tTask) {
+ 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
diff --git a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.h b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.h
index 9c777b8a7cb..26df2022b4d 100644
--- a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.h
+++ b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.h
@@ -32,7 +32,7 @@ namespace ClangBackEnd {
class PchTaskQueueInterface;
-class PchTasksMerger : public PchTasksMergerInterface
+class PchTasksMerger final : public PchTasksMergerInterface
{
public:
PchTasksMerger(PchTaskQueueInterface &pchTaskQueue)
@@ -42,6 +42,18 @@ public:
void mergeTasks(PchTaskSets &&taskSets, Utils::SmallStringVector &&toolChainArguments) 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:
PchTaskQueueInterface &m_pchTaskQueue;
};
diff --git a/src/tools/clangpchmanagerbackend/source/taskscheduler.h b/src/tools/clangpchmanagerbackend/source/taskscheduler.h
index 621baef0909..37fdc744a84 100644
--- a/src/tools/clangpchmanagerbackend/source/taskscheduler.h
+++ b/src/tools/clangpchmanagerbackend/source/taskscheduler.h
@@ -80,6 +80,11 @@ public:
, m_callDoInMainThreadAfterFinished(callDoInMainThreadAfterFinished)
{}
+ ~TaskScheduler()
+ {
+ syncTasks();
+ }
+
void addTasks(std::vector &&tasks)
{
for (auto &task : tasks) {
diff --git a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h
index e7969c4ea1b..0b39ae1f4f2 100644
--- a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h
+++ b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h
@@ -32,6 +32,27 @@
namespace ClangBackEnd {
+template
+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
{
public:
@@ -41,11 +62,14 @@ public:
FilePathIds system;
};
- UsedMacroFilter(const SourceEntries &includes, const UsedMacros &usedMacros)
+ UsedMacroFilter(const SourceEntries &includes,
+ const UsedMacros &usedMacros,
+ const CompilerMacros &compilerMacros)
{
filterIncludes(includes);
systemUsedMacros = filterUsedMarcos(usedMacros, systemIncludes);
projectUsedMacros = filterUsedMarcos(usedMacros, projectIncludes);
+ filter(compilerMacros);
}
void filterIncludes(const SourceEntries &includes)
@@ -98,7 +122,8 @@ private:
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
{
@@ -113,52 +138,57 @@ private:
}
};
- UsedMacros filtertedMacros;
+ Utils::SmallStringVector filtertedMacros;
filtertedMacros.reserve(usedMacros.size());
- std::set_intersection(usedMacros.begin(),
- usedMacros.end(),
- filePathId.begin(),
- filePathId.end(),
- std::back_inserter(filtertedMacros),
- Compare{});
+ set_greedy_intersection(usedMacros.begin(),
+ usedMacros.end(),
+ filePathId.begin(),
+ filePathId.end(),
+ std::back_inserter(filtertedMacros),
+ Compare{});
- std::sort(filtertedMacros.begin(),
- filtertedMacros.end(),
- [](const UsedMacro &first, const UsedMacro &second) {
- return first.macroName < second.macroName;
- });
+ std::sort(filtertedMacros.begin(), filtertedMacros.end());
return filtertedMacros;
}
static CompilerMacros filtercompilerMacros(const CompilerMacros &indexedCompilerMacro,
- const UsedMacros &usedMacros)
+ const Utils::SmallStringVector &usedMacros)
{
+ CompilerMacros filtertedCompilerMacros;
+ filtertedCompilerMacros.reserve(indexedCompilerMacro.size() + usedMacros.size());
+
struct Compare
{
- bool operator()(const UsedMacro &usedMacro,
- const CompilerMacro &compileMacro)
+ bool operator()(const CompilerMacro &compilerMacro, Utils::SmallStringView usedMacro)
{
- return usedMacro.macroName < compileMacro.key;
+ return compilerMacro.key < usedMacro;
}
- bool operator()(const CompilerMacro &compileMacro,
- const UsedMacro &usedMacro)
+ bool operator()(Utils::SmallStringView usedMacro, const CompilerMacro &compilerMacro)
{
- return compileMacro.key < usedMacro.macroName;
+ return usedMacro < compilerMacro.key;
}
};
- CompilerMacros filtertedCompilerMacros;
- filtertedCompilerMacros.reserve(indexedCompilerMacro.size());
+ set_greedy_intersection(indexedCompilerMacro.begin(),
+ indexedCompilerMacro.end(),
+ usedMacros.begin(),
+ usedMacros.end(),
+ std::back_inserter(filtertedCompilerMacros),
+ Compare{});
- std::set_intersection(indexedCompilerMacro.begin(),
- indexedCompilerMacro.end(),
- usedMacros.begin(),
- usedMacros.end(),
- std::back_inserter(filtertedCompilerMacros),
- Compare{});
+ auto split = filtertedCompilerMacros.end();
+
+ std::set_difference(usedMacros.begin(),
+ usedMacros.end(),
+ filtertedCompilerMacros.begin(),
+ filtertedCompilerMacros.end(),
+ std::back_inserter(filtertedCompilerMacros),
+ Compare{});
+
+ std::inplace_merge(filtertedCompilerMacros.begin(), split, filtertedCompilerMacros.end());
return filtertedCompilerMacros;
}
@@ -169,8 +199,8 @@ public:
FilePathIds systemIncludes;
FilePathIds topProjectIncludes;
FilePathIds topSystemIncludes;
- UsedMacros projectUsedMacros;
- UsedMacros systemUsedMacros;
+ Utils::SmallStringVector projectUsedMacros;
+ Utils::SmallStringVector systemUsedMacros;
CompilerMacros projectCompilerMacros;
CompilerMacros systemCompilerMacros;
};
diff --git a/src/tools/clangrefactoringbackend/clangrefactoringbackendmain.cpp b/src/tools/clangrefactoringbackend/clangrefactoringbackendmain.cpp
index 07e594b7217..23a127c17f2 100644
--- a/src/tools/clangrefactoringbackend/clangrefactoringbackendmain.cpp
+++ b/src/tools/clangrefactoringbackend/clangrefactoringbackendmain.cpp
@@ -39,6 +39,7 @@
#include
#include
+#include
using namespace std::chrono_literals;
@@ -93,12 +94,24 @@ struct Data // because we have a cycle dependency
RefactoringDatabaseInitializer databaseInitializer{database};
FilePathCaching filePathCache{database};
GeneratedFiles generatedFiles;
- SymbolIndexing symbolIndexing{database, filePathCache, generatedFiles, [&] (int progress, int total) { clangCodeModelServer.setProgress(progress, total); }};
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[])
{
+#ifdef Q_OS_WIN
+ qInstallMessageHandler(messageOutput);
+#endif
try {
QCoreApplication::setOrganizationName(QStringLiteral("QtProject"));
QCoreApplication::setOrganizationDomain(QStringLiteral("qt-project.org"));
diff --git a/src/tools/clangrefactoringbackend/source/clangtool.h b/src/tools/clangrefactoringbackend/source/clangtool.h
index b9d366859e3..8b4e47df682 100644
--- a/src/tools/clangrefactoringbackend/source/clangtool.h
+++ b/src/tools/clangrefactoringbackend/source/clangtool.h
@@ -95,8 +95,6 @@ public:
bool isClean() const;
-
-
private:
RefactoringCompilationDatabase m_compilationDatabase;
std::vector m_fileContents;
diff --git a/src/tools/clangrefactoringbackend/source/collectmacrossourcefilecallbacks.cpp b/src/tools/clangrefactoringbackend/source/collectmacrossourcefilecallbacks.cpp
index d96fb05026c..d0d107e45e2 100644
--- a/src/tools/clangrefactoringbackend/source/collectmacrossourcefilecallbacks.cpp
+++ b/src/tools/clangrefactoringbackend/source/collectmacrossourcefilecallbacks.cpp
@@ -45,6 +45,8 @@ bool CollectMacrosSourceFileCallbacks::handleBeginSource(clang::CompilerInstance
compilerInstance.getPreprocessorPtr(),
m_sourcesManager);
+ compilerInstance.getLangOpts().DelayedTemplateParsing = false;
+ compilerInstance.getPreprocessorPtr()->SetSuppressIncludeNotFoundError(true);
compilerInstance.getPreprocessorPtr()->addPPCallbacks(std::move(callbacks));
return true;
diff --git a/src/tools/clangrefactoringbackend/source/symbolindexing.h b/src/tools/clangrefactoringbackend/source/symbolindexing.h
index 6f52f863d85..62be193682c 100644
--- a/src/tools/clangrefactoringbackend/source/symbolindexing.h
+++ b/src/tools/clangrefactoringbackend/source/symbolindexing.h
@@ -124,8 +124,6 @@ private:
FileStatusCache m_fileStatusCache{m_filePathCache};
SymbolsCollectorManager m_collectorManger;
ProgressCounter m_progressCounter;
- SymbolIndexerTaskScheduler m_indexerScheduler;
- SymbolIndexerTaskQueue m_indexerQueue{m_indexerScheduler, m_progressCounter};
SymbolIndexer m_indexer{m_indexerQueue,
m_symbolStorage,
m_buildDependencyStorage,
@@ -133,6 +131,8 @@ private:
m_filePathCache,
m_fileStatusCache,
m_symbolStorage.m_database};
+ SymbolIndexerTaskQueue m_indexerQueue{m_indexerScheduler, m_progressCounter};
+ SymbolIndexerTaskScheduler m_indexerScheduler;
};
} // namespace ClangBackEnd
diff --git a/src/tools/clangrefactoringbackend/source/symbolstorage.h b/src/tools/clangrefactoringbackend/source/symbolstorage.h
index f2993f9a43c..f1fdbc7c02e 100644
--- a/src/tools/clangrefactoringbackend/source/symbolstorage.h
+++ b/src/tools/clangrefactoringbackend/source/symbolstorage.h
@@ -341,12 +341,14 @@ public:
m_database};
mutable ReadStatement m_getProjectPartArtefactsBySourceId{
"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 = ?)",
m_database};
mutable ReadStatement m_getProjectPartArtefactsByProjectPartName{
"SELECT toolChainArguments, compilerMacros, systemIncludeSearchPaths, "
- "projectIncludeSearchPaths, projectPartId FROM projectParts WHERE projectPartName = ?",
+ "projectIncludeSearchPaths, projectPartId, language, languageVersion, languageExtension "
+ "FROM projectParts WHERE projectPartName = ?",
m_database};
mutable ReadStatement m_getPrecompiledHeader{
"SELECT projectPchPath, projectPchBuildTime FROM precompiledHeaders WHERE projectPartId = ?",
diff --git a/src/tools/clangrefactoringbackend/source/symbolsvisitorbase.h b/src/tools/clangrefactoringbackend/source/symbolsvisitorbase.h
index c833f73afbe..ff2142f40e2 100644
--- a/src/tools/clangrefactoringbackend/source/symbolsvisitorbase.h
+++ b/src/tools/clangrefactoringbackend/source/symbolsvisitorbase.h
@@ -68,7 +68,8 @@ public:
bool isAlreadyParsed(clang::FileID fileId)
{
const clang::FileEntry *fileEntry = m_sourceManager->getFileEntryForID(fileId);
-
+ if (!fileEntry)
+ return false;
return m_sourcesManager.alreadyParsed(filePathId(fileEntry),
fileEntry->getModificationTime());
}
diff --git a/src/tools/clangrefactoringbackend/source/usedmacro.h b/src/tools/clangrefactoringbackend/source/usedmacro.h
index a7312b63761..8fc992e39b1 100644
--- a/src/tools/clangrefactoringbackend/source/usedmacro.h
+++ b/src/tools/clangrefactoringbackend/source/usedmacro.h
@@ -62,6 +62,10 @@ public:
{
return !(first == second);
}
+
+ operator Utils::SmallStringView() const { return macroName; }
+ operator const Utils::SmallString &() const { return macroName; }
+
public:
Utils::SmallString macroName;
FilePathId filePathId;
diff --git a/tests/system/suite_debugger/tst_simple_analyze/test.py b/tests/system/suite_debugger/tst_simple_analyze/test.py
index 202c5053b25..111336e33a9 100644
--- a/tests/system/suite_debugger/tst_simple_analyze/test.py
+++ b/tests/system/suite_debugger/tst_simple_analyze/test.py
@@ -103,7 +103,7 @@ def performTest(workingDir, projectName, availableConfigs):
compareEventsTab(model, "events_qt%s.tsv" % qtVersion)
test.compare(dumpItems(model, column=colPercent)[0], '100 %')
# 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]:
test.verify(item.endswith('ms'), "Verify that '%s' ends with 'ms'" % item)
for i in [colTotal, colMean, colMedian, colLongest, colShortest]:
diff --git a/tests/unit/unittest/builddependencycollector-test.cpp b/tests/unit/unittest/builddependencycollector-test.cpp
index 4631a883766..3c9ea84d32b 100644
--- a/tests/unit/unittest/builddependencycollector-test.cpp
+++ b/tests/unit/unittest/builddependencycollector-test.cpp
@@ -435,9 +435,7 @@ TEST_F(BuildDependencyCollector, CollectUsedMacrosWithExternalDefine)
ElementsAre(Eq(UsedMacro{"DEFINED", fileId}),
Eq(UsedMacro{"IF_DEFINE", fileId}),
Eq(UsedMacro{"__clang__", fileId}),
- Eq(UsedMacro{"CLASS_EXPORT", fileId}),
Eq(UsedMacro{"IF_NOT_DEFINE", fileId}),
- Eq(UsedMacro{"MACRO_EXPANSION", fileId}),
Eq(UsedMacro{"COMPILER_ARGUMENT", fileId})));
}
@@ -452,9 +450,7 @@ TEST_F(BuildDependencyCollector, CollectUsedMacrosWithoutExternalDefine)
ElementsAre(Eq(UsedMacro{"DEFINED", fileId}),
Eq(UsedMacro{"IF_DEFINE", fileId}),
Eq(UsedMacro{"__clang__", fileId}),
- Eq(UsedMacro{"CLASS_EXPORT", fileId}),
Eq(UsedMacro{"IF_NOT_DEFINE", fileId}),
- Eq(UsedMacro{"MACRO_EXPANSION", fileId}),
Eq(UsedMacro{"COMPILER_ARGUMENT", fileId})));
}
@@ -639,7 +635,6 @@ TEST_F(BuildDependencyCollector, Create)
SourceType::TopProjectInclude))),
Field(&BuildDependency::usedMacros,
UnorderedElementsAre(
- UsedMacro{"DEFINE", id(TESTDATA_DIR "/builddependencycollector/project/macros.h")},
UsedMacro{"IFDEF", id(TESTDATA_DIR "/builddependencycollector/project/macros.h")},
UsedMacro{"DEFINED",
id(TESTDATA_DIR "/builddependencycollector/project/macros.h")})),
diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp
index 771e3159fe5..8b64fb19149 100644
--- a/tests/unit/unittest/clangformat-test.cpp
+++ b/tests/unit/unittest/clangformat-test.cpp
@@ -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
{
protected:
void SetUp() final
{
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 &lines)
@@ -85,6 +100,7 @@ protected:
QTextDocument doc;
ClangFormatIndenter indenter{&doc};
+ ClangFormatExtendedIndenter extendedIndenter{&doc};
QTextCursor cursor{&doc};
};
@@ -315,6 +331,83 @@ TEST_F(ClangFormat, NoExtraIndentAfterBraceInitialization)
"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)
{
insertLines({"int main()",
diff --git a/tests/unit/unittest/commandlinebuilder-test.cpp b/tests/unit/unittest/commandlinebuilder-test.cpp
index f51a4f6a714..c3dad70de3c 100644
--- a/tests/unit/unittest/commandlinebuilder-test.cpp
+++ b/tests/unit/unittest/commandlinebuilder-test.cpp
@@ -136,7 +136,7 @@ TYPED_TEST(CommandLineBuilder, CTask)
ASSERT_THAT(
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)
@@ -153,7 +153,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCTask)
"objective-c-header",
"-std=c11",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"/source/file.c"));
}
@@ -170,7 +170,7 @@ TYPED_TEST(CommandLineBuilder, CppTask)
"c++-header",
"-std=c++98",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"/source/file.cpp"));
}
@@ -188,7 +188,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCppTask)
"objective-c++-header",
"-std=c++98",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"/source/file.cpp"));
}
@@ -420,7 +420,7 @@ TYPED_TEST(CommandLineBuilder, IncludesOrder)
"c++-header",
"-std=c++11",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"-I",
"/include/foo",
"-I",
@@ -441,7 +441,7 @@ TYPED_TEST(CommandLineBuilder, EmptySourceFile)
Builder builder{this->emptyProjectInfo, {}, {}};
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)
@@ -454,7 +454,7 @@ TYPED_TEST(CommandLineBuilder, SourceFile)
"c++-header",
"-std=c++98",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"/source/file.cpp"));
}
@@ -469,7 +469,7 @@ TYPED_TEST(CommandLineBuilder, EmptyOutputFile)
"c++-header",
"-std=c++98",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"/source/file.cpp"));
}
@@ -483,7 +483,7 @@ TYPED_TEST(CommandLineBuilder, OutputFile)
"c++-header",
"-std=c++98",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"-o",
"/output/file.o",
"/source/file.cpp"));
@@ -499,7 +499,7 @@ TYPED_TEST(CommandLineBuilder, IncludePchPath)
"c++-header",
"-std=c++98",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"-Xclang",
"-include-pch",
"-Xclang",
@@ -511,7 +511,7 @@ TYPED_TEST(CommandLineBuilder, IncludePchPath)
TYPED_TEST(CommandLineBuilder, CompilerMacros)
{
- this->emptyProjectInfo.compilerMacros = {{"YI", "1", 2}, {"ER", "2", 1}};
+ this->emptyProjectInfo.compilerMacros = {{"YI", "1", 2}, {"ER", "2", 1}, {"SAN"}};
Builder builder{this->emptyProjectInfo};
@@ -521,7 +521,7 @@ TYPED_TEST(CommandLineBuilder, CompilerMacros)
"c++-header",
"-std=c++98",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"-DER=2",
"-DYI=1"));
}
diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp
index 682d28740b0..3901cb0d305 100644
--- a/tests/unit/unittest/gtest-creator-printing.cpp
+++ b/tests/unit/unittest/gtest-creator-printing.cpp
@@ -1157,10 +1157,9 @@ std::ostream &operator<<(std::ostream &out, const PchCreatorIncludes &includes)
std::ostream &operator<<(std::ostream &out, const PchTask &task)
{
return out << "(" << task.projectPartIds << ", " << task.includes << ", " << task.compilerMacros
- << ", " << task.usedMacros << ", " << toText(task.language) << ", "
- << task.systemIncludeSearchPaths << ", " << task.projectIncludeSearchPaths << ", "
- << task.toolChainArguments << ", " << toText(task.languageVersion) << ", "
- << toText(task.languageExtension) << ")";
+ << toText(task.language) << ", " << task.systemIncludeSearchPaths << ", "
+ << task.projectIncludeSearchPaths << ", " << task.toolChainArguments << ", "
+ << toText(task.languageVersion) << ", " << toText(task.languageExtension) << ")";
}
std::ostream &operator<<(std::ostream &out, const PchTaskSet &taskSet)
diff --git a/tests/unit/unittest/pchcreator-test.cpp b/tests/unit/unittest/pchcreator-test.cpp
index 0da712d9836..26ca9965c2f 100644
--- a/tests/unit/unittest/pchcreator-test.cpp
+++ b/tests/unit/unittest/pchcreator-test.cpp
@@ -157,7 +157,7 @@ TEST_F(PchCreator, CreateProjectPartClangCompilerArguments)
"c++-header",
"-std=c++98",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"-I",
TESTDATA_DIR "/builddependencycollector/project",
"-isystem",
@@ -183,7 +183,7 @@ TEST_F(PchCreator, CreateProjectPartClangCompilerArgumentsWithSystemPch)
"c++-header",
"-std=c++98",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"-I",
TESTDATA_DIR "/builddependencycollector/project",
"-isystem",
diff --git a/tests/unit/unittest/pchmanagerserver-test.cpp b/tests/unit/unittest/pchmanagerserver-test.cpp
index 9100b51dc30..0cb6e3d1baf 100644
--- a/tests/unit/unittest/pchmanagerserver-test.cpp
+++ b/tests/unit/unittest/pchmanagerserver-test.cpp
@@ -47,6 +47,7 @@ using Utils::SmallString;
using ClangBackEnd::V2::FileContainer;
using ClangBackEnd::V2::FileContainers;
using ClangBackEnd::ProjectPartContainer;
+using ClangBackEnd::ProjectPartContainers;
class PchManagerServer : public ::testing::Test
{
@@ -198,8 +199,11 @@ TEST_F(PchManagerServer, DontGeneratePchIfGeneratedFilesAreNotValid)
{
InSequence s;
+ EXPECT_CALL(mockProjectParts, update(ElementsAre(projectPart1)))
+ .WillOnce(Return(ProjectPartContainers{projectPart1}));
EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(false));
EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)).Times(0);
+ EXPECT_CALL(mockProjectParts, updateDeferred(ElementsAre(projectPart1)));
server.updateProjectParts(
ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}});
@@ -209,8 +213,11 @@ TEST_F(PchManagerServer, GeneratePchIfGeneratedFilesAreValid)
{
InSequence s;
+ EXPECT_CALL(mockProjectParts, update(ElementsAre(projectPart1)))
+ .WillOnce(Return(ProjectPartContainers{projectPart1}));
EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(true));
EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _));
+ EXPECT_CALL(mockProjectParts, updateDeferred(_)).Times(0);
server.updateProjectParts(
ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}});
diff --git a/tests/unit/unittest/pchtaskgenerator-test.cpp b/tests/unit/unittest/pchtaskgenerator-test.cpp
index 0b2ec3968e3..a3ebb3c17be 100644
--- a/tests/unit/unittest/pchtaskgenerator-test.cpp
+++ b/tests/unit/unittest/pchtaskgenerator-test.cpp
@@ -99,7 +99,6 @@ TEST_F(PchTaskGenerator, AddProjectParts)
Field(&PchTask::allIncludes, IsEmpty()),
Field(&PchTask::compilerMacros,
ElementsAre(CompilerMacro{"SE", "4", 4}, CompilerMacro{"WU", "5", 5})),
- Field(&PchTask::usedMacros, ElementsAre(UsedMacro{"SE", 4}, UsedMacro{"WU", 5})),
Field(&PchTask::systemIncludeSearchPaths,
ElementsAre(
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::compilerMacros,
ElementsAre(CompilerMacro{"YI", "1", 1}, CompilerMacro{"SAN", "3", 3})),
- Field(&PchTask::usedMacros, ElementsAre(UsedMacro{"YI", 1}, UsedMacro{"SAN", 3})),
Field(&PchTask::systemIncludeSearchPaths,
ElementsAre(
IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System},
diff --git a/tests/unit/unittest/pchtasksmerger-test.cpp b/tests/unit/unittest/pchtasksmerger-test.cpp
index f54e7aca582..e878438f339 100644
--- a/tests/unit/unittest/pchtasksmerger-test.cpp
+++ b/tests/unit/unittest/pchtasksmerger-test.cpp
@@ -31,11 +31,14 @@
namespace {
+using ClangBackEnd::CompilerMacro;
+using ClangBackEnd::CompilerMacros;
using ClangBackEnd::IncludeSearchPath;
using ClangBackEnd::IncludeSearchPathType;
using ClangBackEnd::PchTask;
using ClangBackEnd::PchTaskSet;
-
+using Merger = ClangBackEnd::PchTasksMerger;
+using Id = ClangBackEnd::FilePathId;
class PchTasksMerger : public testing::Test
{
protected:
@@ -51,48 +54,58 @@ protected:
ClangBackEnd::PchTasksMerger merger{mockPchTaskQueue};
PchTask systemTask1{"ProjectPart1",
{1, 2},
- {1, 2},
+ {1, 2, 3},
{{"YI", "1", 1}, {"SAN", "3", 3}},
- {{"LIANG", 0}, {"YI", 1}},
+ {"YI", "LIANG"},
{"--yi"},
- {IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System},
- IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn},
- IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}},
- {IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User},
- IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}};
+ {{"/system/path", 2, IncludeSearchPathType::System},
+ {"/builtin/path2", 3, IncludeSearchPathType::BuiltIn},
+ {"/framework/path", 1, IncludeSearchPathType::System}},
+ {{"/to/path1", 1, IncludeSearchPathType::User},
+ {"/to/path2", 2, IncludeSearchPathType::User}}};
PchTask projectTask1{"ProjectPart1",
{11, 12},
{11, 12},
{{"SE", "4", 4}, {"WU", "5", 5}},
- {{"ER", 2}, {"SAN", 3}},
+ {"ER", "SAN"},
{"--yi"},
- {IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System},
- IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn},
- IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}},
- {IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User},
- IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}};
+ {{"/system/path", 1, IncludeSearchPathType::System},
+ {"/builtin/path", 2, IncludeSearchPathType::BuiltIn}},
+ {{"/to/path1", 1, IncludeSearchPathType::User},
+ {"/to/path2", 2, IncludeSearchPathType::User}}};
PchTask systemTask2{"ProjectPart2",
- {1, 2},
- {1, 2},
- {{"YI", "1", 1}, {"SAN", "3", 3}},
- {{"LIANG", 0}, {"YI", 1}},
+ {11, 12},
+ {11, 12, 13},
+ {{"SE", "4", 4}, {"WU", "5", 5}},
+ {"ER", "SAN"},
{"--yi"},
- {IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System},
- IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn},
- IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}},
- {IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User},
- IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}};
+ {{"/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}}};
PchTask projectTask2{"ProjectPart2",
{11, 12},
{11, 12},
{{"SE", "4", 4}, {"WU", "5", 5}},
- {{"ER", 2}, {"SAN", 3}},
+ {"ER", "SAN"},
{"--yi"},
- {IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System},
- IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn},
- IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}},
- {IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User},
- IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}};
+ {{"/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}}};
+ 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"};
};
@@ -103,21 +116,33 @@ TEST_F(PchTasksMerger, AddProjectTasks)
EXPECT_CALL(mockPchTaskQueue, addProjectPchTasks(ElementsAre(projectTask1, projectTask2)));
EXPECT_CALL(mockPchTaskQueue, processEntries());
- merger.mergeTasks(
- {{clone(systemTask1), clone(projectTask1)}, {clone(systemTask1), clone(projectTask2)}},
- std::move(toolChainArguments));
+ merger.mergeTasks({{clone(systemTask1), clone(projectTask1)},
+ {clone(systemTask1), clone(projectTask2)}},
+ std::move(toolChainArguments));
}
TEST_F(PchTasksMerger, AddSystemTasks)
{
InSequence s;
- EXPECT_CALL(mockPchTaskQueue, addSystemPchTasks(ElementsAre(systemTask1, systemTask2)));
+ EXPECT_CALL(mockPchTaskQueue, addSystemPchTasks(ElementsAre(_, systemTask3)));
EXPECT_CALL(mockPchTaskQueue, processEntries());
- merger.mergeTasks(
- {{clone(systemTask1), clone(projectTask1)}, {clone(systemTask2), clone(projectTask2)}},
- std::move(toolChainArguments));
+ merger.mergeTasks({{clone(systemTask1), clone(projectTask1)},
+ {clone(systemTask2), clone(projectTask2)},
+ {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)
@@ -126,4 +151,233 @@ TEST_F(PchTasksMerger, RemoveTasks)
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
diff --git a/tests/unit/unittest/symbolindexer-test.cpp b/tests/unit/unittest/symbolindexer-test.cpp
index 23f469cd340..104c17b11b3 100644
--- a/tests/unit/unittest/symbolindexer-test.cpp
+++ b/tests/unit/unittest/symbolindexer-test.cpp
@@ -241,12 +241,6 @@ protected:
Manager collectorManger{generatedFiles};
NiceMock> mockSetProgressCallback;
ClangBackEnd::ProgressCounter progressCounter{mockSetProgressCallback.AsStdFunction()};
- Scheduler indexerScheduler{collectorManger,
- indexerQueue,
- progressCounter,
- 1,
- ClangBackEnd::CallDoInMainThreadAfterFinished::Yes};
- SymbolIndexerTaskQueue indexerQueue{indexerScheduler, progressCounter};
ClangBackEnd::SymbolIndexer indexer{indexerQueue,
mockSymbolStorage,
mockBuildDependenciesStorage,
@@ -254,6 +248,12 @@ protected:
filePathCache,
fileStatusCache,
mockSqliteTransactionBackend};
+ SymbolIndexerTaskQueue indexerQueue{indexerScheduler, progressCounter};
+ Scheduler indexerScheduler{collectorManger,
+ indexerQueue,
+ progressCounter,
+ 1,
+ ClangBackEnd::CallDoInMainThreadAfterFinished::Yes};
MockSymbolsCollector &mockCollector{static_cast(collectorManger.unusedProcessor())};
};
@@ -269,7 +269,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesInCollector)
"c++-header",
"-std=c++14",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"-DBAR=1",
"-DFOO=1",
"-I",
@@ -299,7 +299,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithPrecompiledHeaderInColl
"c++-header",
"-std=c++14",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"-DBAR=1",
"-DFOO=1",
"-I",
@@ -332,7 +332,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithoutPrecompiledHeaderInC
"c++-header",
"-std=c++14",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"-DBAR=1",
"-DFOO=1",
"-I",
@@ -512,7 +512,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithoutProjectPartArtifact)
"c++-header",
"-std=c++14",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"-DBAR=1",
"-DFOO=1",
"-I",
@@ -564,7 +564,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithProjectPartArtifact)
"c++-header",
"-std=c++14",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"-DBAR=1",
"-DFOO=1",
"-I",
@@ -620,7 +620,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrder)
"c++-header",
"-std=c++14",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"-DBAR=1",
"-DFOO=1",
"-I",
@@ -682,7 +682,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathIsUsingPrecompiledHeader)
"c++-header",
"-std=c++14",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"-DBAR=1",
"-DFOO=1",
"-I",
@@ -717,7 +717,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathIsNotUsingPrecompiledHeaderIfItNotExists)
"c++-header",
"-std=c++14",
"-nostdinc",
- "-nostdlibinc",
+ "-nostdinc++",
"-DBAR=1",
"-DFOO=1",
"-I",
diff --git a/tests/unit/unittest/usedmacrofilter-test.cpp b/tests/unit/unittest/usedmacrofilter-test.cpp
index bc5b79cccf5..b02cd7e5e02 100644
--- a/tests/unit/unittest/usedmacrofilter-test.cpp
+++ b/tests/unit/unittest/usedmacrofilter-test.cpp
@@ -46,7 +46,7 @@ protected:
{3, SourceType::ProjectInclude, 0},
{4, SourceType::TopSystemInclude, 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},
{"ER", "2", 2},
{"SAN", "3", 3},
@@ -57,36 +57,35 @@ protected:
TEST_F(UsedMacroFilter, SystemIncludes)
{
- ClangBackEnd::UsedMacroFilter filter(includes, usedMacros);
+ ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.systemIncludes, ElementsAre(FilePathId{2}, FilePathId{4}));
}
TEST_F(UsedMacroFilter, ProjectIncludes)
{
- ClangBackEnd::UsedMacroFilter filter(includes, usedMacros);
+ ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.projectIncludes, ElementsAre(FilePathId{3}, FilePathId{5}));
}
TEST_F(UsedMacroFilter, TopSystemIncludes)
{
- ClangBackEnd::UsedMacroFilter filter(includes, usedMacros);
+ ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.topSystemIncludes, ElementsAre(FilePathId{4}));
}
TEST_F(UsedMacroFilter, TopProjectIncludes)
{
- ClangBackEnd::UsedMacroFilter filter(includes, usedMacros);
+ ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.topProjectIncludes, ElementsAre(FilePathId{5}));
}
-
TEST_F(UsedMacroFilter, AllIncludes)
{
- ClangBackEnd::UsedMacroFilter filter(includes, usedMacros);
+ ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.allIncludes,
ElementsAre(FilePathId{1}, FilePathId{2}, FilePathId{3}, FilePathId{4}, FilePathId{5}));
@@ -94,36 +93,36 @@ TEST_F(UsedMacroFilter, AllIncludes)
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)
{
- 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)
{
- ClangBackEnd::UsedMacroFilter filter(includes, usedMacros);
-
- filter.filter(compileMacros);
+ ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
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)
{
- ClangBackEnd::UsedMacroFilter filter(includes, usedMacros);
-
- filter.filter(compileMacros);
+ ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
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