Merge remote-tracking branch 'origin/4.9'

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

View File

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

View File

@@ -182,6 +182,13 @@ public:
{
CompilerMacros macros = compilerMacros;
macros.erase(std::remove_if(macros.begin(),
macros.end(),
[](const auto &macro) {
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:

View File

@@ -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<unsigned char>(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<CompilerMacroType>(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<CompilerMacro>;

View File

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

View File

@@ -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);

View File

@@ -27,6 +27,7 @@
#include <clang/Tooling/Core/Replacement.h>
#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <utils/textutils.h>
#include <utils/qtcassert.h>
@@ -57,19 +58,28 @@ 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<int>(replacement.getOffset());
if (onlyIndention && replacementOffset != offset - 1)
const bool replacementDoesNotMatchRestriction
= (replacementsToKeep == ReplacementsToKeep::OnlyIndent
&& replacementOffset != offset - 1)
|| (replacementsToKeep == ReplacementsToKeep::OnlyBeforeIndent
&& replacementOffset >= offset + utf8LineLengthBeforeCursor - 1);
if (replacementDoesNotMatchRestriction)
continue;
if (replacementOffset + 1 >= offset)
replacementOffset += extraOffsetToAdd;
if (replacementOffset >= offset - 1)
replacementOffset += extraEmptySpaceOffset;
replacementOffset += extraOffsetFromStartOfFile;
llvm::StringRef text = onlyIndention ? clearExtraNewline(replacement.getReplacementText())
llvm::StringRef text = replacementsToKeep == ReplacementsToKeep::OnlyIndent
? clearExtraNewline(replacement.getReplacementText())
: replacement.getReplacementText();
llvm::Error error = filtered.add(
@@ -78,9 +88,15 @@ 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 &currentBlock)
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
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 &currentBlock,
const QByteArray &buffer,
int documentRevision)
{
QTextBlock prevBlock = currentBlock.previous();
while ((prevBlock.position() > 0 || prevBlock.length() > 0)
&& prevBlock.revision() != documentRevision
&& (currentBlock.blockNumber() - prevBlock.blockNumber() < kMaxLinesFromCurrentBlock)) {
// Find the first block with not matching revision.
prevBlock = prevBlock.previous();
}
if (prevBlock.revision() == documentRevision)
prevBlock = prevBlock.next();
return Utils::Text::utf8NthLineOffset(prevBlock.document(), buffer, prevBlock.blockNumber() + 1);
}
TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer,
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(),
extraOffsetFromStartOfFile
= Utils::Text::utf8NthLineOffset(block.document(),
buffer,
block.blockNumber()
- kMaxLinesFromCurrentBlock);
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;
extraEmptySpaceOffset = previousEmptyLinesLength(block);
utf8Offset -= extraEmptySpaceOffset;
buffer.remove(utf8Offset, extraEmptySpaceOffset);
if (replacementsToKeep == ReplacementsToKeep::OnlyIndent)
adjustFormatStyleForLineBreak(style);
if (typedChar == QChar::Null)
modifyToIndentEmptyLines(buffer, utf8Offset, utf8Length, block, secondTry);
}
std::vector<clang::tooling::Range> ranges{
{static_cast<unsigned int>(utf8Offset), static_cast<unsigned int>(utf8Length)}};
if (replacementsToKeep != ReplacementsToKeep::OnlyBeforeIndent || utf8Offset < rangeStart)
rangeStart = utf8Offset;
unsigned int rangeLength = static_cast<unsigned int>(utf8Offset + utf8Length - rangeStart);
std::vector<clang::tooling::Range> ranges{{static_cast<unsigned int>(rangeStart), rangeLength}};
clang::format::FormattingAttemptStatus status;
clang::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,
clang::tooling::Replacements filtered;
if (status.FormatComplete) {
filtered = filteredReplacements(clangReplacements,
utf8Offset,
extraOffset,
onlyIndention);
const bool canTryAgain = onlyIndention && typedChar == QChar::Null && !secondTry;
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);
}

View File

@@ -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;
};

View File

@@ -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();
}

View File

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

View File

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

View File

@@ -32,5 +32,7 @@ static const char SETTINGS_FILE_ALT_NAME[] = "_clang-format";
static const char SAMPLE_FILE_NAME[] = "test.cpp";
static const char 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

View File

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

View File

@@ -36,10 +36,13 @@ class ClangFormatIndenter final : public ClangFormatBaseIndenter
public:
ClangFormatIndenter(QTextDocument *doc);
Utils::optional<TextEditor::TabSettings> 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

View File

@@ -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

View File

@@ -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

View File

@@ -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<QAction *> DiagnosticView::customActions() const

View File

@@ -25,6 +25,8 @@
#include "clangtoolslogfilereader.h"
#include <cpptools/cppprojectfile.h>
#include <QDebug>
#include <QDir>
#include <QObject>
@@ -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;

View File

@@ -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()

View File

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

View File

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

View File

@@ -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);

View File

@@ -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;

View File

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

View File

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

View File

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

View File

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

View File

@@ -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

View File

@@ -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);

View File

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

View File

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

View File

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

View File

@@ -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<QTextBlock> &blocks,
const TabSettings &tabSettings,

View File

@@ -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)

View File

@@ -55,6 +55,7 @@
#include <QTemporaryDir>
#include <QTimer>
#include <chrono>
#include <iostream>
#include <thread>
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"));

View File

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

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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},

View File

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

View File

@@ -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;
};

View File

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

View File

@@ -32,6 +32,27 @@
namespace ClangBackEnd {
template<typename InputIterator1, typename InputIterator2, typename OutputIterator, typename Compare>
inline OutputIterator set_greedy_intersection(InputIterator1 first1,
InputIterator1 last1,
InputIterator2 first2,
InputIterator2 last2,
OutputIterator result,
Compare comp)
{
while (first1 != last1 && first2 != last2)
if (comp(*first1, *first2))
++first1;
else if (comp(*first2, *first1))
++first2;
else {
*result = *first1;
++first1;
++result;
}
return result;
}
class UsedMacroFilter
{
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,53 +138,58 @@ private:
}
};
UsedMacros filtertedMacros;
Utils::SmallStringVector filtertedMacros;
filtertedMacros.reserve(usedMacros.size());
std::set_intersection(usedMacros.begin(),
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());
std::set_intersection(indexedCompilerMacro.begin(),
set_greedy_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;
};

View File

@@ -39,6 +39,7 @@
#include <sqliteexception.h>
#include <chrono>
#include <iostream>
using namespace std::chrono_literals;
@@ -93,12 +94,24 @@ struct Data // because we have a cycle dependency
RefactoringDatabaseInitializer<Sqlite::Database> 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"));

View File

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

View File

@@ -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;

View File

@@ -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

View File

@@ -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 = ?",

View File

@@ -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());
}

View File

@@ -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;

View File

@@ -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]:

View File

@@ -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")})),

View File

@@ -51,12 +51,27 @@ public:
}
};
class ClangFormatExtendedIndenter : public ClangFormatIndenter
{
public:
ClangFormatExtendedIndenter(QTextDocument *doc)
: ClangFormatIndenter(doc)
{}
bool formatWhileTyping() const override
{
return true;
}
};
class ClangFormat : public ::testing::Test
{
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<QString> &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()",

View File

@@ -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<TypeParam> 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<TypeParam> builder{this->emptyProjectInfo};
@@ -521,7 +521,7 @@ TYPED_TEST(CommandLineBuilder, CompilerMacros)
"c++-header",
"-std=c++98",
"-nostdinc",
"-nostdlibinc",
"-nostdinc++",
"-DER=2",
"-DYI=1"));
}

View File

@@ -1157,10 +1157,9 @@ std::ostream &operator<<(std::ostream &out, const PchCreatorIncludes &includes)
std::ostream &operator<<(std::ostream &out, const PchTask &task)
{
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)

View File

@@ -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",

View File

@@ -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"}});

View File

@@ -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},

View File

@@ -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,8 +116,8 @@ 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)}},
merger.mergeTasks({{clone(systemTask1), clone(projectTask1)},
{clone(systemTask1), clone(projectTask2)}},
std::move(toolChainArguments));
}
@@ -112,11 +125,23 @@ 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)}},
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));
}
@@ -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

View File

@@ -241,12 +241,6 @@ protected:
Manager collectorManger{generatedFiles};
NiceMock<MockFunction<void(int, int)>> 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<MockSymbolsCollector&>(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",

View File

@@ -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