Merge remote-tracking branch 'origin/4.9'

Change-Id: I7bdb6a4658c5fca1a7e1dda5adbb5613dabc6d18
This commit is contained in:
Eike Ziller
2019-02-19 09:08:53 +01:00
50 changed files with 817 additions and 328 deletions

View File

@@ -48,10 +48,11 @@ public:
FilePathView outputPath = {}, FilePathView outputPath = {},
FilePathView includePchPath = {}) FilePathView includePchPath = {})
{ {
commandLine.reserve(128); commandLine.reserve(1024);
addCompiler(projectInfo.language); addCompiler(projectInfo.language);
addToolChainArguments(toolChainArguments); addToolChainArguments(toolChainArguments);
addExtraFlags();
addLanguage(projectInfo, sourceType); addLanguage(projectInfo, sourceType);
addLanguageVersion(projectInfo); addLanguageVersion(projectInfo);
addNoStdIncAndNoStdLibInc(projectInfo.language); addNoStdIncAndNoStdLibInc(projectInfo.language);
@@ -79,6 +80,8 @@ public:
commandLine.emplace_back(argument); commandLine.emplace_back(argument);
} }
void addExtraFlags() { commandLine.emplace_back("-DNOMINMAX"); }
static const char *language(const ProjectInfo &projectInfo, InputFileType sourceType) static const char *language(const ProjectInfo &projectInfo, InputFileType sourceType)
{ {
switch (projectInfo.language) { switch (projectInfo.language) {

View File

@@ -30,9 +30,9 @@ namespace V2 {
QDebug operator<<(QDebug debug, const FileContainer &container) QDebug operator<<(QDebug debug, const FileContainer &container)
{ {
debug.nospace() << "FileContainer(" debug.nospace() << "FileContainer(" << container.filePath << ", "
<< container.filePath << ", "
<< container.commandLineArguments << ", " << container.commandLineArguments << ", "
<< container.unsavedFileContent.hasContent() << ", "
<< container.documentRevision; << container.documentRevision;
debug.nospace() << ")"; debug.nospace() << ")";

View File

@@ -140,6 +140,13 @@ QTextCursor wordStartCursor(const QTextCursor &textCursor)
return cursor; return cursor;
} }
QString wordUnderCursor(const QTextCursor &cursor)
{
QTextCursor tc(cursor);
tc.select(QTextCursor::WordUnderCursor);
return tc.selectedText();
}
int utf8NthLineOffset(const QTextDocument *textDocument, const QByteArray &buffer, int line) int utf8NthLineOffset(const QTextDocument *textDocument, const QByteArray &buffer, int line)
{ {
if (textDocument->blockCount() < line) if (textDocument->blockCount() < line)

View File

@@ -53,6 +53,7 @@ QTCREATOR_UTILS_EXPORT QTextCursor selectAt(QTextCursor textCursor, uint line, u
QTCREATOR_UTILS_EXPORT QTextCursor flippedCursor(const QTextCursor &cursor); QTCREATOR_UTILS_EXPORT QTextCursor flippedCursor(const QTextCursor &cursor);
QTCREATOR_UTILS_EXPORT QTextCursor wordStartCursor(const QTextCursor &cursor); QTCREATOR_UTILS_EXPORT QTextCursor wordStartCursor(const QTextCursor &cursor);
QTCREATOR_UTILS_EXPORT QString wordUnderCursor(const QTextCursor &cursor);
QTCREATOR_UTILS_EXPORT int utf8NthLineOffset(const QTextDocument *textDocument, QTCREATOR_UTILS_EXPORT int utf8NthLineOffset(const QTextDocument *textDocument,
const QByteArray &buffer, const QByteArray &buffer,

View File

@@ -39,9 +39,6 @@ namespace ClangFormat {
static void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style, static void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style,
ReplacementsToKeep replacementsToKeep) ReplacementsToKeep replacementsToKeep)
{ {
if (replacementsToKeep == ReplacementsToKeep::All)
return;
style.MaxEmptyLinesToKeep = 2; style.MaxEmptyLinesToKeep = 2;
style.SortIncludes = false; style.SortIncludes = false;
style.SortUsingDeclarations = false; style.SortUsingDeclarations = false;
@@ -67,9 +64,10 @@ static llvm::StringRef clearExtraNewline(llvm::StringRef text)
} }
static clang::tooling::Replacements filteredReplacements( static clang::tooling::Replacements filteredReplacements(
const QByteArray &buffer,
const clang::tooling::Replacements &replacements, const clang::tooling::Replacements &replacements,
int offset, int utf8Offset,
int utf8LineLengthBeforeCursor, int utf8Length,
int extraEmptySpaceOffset, int extraEmptySpaceOffset,
ReplacementsToKeep replacementsToKeep) ReplacementsToKeep replacementsToKeep)
{ {
@@ -77,14 +75,13 @@ static clang::tooling::Replacements filteredReplacements(
for (const clang::tooling::Replacement &replacement : replacements) { for (const clang::tooling::Replacement &replacement : replacements) {
int replacementOffset = static_cast<int>(replacement.getOffset()); int replacementOffset = static_cast<int>(replacement.getOffset());
const bool replacementDoesNotMatchRestriction const bool replacementDoesNotMatchRestriction
= (replacementsToKeep == ReplacementsToKeep::OnlyIndent = replacementOffset >= utf8Offset + utf8Length
&& replacementOffset != offset - 1) || (replacementsToKeep == ReplacementsToKeep::OnlyIndent
|| (replacementsToKeep == ReplacementsToKeep::IndentAndBefore && (replacementOffset < utf8Offset - 1 || buffer.at(replacementOffset) != '\n'));
&& replacementOffset > offset + utf8LineLengthBeforeCursor - 1);
if (replacementDoesNotMatchRestriction) if (replacementDoesNotMatchRestriction)
continue; continue;
if (replacementOffset >= offset - 1) if (replacementOffset >= utf8Offset - 1)
replacementOffset += extraEmptySpaceOffset; replacementOffset += extraEmptySpaceOffset;
llvm::StringRef text = replacementsToKeep == ReplacementsToKeep::OnlyIndent llvm::StringRef text = replacementsToKeep == ReplacementsToKeep::OnlyIndent
@@ -151,13 +148,13 @@ static int previousEmptyLinesLength(const QTextBlock &currentBlock)
} }
static void modifyToIndentEmptyLines( static void modifyToIndentEmptyLines(
QByteArray &buffer, int offset, int &length, const QTextBlock &block, bool secondTry) QByteArray &buffer, int utf8Offset, const QTextBlock &block, bool secondTry)
{ {
const QString blockText = block.text(); const QString blockText = block.text();
int firstNonWhitespace = Utils::indexOf(blockText, int firstNonWhitespace = Utils::indexOf(blockText,
[](const QChar &ch) { return !ch.isSpace(); }); [](const QChar &ch) { return !ch.isSpace(); });
if (firstNonWhitespace > 0) if (firstNonWhitespace > 0)
offset += firstNonWhitespace; utf8Offset += firstNonWhitespace;
const bool closingParenBlock = firstNonWhitespace >= 0 const bool closingParenBlock = firstNonWhitespace >= 0
&& blockText.at(firstNonWhitespace) == ')'; && blockText.at(firstNonWhitespace) == ')';
@@ -176,12 +173,11 @@ static void modifyToIndentEmptyLines(
if (closingParenBlock || prevBlock.text().endsWith(',')) if (closingParenBlock || prevBlock.text().endsWith(','))
dummyText = "&& a"; dummyText = "&& a";
length += dummyText.length(); buffer.insert(utf8Offset, dummyText);
buffer.insert(offset, dummyText);
} }
if (secondTry) { if (secondTry) {
int nextLinePos = buffer.indexOf('\n', offset); int nextLinePos = buffer.indexOf('\n', utf8Offset);
if (nextLinePos < 0) if (nextLinePos < 0)
nextLinePos = buffer.size() - 1; nextLinePos = buffer.size() - 1;
@@ -190,7 +186,6 @@ static void modifyToIndentEmptyLines(
// unclosed parentheses. // unclosed parentheses.
// TODO: Does it help to add different endings depending on the context? // TODO: Does it help to add different endings depending on the context?
buffer.insert(nextLinePos, ')'); buffer.insert(nextLinePos, ')');
length += 1;
} }
} }
} }
@@ -251,13 +246,13 @@ static TextEditor::Replacements utf16Replacements(const QTextBlock &block,
return convertedReplacements; return convertedReplacements;
} }
static void applyReplacements(const QTextBlock &block, const TextEditor::Replacements &replacements) static void applyReplacements(QTextDocument *doc, const TextEditor::Replacements &replacements)
{ {
if (replacements.empty()) if (replacements.empty())
return; return;
int fullOffsetShift = 0; int fullOffsetShift = 0;
QTextCursor editCursor(block); QTextCursor editCursor(doc);
for (const TextEditor::Replacement &replacement : replacements) { for (const TextEditor::Replacement &replacement : replacements) {
editCursor.beginEditBlock(); editCursor.beginEditBlock();
editCursor.setPosition(replacement.offset + fullOffsetShift); editCursor.setPosition(replacement.offset + fullOffsetShift);
@@ -305,24 +300,12 @@ void ClangFormatBaseIndenter::indent(const QTextCursor &cursor,
int cursorPositionInEditor) int cursorPositionInEditor)
{ {
if (cursor.hasSelection()) { if (cursor.hasSelection()) {
// Calling currentBlock.next() might be unsafe because we change the document. indentBlocks(m_doc->findBlock(cursor.selectionStart()),
// Let's operate with block numbers instead. m_doc->findBlock(cursor.selectionEnd()),
const int startNumber = m_doc->findBlock(cursor.selectionStart()).blockNumber(); typedChar,
const int endNumber = m_doc->findBlock(cursor.selectionEnd()).blockNumber(); cursorPositionInEditor);
for (int currentBlockNumber = startNumber; currentBlockNumber <= endNumber;
++currentBlockNumber) {
const QTextBlock currentBlock = m_doc->findBlockByNumber(currentBlockNumber);
if (currentBlock.isValid()) {
const int blocksAmount = m_doc->blockCount();
indentBlock(currentBlock, typedChar, cursorPositionInEditor);
// Only blocks before current might be added/removed, so it's safe to modify the index.
if (blocksAmount != m_doc->blockCount())
currentBlockNumber += (m_doc->blockCount() - blocksAmount);
}
}
} else { } else {
indentBlock(cursor.block(), typedChar, cursorPositionInEditor); indentBlocks(cursor.block(), cursor.block(), typedChar, cursorPositionInEditor);
} }
} }
@@ -341,70 +324,55 @@ void ClangFormatBaseIndenter::reindent(const QTextCursor &cursor,
indent(cursor, QChar::Null, cursorPositionInEditor); indent(cursor, QChar::Null, cursorPositionInEditor);
} }
TextEditor::Replacements ClangFormatBaseIndenter::format(const QTextCursor &cursor, TextEditor::Replacements ClangFormatBaseIndenter::format(
int cursorPositionInEditor) const TextEditor::RangesInLines &rangesInLines)
{ {
int utf8Offset; if (rangesInLines.empty())
int utf8Length; return TextEditor::Replacements();
int utf8Offset = -1;
QTextBlock block; QTextBlock block;
const QByteArray buffer = m_doc->toPlainText().toUtf8(); const QByteArray buffer = m_doc->toPlainText().toUtf8();
if (cursor.hasSelection()) { std::vector<clang::tooling::Range> ranges;
block = m_doc->findBlock(cursor.selectionStart()); ranges.reserve(rangesInLines.size());
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 {
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(); for (auto &range : rangesInLines) {
const int utf8StartOffset = Utils::Text::utf8NthLineOffset(m_doc, buffer, range.startLine);
const QTextBlock end = m_doc->findBlockByNumber(range.endLine - 1);
int utf8RangeLength = end.text().toUtf8().size();
if (range.endLine > range.startLine) {
utf8RangeLength += Utils::Text::utf8NthLineOffset(m_doc, buffer, range.endLine)
- utf8StartOffset;
}
ranges.emplace_back(static_cast<unsigned int>(utf8StartOffset),
static_cast<unsigned int>(utf8RangeLength));
if (utf8Offset < 0) {
utf8Offset = utf8StartOffset;
block = m_doc->findBlockByNumber(range.startLine - 1);
}
} }
const TextEditor::Replacements toReplace = replacements(buffer, clang::format::FormatStyle style = styleForFile();
clang::format::FormattingAttemptStatus status;
const clang::tooling::Replacements clangReplacements
= reformat(style, buffer.data(), ranges, m_fileName.toString().toStdString(), &status);
const TextEditor::Replacements toReplace = utf16Replacements(block,
utf8Offset, utf8Offset,
utf8Length, buffer,
block, clangReplacements);
cursorPositionInEditor, applyReplacements(m_doc, toReplace);
ReplacementsToKeep::All,
QChar::Null);
applyReplacements(block, toReplace);
return toReplace; return toReplace;
} }
TextEditor::Replacements ClangFormatBaseIndenter::format(
const QTextCursor &cursor,
const TextEditor::TabSettings & /*tabSettings*/,
int cursorPositionInEditor)
{
return format(cursor, cursorPositionInEditor);
}
void 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;);
const TextEditor::Replacements toReplace = replacements(buffer,
utf8Offset,
0,
block,
cursorPositionInEditor,
ReplacementsToKeep::IndentAndBefore,
typedChar);
applyReplacements(block, toReplace);
}
static bool doNotIndentInContext(QTextDocument *doc, int pos) static bool doNotIndentInContext(QTextDocument *doc, int pos)
{ {
const QChar character = doc->characterAt(pos); const QChar character = doc->characterAt(pos);
const QTextBlock currentBlock = doc->findBlock(pos); const QTextBlock currentBlock = doc->findBlock(pos);
const QString text = currentBlock.text().left(pos - currentBlock.position()); const QString text = currentBlock.text().left(pos - currentBlock.position());
// NOTE: check if "<<" and ">>" always work correctly.
switch (character.toLatin1()) { switch (character.toLatin1()) {
default: default:
break; break;
@@ -419,33 +387,30 @@ static bool doNotIndentInContext(QTextDocument *doc, int pos)
if (pos > 0 && doc->characterAt(pos - 1) != ':') if (pos > 0 && doc->characterAt(pos - 1) != ':')
return true; return true;
break; break;
case '<':
case '>':
// "<<" and ">>" could be problematic
if (pos > 0 && doc->characterAt(pos - 1) == character)
return true;
break;
} }
return false; return false;
} }
void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block, void ClangFormatBaseIndenter::indentBlocks(const QTextBlock &startBlock,
const QTextBlock &endBlock,
const QChar &typedChar, const QChar &typedChar,
int cursorPositionInEditor) int cursorPositionInEditor)
{ {
QTextBlock currentBlock = block;
const int blockPosition = currentBlock.position();
trimFirstNonEmptyBlock(currentBlock);
if (typedChar != QChar::Null && cursorPositionInEditor > 0 if (typedChar != QChar::Null && cursorPositionInEditor > 0
&& m_doc->characterAt(cursorPositionInEditor - 1) == typedChar && m_doc->characterAt(cursorPositionInEditor - 1) == typedChar
&& doNotIndentInContext(m_doc, cursorPositionInEditor - 1)) { && doNotIndentInContext(m_doc, cursorPositionInEditor - 1)) {
return; return;
} }
const int startBlockPosition = startBlock.position();
trimFirstNonEmptyBlock(startBlock);
if (cursorPositionInEditor >= 0)
cursorPositionInEditor += startBlock.position() - startBlockPosition;
ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent;
if (formatWhileTyping() if (formatWhileTyping()
&& (cursorPositionInEditor == -1 || cursorPositionInEditor >= blockPosition) && (cursorPositionInEditor == -1 || cursorPositionInEditor >= startBlockPosition)
&& (typedChar == QChar::Null || typedChar == ';' || typedChar == '}')) { && (typedChar == QChar::Null || typedChar == ';' || typedChar == '}')) {
// Format before current position only in case the cursor is inside the indented block. // 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 // So if cursor position is less then the block position then the current line is before
@@ -453,26 +418,23 @@ void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
// cursorPositionInEditor == -1 means the consition matches automatically. // cursorPositionInEditor == -1 means the consition matches automatically.
// Format only before newline or complete statement not to break code. // Format only before newline or complete statement not to break code.
if (cursorPositionInEditor >= 0) replacementsToKeep = ReplacementsToKeep::IndentAndBefore;
cursorPositionInEditor += currentBlock.position() - blockPosition;
else
cursorPositionInEditor = currentBlock.position();
indentBeforeCursor(currentBlock, typedChar, cursorPositionInEditor);
return;
} }
const QByteArray buffer = m_doc->toPlainText().toUtf8(); const QByteArray buffer = m_doc->toPlainText().toUtf8();
const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1); const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc,
buffer,
startBlock.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return;); QTC_ASSERT(utf8Offset >= 0, return;);
const int utf8Length = selectedLines(m_doc, startBlock, endBlock).toUtf8().size();
applyReplacements(currentBlock, applyReplacements(m_doc,
replacements(buffer, replacements(buffer,
utf8Offset, utf8Offset,
0, utf8Length,
currentBlock, startBlock,
cursorPositionInEditor, endBlock,
ReplacementsToKeep::OnlyIndent, replacementsToKeep,
typedChar)); typedChar));
} }
@@ -481,12 +443,13 @@ void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
const TextEditor::TabSettings & /*tabSettings*/, const TextEditor::TabSettings & /*tabSettings*/,
int cursorPositionInEditor) int cursorPositionInEditor)
{ {
indentBlock(block, typedChar, cursorPositionInEditor); indentBlocks(block, block, typedChar, cursorPositionInEditor);
} }
int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, int cursorPositionInEditor) int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, int /*cursorPositionInEditor*/)
{ {
trimFirstNonEmptyBlock(block); trimFirstNonEmptyBlock(block);
const QByteArray buffer = m_doc->toPlainText().toUtf8(); const QByteArray buffer = m_doc->toPlainText().toUtf8();
const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1); const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return 0;); QTC_ASSERT(utf8Offset >= 0, return 0;);
@@ -495,7 +458,7 @@ int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, int cursorPositi
utf8Offset, utf8Offset,
0, 0,
block, block,
cursorPositionInEditor, block,
ReplacementsToKeep::OnlyIndent); ReplacementsToKeep::OnlyIndent);
if (toReplace.empty()) if (toReplace.empty())
@@ -535,11 +498,20 @@ void ClangFormatBaseIndenter::formatOrIndent(const QTextCursor &cursor,
const TextEditor::TabSettings & /*tabSettings*/, const TextEditor::TabSettings & /*tabSettings*/,
int cursorPositionInEditor) int cursorPositionInEditor)
{ {
if (formatCodeInsteadOfIndent()) if (formatCodeInsteadOfIndent()) {
format(cursor, cursorPositionInEditor); QTextBlock start;
else QTextBlock end;
if (cursor.hasSelection()) {
start = m_doc->findBlock(cursor.selectionStart());
end = m_doc->findBlock(cursor.selectionEnd());
} else {
start = end = cursor.block();
}
format({{start.blockNumber() + 1, end.blockNumber() + 1}});
} else {
indent(cursor, QChar::Null, cursorPositionInEditor); indent(cursor, QChar::Null, cursorPositionInEditor);
} }
}
clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const
{ {
@@ -574,44 +546,39 @@ static int formattingRangeStart(const QTextBlock &currentBlock,
TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer, TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer,
int utf8Offset, int utf8Offset,
int utf8Length, int utf8Length,
const QTextBlock &block, const QTextBlock &startBlock,
int cursorPositionInEditor, const QTextBlock &endBlock,
ReplacementsToKeep replacementsToKeep, ReplacementsToKeep replacementsToKeep,
const QChar &typedChar, const QChar &typedChar,
bool secondTry) const bool secondTry) const
{ {
QTC_ASSERT(replacementsToKeep != ReplacementsToKeep::All, return TextEditor::Replacements());
clang::format::FormatStyle style = styleForFile(); clang::format::FormatStyle style = styleForFile();
int originalOffsetUtf8 = utf8Offset; int originalOffsetUtf8 = utf8Offset;
int originalLengthUtf8 = utf8Length; int originalLengthUtf8 = utf8Length;
QByteArray originalBuffer = buffer; QByteArray originalBuffer = buffer;
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 extraEmptySpaceOffset = 0;
int rangeStart = 0; int rangeStart = 0;
if (replacementsToKeep != ReplacementsToKeep::All) {
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore)
rangeStart = formattingRangeStart(block, buffer, lastSaveRevision()); rangeStart = formattingRangeStart(startBlock, buffer, lastSaveRevision());
extraEmptySpaceOffset = previousEmptyLinesLength(block); int extraEmptySpaceOffset = previousEmptyLinesLength(startBlock);
utf8Offset -= extraEmptySpaceOffset; utf8Offset -= extraEmptySpaceOffset;
buffer.remove(utf8Offset, extraEmptySpaceOffset); buffer.remove(utf8Offset, extraEmptySpaceOffset);
adjustFormatStyleForLineBreak(style, replacementsToKeep); adjustFormatStyleForLineBreak(style, replacementsToKeep);
modifyToIndentEmptyLines(buffer, utf8Offset, utf8Length, block, secondTry); if (typedChar == QChar::Null && startBlock == endBlock) {
modifyToIndentEmptyLines(buffer, utf8Offset, startBlock, secondTry);
utf8Length = 0;
}
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) { if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) {
buffer.insert(utf8Offset - 1, " //"); buffer.insert(utf8Offset - 1, " //");
extraEmptySpaceOffset -= 3; extraEmptySpaceOffset -= 3;
utf8Offset += 3; utf8Offset += 3;
} }
}
if (replacementsToKeep != ReplacementsToKeep::IndentAndBefore || utf8Offset < rangeStart) if (replacementsToKeep != ReplacementsToKeep::IndentAndBefore || utf8Offset < rangeStart)
rangeStart = utf8Offset; rangeStart = utf8Offset;
@@ -630,9 +597,10 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer
clang::tooling::Replacements filtered; clang::tooling::Replacements filtered;
if (status.FormatComplete) { if (status.FormatComplete) {
filtered = filteredReplacements(clangReplacements, filtered = filteredReplacements(buffer,
clangReplacements,
utf8Offset, utf8Offset,
utf8LineLengthBeforeCursor, utf8Length,
extraEmptySpaceOffset, extraEmptySpaceOffset,
replacementsToKeep); replacementsToKeep);
} }
@@ -642,14 +610,14 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer
return replacements(originalBuffer, return replacements(originalBuffer,
originalOffsetUtf8, originalOffsetUtf8,
originalLengthUtf8, originalLengthUtf8,
block, startBlock,
cursorPositionInEditor, endBlock,
replacementsToKeep, replacementsToKeep,
typedChar, typedChar,
true); true);
} }
return utf16Replacements(block, originalOffsetUtf8, originalBuffer, filtered); return utf16Replacements(startBlock, originalOffsetUtf8, originalBuffer, filtered);
} }
} // namespace ClangFormat } // namespace ClangFormat

View File

@@ -53,9 +53,8 @@ public:
void formatOrIndent(const QTextCursor &cursor, void formatOrIndent(const QTextCursor &cursor,
const TextEditor::TabSettings &tabSettings, const TextEditor::TabSettings &tabSettings,
int cursorPositionInEditor = -1) override; int cursorPositionInEditor = -1) override;
TextEditor::Replacements format(const QTextCursor &cursor, TextEditor::Replacements format(
const TextEditor::TabSettings &tabSettings, const TextEditor::RangesInLines &rangesInLines = TextEditor::RangesInLines()) override;
int cursorPositionInEditor = -1) override;
void indentBlock(const QTextBlock &block, void indentBlock(const QTextBlock &block,
const QChar &typedChar, const QChar &typedChar,
@@ -75,18 +74,17 @@ protected:
virtual int lastSaveRevision() const { return 0; } virtual int lastSaveRevision() const { return 0; }
private: private:
TextEditor::Replacements format(const QTextCursor &cursor, int cursorPositionInEditor);
void indent(const QTextCursor &cursor, const QChar &typedChar, int cursorPositionInEditor); void indent(const QTextCursor &cursor, const QChar &typedChar, int cursorPositionInEditor);
void indentBlock(const QTextBlock &block, const QChar &typedChar, int cursorPositionInEditor); void indentBlocks(const QTextBlock &startBlock,
int indentFor(const QTextBlock &block, int cursorPositionInEditor); const QTextBlock &endBlock,
void indentBeforeCursor(const QTextBlock &block,
const QChar &typedChar, const QChar &typedChar,
int cursorPositionInEditor); int cursorPositionInEditor);
int indentFor(const QTextBlock &block, int cursorPositionInEditor);
TextEditor::Replacements replacements(QByteArray buffer, TextEditor::Replacements replacements(QByteArray buffer,
int utf8Offset, int utf8Offset,
int utf8Length, int utf8Length,
const QTextBlock &block, const QTextBlock &startBlock,
int cursorPositionInEditor, const QTextBlock &endBlock,
ReplacementsToKeep replacementsToKeep, ReplacementsToKeep replacementsToKeep,
const QChar &typedChar = QChar::Null, const QChar &typedChar = QChar::Null,
bool secondTry = false) const; bool secondTry = false) const;

View File

@@ -37,6 +37,9 @@
#include <cpptools/compileroptionsbuilder.h> #include <cpptools/compileroptionsbuilder.h>
#include <cpptools/projectpart.h> #include <cpptools/projectpart.h>
#include <cpptools/headerpathfilter.h> #include <cpptools/headerpathfilter.h>
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>
#include <projectexplorer/buildconfiguration.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
@@ -140,8 +143,10 @@ HeaderAndSources ProjectUpdater::headerAndSourcesFromProjectPart(
HeaderAndSources headerAndSources; HeaderAndSources headerAndSources;
headerAndSources.reserve(std::size_t(projectPart->files.size()) * 3 / 2); headerAndSources.reserve(std::size_t(projectPart->files.size()) * 3 / 2);
for (const CppTools::ProjectFile &projectFile : projectPart->files) for (const CppTools::ProjectFile &projectFile : projectPart->files) {
if (projectFile.active)
addToHeaderAndSources(headerAndSources, projectFile); addToHeaderAndSources(headerAndSources, projectFile);
}
std::sort(headerAndSources.sources.begin(), headerAndSources.sources.end()); std::sort(headerAndSources.sources.begin(), headerAndSources.sources.end());
std::sort(headerAndSources.headers.begin(), headerAndSources.headers.end()); std::sort(headerAndSources.headers.begin(), headerAndSources.headers.end());
@@ -231,6 +236,21 @@ ClangBackEnd::IncludeSearchPaths convertToIncludeSearchPaths(
return paths; return paths;
} }
QString projectDirectory(ProjectExplorer::Project *project)
{
if (project)
return project->rootProjectDirectory().toString();
return {};
}
QString buildDirectory(ProjectExplorer::Project *project)
{
if (project && project->activeTarget() && project->activeTarget()->activeBuildConfiguration())
return project->activeTarget()->activeBuildConfiguration()->buildDirectory().toString();
return {};
}
} // namespace } // namespace
ProjectUpdater::SystemAndProjectIncludeSearchPaths ProjectUpdater::createIncludeSearchPaths( ProjectUpdater::SystemAndProjectIncludeSearchPaths ProjectUpdater::createIncludeSearchPaths(
@@ -239,7 +259,9 @@ ProjectUpdater::SystemAndProjectIncludeSearchPaths ProjectUpdater::createInclude
CppTools::HeaderPathFilter filter(projectPart, CppTools::HeaderPathFilter filter(projectPart,
CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseTweakedHeaderPaths::Yes,
CLANG_VERSION, CLANG_VERSION,
CLANG_RESOURCE_DIR); CLANG_RESOURCE_DIR,
projectDirectory(projectPart.project),
buildDirectory(projectPart.project));
filter.process(); filter.process();
return {convertToIncludeSearchPaths(filter.systemHeaderPaths, filter.builtInHeaderPaths), return {convertToIncludeSearchPaths(filter.systemHeaderPaths, filter.builtInHeaderPaths),
@@ -277,6 +299,13 @@ ClangBackEnd::ProjectPartContainers ProjectUpdater::toProjectPartContainers(
std::vector<ClangBackEnd::ProjectPartContainer> projectPartContainers; std::vector<ClangBackEnd::ProjectPartContainer> projectPartContainers;
projectPartContainers.reserve(projectParts.size()); projectPartContainers.reserve(projectParts.size());
projectParts.erase(std::remove_if(projectParts.begin(),
projectParts.end(),
[](const CppTools::ProjectPart *projectPart) {
return !projectPart->selectedForBuilding;
}),
projectParts.end());
std::transform(projectParts.begin(), std::transform(projectParts.begin(),
projectParts.end(), projectParts.end(),
std::back_inserter(projectPartContainers), std::back_inserter(projectPartContainers),

View File

@@ -28,6 +28,7 @@
#include "pchmanagerprojectupdater.h" #include "pchmanagerprojectupdater.h"
#include <cpptools/cppmodelmanager.h> #include <cpptools/cppmodelmanager.h>
#include <projectexplorer/extracompiler.h>
#include <filecontainerv2.h> #include <filecontainerv2.h>
@@ -50,7 +51,8 @@ CLANGPCHMANAGER_EXPORT std::vector<CppTools::ProjectPart*> createProjectParts(Pr
} }
template<typename ProjectUpdaterType> template<typename ProjectUpdaterType>
class QtCreatorProjectUpdater : public ProjectUpdaterType class QtCreatorProjectUpdater : public ProjectUpdaterType,
public ProjectExplorer::ExtraCompilerFactoryObserver
{ {
public: public:
template <typename ClientType> template <typename ClientType>
@@ -90,6 +92,15 @@ public:
ProjectUpdaterType::removeGeneratedFiles({ClangBackEnd::FilePath{filePath}}); ProjectUpdaterType::removeGeneratedFiles({ClangBackEnd::FilePath{filePath}});
} }
protected:
void newExtraCompiler(const ProjectExplorer::Project *,
const Utils::FileName &,
const Utils::FileNameList &targets) override
{
for (const Utils::FileName &target : targets)
abstractEditorUpdated(target.toString(), {});
}
private: private:
void connectToCppModelManager() void connectToCppModelManager()
{ {

View File

@@ -89,6 +89,10 @@ bool FixitsRefactoringFile::apply()
= CppTools::CppCodeStyleSettings::currentProjectTabSettings(); = CppTools::CppCodeStyleSettings::currentProjectTabSettings();
// Apply changes // Apply changes
std::unique_ptr<TextEditor::Indenter> indenter;
QString lastFilename;
ReplacementOperations operationsForFile;
for (int i=0; i < m_replacementOperations.size(); ++i) { for (int i=0; i < m_replacementOperations.size(); ++i) {
ReplacementOperation &op = *m_replacementOperations[i]; ReplacementOperation &op = *m_replacementOperations[i];
if (op.apply) { if (op.apply) {
@@ -103,15 +107,19 @@ bool FixitsRefactoringFile::apply()
// Apply // Apply
QTextDocument *doc = document(op.fileName); QTextDocument *doc = document(op.fileName);
std::unique_ptr<TextEditor::Indenter> indenter(factory->createIndenter(doc)); if (lastFilename != op.fileName) {
if (indenter)
format(*indenter, doc, operationsForFile, i);
operationsForFile.clear();
indenter = std::unique_ptr<TextEditor::Indenter>(factory->createIndenter(doc));
indenter->setFileName(Utils::FileName::fromString(op.fileName)); indenter->setFileName(Utils::FileName::fromString(op.fileName));
}
QTextCursor cursor(doc); QTextCursor cursor(doc);
cursor.setPosition(op.pos); cursor.setPosition(op.pos);
cursor.setPosition(op.pos + op.length, QTextCursor::KeepAnchor); cursor.setPosition(op.pos + op.length, QTextCursor::KeepAnchor);
cursor.insertText(op.text); cursor.insertText(op.text);
operationsForFile.push_back(&op);
tryToFormat(*indenter, tabSettings, doc, op, i);
} }
} }
@@ -130,28 +138,29 @@ bool FixitsRefactoringFile::apply()
return true; return true;
} }
void FixitsRefactoringFile::tryToFormat(TextEditor::Indenter &indenter, void FixitsRefactoringFile::format(TextEditor::Indenter &indenter,
const TextEditor::TabSettings &tabSettings,
QTextDocument *doc, QTextDocument *doc,
const ReplacementOperation &op, const ReplacementOperations &operationsForFile,
int currentIndex) int firstOperationIndex)
{ {
QTextCursor cursor(doc); if (operationsForFile.isEmpty())
cursor.beginEditBlock(); return;
cursor.setPosition(op.pos);
cursor.movePosition(QTextCursor::Right, TextEditor::RangesInLines ranges;
QTextCursor::KeepAnchor, for (int i = 0; i < operationsForFile.size(); ++i) {
op.text.length()); const ReplacementOperation &op = *operationsForFile.at(i);
const Replacements replacements = indenter.format(cursor, tabSettings); const int start = doc->findBlock(op.pos).blockNumber() + 1;
cursor.endEditBlock(); const int end = doc->findBlock(op.pos + op.length).blockNumber() + 1;
ranges.push_back({start, end});
}
const Replacements replacements = indenter.format(ranges);
if (replacements.empty()) if (replacements.empty())
return; return;
if (hasIntersection(op.fileName, replacements, currentIndex + 1)) shiftAffectedReplacements(operationsForFile.front()->fileName,
doc->undo(&cursor); replacements,
else firstOperationIndex + 1);
shiftAffectedReplacements(op.fileName, replacements, currentIndex + 1);
} }
QTextDocument *FixitsRefactoringFile::document(const QString &filePath) const QTextDocument *FixitsRefactoringFile::document(const QString &filePath) const

View File

@@ -67,11 +67,10 @@ private:
QTextDocument *document(const QString &filePath) const; QTextDocument *document(const QString &filePath) const;
void shiftAffectedReplacements(const ReplacementOperation &op, int startIndex); void shiftAffectedReplacements(const ReplacementOperation &op, int startIndex);
void tryToFormat(TextEditor::Indenter &indenter, void format(TextEditor::Indenter &indenter,
const TextEditor::TabSettings &tabSettings,
QTextDocument *doc, QTextDocument *doc,
const ReplacementOperation &op, const ReplacementOperations &operationsForFile,
int currentIndex); int firstOperationIndex);
void shiftAffectedReplacements(const QString &fileName, void shiftAffectedReplacements(const QString &fileName,
const TextEditor::Replacements &replacements, const TextEditor::Replacements &replacements,
int startIndex); int startIndex);

View File

@@ -300,8 +300,8 @@ ClangTidyClazyTool::ClangTidyClazyTool()
}); });
connect(m_applyFixitsButton, &QToolButton::clicked, [this]() { connect(m_applyFixitsButton, &QToolButton::clicked, [this]() {
QVector<DiagnosticItem *> diagnosticItems; QVector<DiagnosticItem *> diagnosticItems;
m_diagnosticModel->rootItem()->forChildrenAtLevel(2, [&](TreeItem *item){ m_diagnosticModel->forItemsAtLevel<2>([&](DiagnosticItem *item){
diagnosticItems += static_cast<DiagnosticItem *>(item); diagnosticItems += item;
}); });
ApplyFixIts(diagnosticItems).apply(m_diagnosticModel); ApplyFixIts(diagnosticItems).apply(m_diagnosticModel);

View File

@@ -81,7 +81,7 @@ private:
}; };
ClangToolsDiagnosticModel::ClangToolsDiagnosticModel(QObject *parent) ClangToolsDiagnosticModel::ClangToolsDiagnosticModel(QObject *parent)
: Utils::TreeModel<>(parent) : ClangToolsDiagnosticModelBase(parent)
, m_filesWatcher(std::make_unique<QFileSystemWatcher>()) , m_filesWatcher(std::make_unique<QFileSystemWatcher>())
{ {
setHeader({tr("Diagnostic")}); setHeader({tr("Diagnostic")});
@@ -146,7 +146,7 @@ void ClangToolsDiagnosticModel::clear()
m_filePathToItem.clear(); m_filePathToItem.clear();
m_diagnostics.clear(); m_diagnostics.clear();
clearAndSetupCache(); clearAndSetupCache();
Utils::TreeModel<>::clear(); ClangToolsDiagnosticModelBase::clear();
} }
void ClangToolsDiagnosticModel::updateItems(const DiagnosticItem *changedItem) void ClangToolsDiagnosticModel::updateItems(const DiagnosticItem *changedItem)
@@ -174,10 +174,9 @@ void ClangToolsDiagnosticModel::clearAndSetupCache()
void ClangToolsDiagnosticModel::onFileChanged(const QString &path) void ClangToolsDiagnosticModel::onFileChanged(const QString &path)
{ {
rootItem()->forChildrenAtLevel(2, [&](Utils::TreeItem *item){ forItemsAtLevel<2>([&](DiagnosticItem *item){
auto diagnosticItem = static_cast<DiagnosticItem *>(item); if (item->diagnostic().location.filePath == path)
if (diagnosticItem->diagnostic().location.filePath == path) item->setFixItStatus(FixitStatus::Invalidated);
diagnosticItem->setFixItStatus(FixitStatus::Invalidated);
}); });
removeWatchedPath(path); removeWatchedPath(path);
} }
@@ -623,9 +622,10 @@ bool DiagnosticFilterModel::filterAcceptsRow(int sourceRow,
// DiagnosticItem // DiagnosticItem
Utils::TreeItem *parentItem = model->itemForIndex(sourceParent); Utils::TreeItem *parentItem = model->itemForIndex(sourceParent);
if (auto filePathItem = dynamic_cast<FilePathItem *>(parentItem)) { QTC_ASSERT(parentItem, return true);
auto diagnosticItem = dynamic_cast<DiagnosticItem *>(filePathItem->childAt(sourceRow)); if (parentItem->level() == 1) {
QTC_ASSERT(diagnosticItem, return false); auto filePathItem = static_cast<FilePathItem *>(parentItem);
auto diagnosticItem = static_cast<DiagnosticItem *>(filePathItem->childAt(sourceRow));
// Is the diagnostic explicitly suppressed? // Is the diagnostic explicitly suppressed?
const Diagnostic &diag = diagnosticItem->diagnostic(); const Diagnostic &diag = diagnosticItem->diagnostic();
@@ -651,11 +651,12 @@ bool DiagnosticFilterModel::lessThan(const QModelIndex &l, const QModelIndex &r)
{ {
auto model = static_cast<ClangToolsDiagnosticModel *>(sourceModel()); auto model = static_cast<ClangToolsDiagnosticModel *>(sourceModel());
Utils::TreeItem *itemLeft = model->itemForIndex(l); Utils::TreeItem *itemLeft = model->itemForIndex(l);
const bool isComparingDiagnostics = !dynamic_cast<FilePathItem *>(itemLeft); QTC_ASSERT(itemLeft, return QSortFilterProxyModel::lessThan(l, r));
const bool isComparingDiagnostics = itemLeft->level() > 1;
if (sortColumn() == Debugger::DetailedErrorView::DiagnosticColumn && isComparingDiagnostics) { if (sortColumn() == Debugger::DetailedErrorView::DiagnosticColumn && isComparingDiagnostics) {
bool result = false; bool result = false;
if (dynamic_cast<DiagnosticItem *>(itemLeft)) { if (itemLeft->level() == 2) {
using Debugger::DiagnosticLocation; using Debugger::DiagnosticLocation;
const int role = Debugger::DetailedErrorView::LocationRole; const int role = Debugger::DetailedErrorView::LocationRole;
@@ -669,8 +670,11 @@ bool DiagnosticFilterModel::lessThan(const QModelIndex &l, const QModelIndex &r)
result = std::tie(leftLoc.line, leftLoc.column, leftText) result = std::tie(leftLoc.line, leftLoc.column, leftText)
< std::tie(rightLoc.line, rightLoc.column, rightText); < std::tie(rightLoc.line, rightLoc.column, rightText);
} else if (auto left = dynamic_cast<ExplainingStepItem *>(itemLeft)) { } else if (itemLeft->level() == 3) {
const auto right = dynamic_cast<ExplainingStepItem *>(model->itemForIndex(r)); Utils::TreeItem *itemRight = model->itemForIndex(r);
QTC_ASSERT(itemRight, QSortFilterProxyModel::lessThan(l, r));
const auto left = static_cast<ExplainingStepItem *>(itemLeft);
const auto right = static_cast<ExplainingStepItem *>(itemRight);
result = left->index() < right->index(); result = left->index() < right->index();
} else { } else {
QTC_CHECK(false && "Unexpected item"); QTC_CHECK(false && "Unexpected item");

View File

@@ -100,7 +100,11 @@ private:
ClangToolsDiagnosticModel *m_parentModel = nullptr; ClangToolsDiagnosticModel *m_parentModel = nullptr;
}; };
class ClangToolsDiagnosticModel : public Utils::TreeModel<> class ExplainingStepItem;
using ClangToolsDiagnosticModelBase
= Utils::TreeModel<Utils::TreeItem, FilePathItem, DiagnosticItem, ExplainingStepItem>;
class ClangToolsDiagnosticModel : public ClangToolsDiagnosticModelBase
{ {
Q_OBJECT Q_OBJECT

View File

@@ -446,47 +446,40 @@ TextEditor::TabSettings CppEditorDocument::tabSettings() const
return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings()); return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings());
} }
static int formatRange(QTextDocument *doc,
TextEditor::Indenter *indenter,
std::pair<int, int> editedRange,
const TextEditor::TabSettings &tabSettings)
{
QTextCursor cursor(doc);
cursor.setPosition(editedRange.first);
cursor.setPosition(editedRange.second, QTextCursor::KeepAnchor);
const int oldBlockCount = doc->blockCount();
indenter->format(cursor, tabSettings);
return doc->blockCount() - oldBlockCount;
}
bool CppEditorDocument::save(QString *errorString, const QString &fileName, bool autoSave) bool CppEditorDocument::save(QString *errorString, const QString &fileName, bool autoSave)
{ {
if (indenter()->formatOnSave()) { if (indenter()->formatOnSave() && !autoSave) {
QTextCursor cursor(document());
cursor.joinPreviousEditBlock();
auto *layout = qobject_cast<TextEditor::TextDocumentLayout *>(document()->documentLayout()); auto *layout = qobject_cast<TextEditor::TextDocumentLayout *>(document()->documentLayout());
const int documentRevision = layout->lastSaveRevision; const int documentRevision = layout->lastSaveRevision;
std::pair<int, int> editedRange; TextEditor::RangesInLines editedRanges;
TextEditor::RangeInLines lastRange{-1, -1};
for (int i = 0; i < document()->blockCount(); ++i) { for (int i = 0; i < document()->blockCount(); ++i) {
const QTextBlock block = document()->findBlockByNumber(i); const QTextBlock block = document()->findBlockByNumber(i);
if (block.revision() == documentRevision) { if (block.revision() == documentRevision) {
if (editedRange.first != -1) if (lastRange.startLine != -1)
i += formatRange(document(), indenter(), editedRange, tabSettings()); editedRanges.push_back(lastRange);
editedRange = std::make_pair(-1, -1); lastRange.startLine = lastRange.endLine = -1;
continue; continue;
} }
// block.revision() != documentRevision // block.revision() != documentRevision
if (editedRange.first == -1) if (lastRange.startLine == -1)
editedRange.first = block.position(); lastRange.startLine = block.blockNumber() + 1;
editedRange.second = block.position() + block.length(); lastRange.endLine = block.blockNumber() + 1;
} }
if (editedRange.first != -1)
formatRange(document(), indenter(), editedRange, tabSettings()); if (lastRange.startLine != -1)
editedRanges.push_back(lastRange);
if (!editedRanges.empty()) {
QTextCursor cursor(document());
cursor.joinPreviousEditBlock();
indenter()->format(editedRanges);
cursor.endEditBlock(); cursor.endEditBlock();
} }
}
return TextEditor::TextDocument::save(errorString, fileName, autoSave); return TextEditor::TextDocument::save(errorString, fileName, autoSave);
} }

View File

@@ -48,6 +48,11 @@ void HeaderPathFilter::process()
tweakHeaderPaths(); tweakHeaderPaths();
} }
bool HeaderPathFilter::isProjectHeaderPath(const QString &path) const
{
return path.startsWith(projectDirectory) || path.startsWith(buildDirectory);
}
void HeaderPathFilter::filterHeaderPath(const ProjectExplorer::HeaderPath &headerPath) void HeaderPathFilter::filterHeaderPath(const ProjectExplorer::HeaderPath &headerPath)
{ {
if (headerPath.path.isEmpty()) if (headerPath.path.isEmpty())
@@ -62,7 +67,10 @@ void HeaderPathFilter::filterHeaderPath(const ProjectExplorer::HeaderPath &heade
systemHeaderPaths.push_back(headerPath); systemHeaderPaths.push_back(headerPath);
break; break;
case HeaderPathType::User: case HeaderPathType::User:
if (isProjectHeaderPath(headerPath.path))
userHeaderPaths.push_back(headerPath); userHeaderPaths.push_back(headerPath);
else
systemHeaderPaths.push_back(headerPath);
break; break;
} }
} }
@@ -133,4 +141,13 @@ void HeaderPathFilter::tweakHeaderPaths()
} }
} }
QString HeaderPathFilter::ensurePathWithSlashEnding(const QString &path)
{
QString pathWithSlashEnding = path;
if (!pathWithSlashEnding.isEmpty() && *pathWithSlashEnding.rbegin() != '/')
pathWithSlashEnding.push_back('/');
return pathWithSlashEnding;
}
} // namespace CppTools } // namespace CppTools

View File

@@ -34,11 +34,15 @@ class CPPTOOLS_EXPORT HeaderPathFilter
public: public:
HeaderPathFilter(const ProjectPart &projectPart, HeaderPathFilter(const ProjectPart &projectPart,
UseTweakedHeaderPaths useTweakedHeaderPaths = UseTweakedHeaderPaths::Yes, UseTweakedHeaderPaths useTweakedHeaderPaths = UseTweakedHeaderPaths::Yes,
const QString &clangVersion = QString(), const QString &clangVersion = {},
const QString &clangResourceDirectory = QString()) const QString &clangResourceDirectory = {},
const QString &projectDirectory = {},
const QString &buildDirectory = {})
: projectPart{projectPart} : projectPart{projectPart}
, clangVersion{clangVersion} , clangVersion{clangVersion}
, clangResourceDirectory{clangResourceDirectory} , clangResourceDirectory{clangResourceDirectory}
, projectDirectory(ensurePathWithSlashEnding(projectDirectory))
, buildDirectory(ensurePathWithSlashEnding(buildDirectory))
, useTweakedHeaderPaths{useTweakedHeaderPaths} , useTweakedHeaderPaths{useTweakedHeaderPaths}
{} {}
@@ -49,6 +53,10 @@ private:
void tweakHeaderPaths(); void tweakHeaderPaths();
bool isProjectHeaderPath(const QString &path) const;
static QString ensurePathWithSlashEnding(const QString &path);
public: public:
ProjectExplorer::HeaderPaths builtInHeaderPaths; ProjectExplorer::HeaderPaths builtInHeaderPaths;
ProjectExplorer::HeaderPaths systemHeaderPaths; ProjectExplorer::HeaderPaths systemHeaderPaths;
@@ -56,6 +64,8 @@ public:
const ProjectPart &projectPart; const ProjectPart &projectPart;
const QString clangVersion; const QString clangVersion;
const QString clangResourceDirectory; const QString clangResourceDirectory;
const QString projectDirectory;
const QString buildDirectory;
const UseTweakedHeaderPaths useTweakedHeaderPaths; const UseTweakedHeaderPaths useTweakedHeaderPaths;
}; };

View File

@@ -1451,8 +1451,9 @@ void DebuggerPluginPrivate::updatePresetState()
if (startupRunConfigName.isEmpty() && startupProject) if (startupRunConfigName.isEmpty() && startupProject)
startupRunConfigName = startupProject->displayName(); startupRunConfigName = startupProject->displayName();
// Restrict width, otherwise Creator gets too wide, see QTCREATORBUG-21885
const QString startToolTip = const QString startToolTip =
canRun ? tr("Start debugging of \"%1\"").arg(startupRunConfigName) : whyNot; canRun ? tr("Start debugging of startup project") : whyNot;
m_startAction.setToolTip(startToolTip); m_startAction.setToolTip(startToolTip);
m_startAction.setText(canRun ? startToolTip : tr("Start Debugging")); m_startAction.setText(canRun ? startToolTip : tr("Start Debugging"));

View File

@@ -52,7 +52,7 @@ namespace ProjectExplorer {
Q_GLOBAL_STATIC(QThreadPool, s_extraCompilerThreadPool); Q_GLOBAL_STATIC(QThreadPool, s_extraCompilerThreadPool);
Q_GLOBAL_STATIC(QList<ExtraCompilerFactory *>, factories); Q_GLOBAL_STATIC(QList<ExtraCompilerFactory *>, factories);
Q_GLOBAL_STATIC(QVector<ExtraCompilerFactoryObserver *>, observers);
class ExtraCompilerPrivate class ExtraCompilerPrivate
{ {
public: public:
@@ -310,7 +310,8 @@ void ExtraCompiler::setContent(const Utils::FileName &file, const QByteArray &co
} }
} }
ExtraCompilerFactory::ExtraCompilerFactory(QObject *parent) : QObject(parent) ExtraCompilerFactory::ExtraCompilerFactory(QObject *parent)
: QObject(parent)
{ {
factories->append(this); factories->append(this);
} }
@@ -320,6 +321,14 @@ ExtraCompilerFactory::~ExtraCompilerFactory()
factories->removeAll(this); factories->removeAll(this);
} }
void ExtraCompilerFactory::annouceCreation(const Project *project,
const Utils::FileName &source,
const Utils::FileNameList &targets)
{
for (ExtraCompilerFactoryObserver *observer : *observers)
observer->newExtraCompiler(project, source, targets);
}
QList<ExtraCompilerFactory *> ExtraCompilerFactory::extraCompilerFactories() QList<ExtraCompilerFactory *> ExtraCompilerFactory::extraCompilerFactories()
{ {
return *factories(); return *factories();
@@ -455,4 +464,14 @@ void ProcessExtraCompiler::cleanUp()
setCompileTime(QDateTime::currentDateTime()); setCompileTime(QDateTime::currentDateTime());
} }
ExtraCompilerFactoryObserver::ExtraCompilerFactoryObserver()
{
observers->push_back(this);
}
ExtraCompilerFactoryObserver::~ExtraCompilerFactoryObserver()
{
observers->removeOne(this);
}
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -137,6 +137,20 @@ private:
QFutureWatcher<FileNameToContentsHash> *m_watcher = nullptr; QFutureWatcher<FileNameToContentsHash> *m_watcher = nullptr;
}; };
class PROJECTEXPLORER_EXPORT ExtraCompilerFactoryObserver
{
friend class ExtraCompilerFactory;
protected:
ExtraCompilerFactoryObserver();
~ExtraCompilerFactoryObserver();
virtual void newExtraCompiler(const Project *project,
const Utils::FileName &source,
const Utils::FileNameList &targets)
= 0;
};
class PROJECTEXPLORER_EXPORT ExtraCompilerFactory : public QObject class PROJECTEXPLORER_EXPORT ExtraCompilerFactory : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -147,8 +161,14 @@ public:
virtual FileType sourceType() const = 0; virtual FileType sourceType() const = 0;
virtual QString sourceTag() const = 0; virtual QString sourceTag() const = 0;
virtual ExtraCompiler *create(const Project *project, const Utils::FileName &source, virtual ExtraCompiler *create(const Project *project,
const Utils::FileNameList &targets) = 0; const Utils::FileName &source,
const Utils::FileNameList &targets)
= 0;
void annouceCreation(const Project *project,
const Utils::FileName &source,
const Utils::FileNameList &targets);
static QList<ExtraCompilerFactory *> extraCompilerFactories(); static QList<ExtraCompilerFactory *> extraCompilerFactories();
}; };

View File

@@ -1143,14 +1143,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
mprojectContextMenu->addAction(cmd, Constants::G_PROJECT_FILES); mprojectContextMenu->addAction(cmd, Constants::G_PROJECT_FILES);
msubProjectContextMenu->addAction(cmd, Constants::G_PROJECT_FILES); msubProjectContextMenu->addAction(cmd, Constants::G_PROJECT_FILES);
// unload project again, in right position
dd->m_unloadActionContextMenu = new Utils::ParameterAction(tr("Close Project"), tr("Close Project \"%1\""),
Utils::ParameterAction::EnabledWithParameter, this);
cmd = ActionManager::registerAction(dd->m_unloadActionContextMenu, Constants::UNLOADCM);
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDescription(dd->m_unloadActionContextMenu->text());
mprojectContextMenu->addAction(cmd, Constants::G_PROJECT_LAST);
dd->m_closeProjectFilesActionContextMenu = new Utils::ParameterAction( dd->m_closeProjectFilesActionContextMenu = new Utils::ParameterAction(
tr("Close All Files"), tr("Close All Files in Project \"%1\""), tr("Close All Files"), tr("Close All Files in Project \"%1\""),
Utils::ParameterAction::EnabledWithParameter, this); Utils::ParameterAction::EnabledWithParameter, this);
@@ -1160,6 +1152,14 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
cmd->setDescription(dd->m_closeProjectFilesActionContextMenu->text()); cmd->setDescription(dd->m_closeProjectFilesActionContextMenu->text());
mprojectContextMenu->addAction(cmd, Constants::G_PROJECT_LAST); mprojectContextMenu->addAction(cmd, Constants::G_PROJECT_LAST);
// unload project again, in right position
dd->m_unloadActionContextMenu = new Utils::ParameterAction(tr("Close Project"), tr("Close Project \"%1\""),
Utils::ParameterAction::EnabledWithParameter, this);
cmd = ActionManager::registerAction(dd->m_unloadActionContextMenu, Constants::UNLOADCM);
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDescription(dd->m_unloadActionContextMenu->text());
mprojectContextMenu->addAction(cmd, Constants::G_PROJECT_LAST);
// file properties action // file properties action
dd->m_filePropertiesAction = new QAction(tr("Properties..."), this); dd->m_filePropertiesAction = new QAction(tr("Properties..."), this);
cmd = ActionManager::registerAction(dd->m_filePropertiesAction, Constants::FILEPROPERTIES, cmd = ActionManager::registerAction(dd->m_filePropertiesAction, Constants::FILEPROPERTIES,
@@ -1854,18 +1854,15 @@ void ProjectExplorerPluginPrivate::setStartupProject(Project *project)
bool ProjectExplorerPluginPrivate::closeAllFilesInProject(const Project *project) bool ProjectExplorerPluginPrivate::closeAllFilesInProject(const Project *project)
{ {
QTC_ASSERT(project, return false); QTC_ASSERT(project, return false);
const Utils::FileNameList filesInProject = project->files(Project::AllFiles);
QList<IDocument *> openFiles = DocumentModel::openedDocuments(); QList<IDocument *> openFiles = DocumentModel::openedDocuments();
Utils::erase(openFiles, [filesInProject](const IDocument *doc) { Utils::erase(openFiles, [project](const IDocument *doc) {
return !filesInProject.contains(doc->filePath()); return !project->isKnownFile(doc->filePath());
}); });
for (const Project * const otherProject : SessionManager::projects()) { for (const Project * const otherProject : SessionManager::projects()) {
if (otherProject == project) if (otherProject == project)
continue; continue;
const Utils::FileNameList filesInOtherProject Utils::erase(openFiles, [otherProject](const IDocument *doc) {
= otherProject->files(Project::AllFiles); return otherProject->isKnownFile(doc->filePath());
Utils::erase(openFiles, [filesInOtherProject](const IDocument *doc) {
return filesInOtherProject.contains(doc->filePath());
}); });
} }
return EditorManager::closeDocuments(openFiles); return EditorManager::closeDocuments(openFiles);

View File

@@ -149,6 +149,8 @@ ExtraCompiler *QScxmlcGeneratorFactory::create(
const Project *project, const Utils::FileName &source, const Project *project, const Utils::FileName &source,
const Utils::FileNameList &targets) const Utils::FileNameList &targets)
{ {
annouceCreation(project, source, targets);
return new QScxmlcGenerator(project, source, targets, this); return new QScxmlcGenerator(project, source, targets, this);
} }

View File

@@ -100,6 +100,8 @@ ExtraCompiler *UicGeneratorFactory::create(const Project *project,
const Utils::FileName &source, const Utils::FileName &source,
const Utils::FileNameList &targets) const Utils::FileNameList &targets)
{ {
annouceCreation(project, source, targets);
return new UicGenerator(project, source, targets, this); return new UicGenerator(project, source, targets, this);
} }

View File

@@ -203,7 +203,9 @@ void AbstractRemoteLinuxDeployService::handleDeviceSetupDone(bool success)
} else { } else {
connect(d->connection, &SshConnection::connected, connect(d->connection, &SshConnection::connected,
this, &AbstractRemoteLinuxDeployService::handleConnected); this, &AbstractRemoteLinuxDeployService::handleConnected);
emit progressMessage(tr("Connecting to device...")); emit progressMessage(tr("Connecting to device '%1' (%2)")
.arg(deviceConfiguration()->displayName())
.arg(deviceConfiguration()->sshParameters().host()));
if (d->connection->state() == SshConnection::Unconnected) if (d->connection->state() == SshConnection::Unconnected)
d->connection->connectToHost(); d->connection->connectToHost();
} }

View File

@@ -58,6 +58,15 @@ public:
using Replacements = std::vector<Replacement>; using Replacements = std::vector<Replacement>;
class RangeInLines
{
public:
int startLine;
int endLine;
};
using RangesInLines = std::vector<RangeInLines>;
class Indenter class Indenter
{ {
public: public:
@@ -91,9 +100,7 @@ public:
} }
// By default just calls indent with default settings. // By default just calls indent with default settings.
virtual Replacements format(const QTextCursor &/*cursor*/, virtual Replacements format(const RangesInLines & /*rangesInLines*/ = RangesInLines())
const TabSettings &/*tabSettings*/,
int /*cursorPositionInEditor*/ = -1)
{ {
return Replacements(); return Replacements();
} }

View File

@@ -8085,11 +8085,20 @@ void BaseTextEditor::setContextHelp(const HelpItem &item)
void TextEditorWidget::contextHelpItem(const IContext::HelpCallback &callback) void TextEditorWidget::contextHelpItem(const IContext::HelpCallback &callback)
{ {
const QString fallbackWordUnderCursor = Text::wordUnderCursor(textCursor());
if (d->m_contextHelpItem.isEmpty() && !d->m_hoverHandlers.isEmpty()) { if (d->m_contextHelpItem.isEmpty() && !d->m_hoverHandlers.isEmpty()) {
d->m_hoverHandlers.first()->contextHelpId(this, d->m_hoverHandlers.first()->contextHelpId(this,
Text::wordStartCursor(textCursor()).position(), Text::wordStartCursor(textCursor()).position(),
callback); [fallbackWordUnderCursor, callback](const HelpItem &item) {
if (item.isEmpty())
callback(fallbackWordUnderCursor);
else
callback(item);
});
} else { } else {
if (d->m_contextHelpItem.isEmpty())
callback(fallbackWordUnderCursor);
else
callback(d->m_contextHelpItem); callback(d->m_contextHelpItem);
} }
} }

View File

@@ -291,6 +291,9 @@ void TextMark::addToToolTipLayout(QGridLayout *target) const
// Right column: action icons/button // Right column: action icons/button
if (!m_actions.isEmpty()) { if (!m_actions.isEmpty()) {
auto actionsLayout = new QHBoxLayout; auto actionsLayout = new QHBoxLayout;
QMargins margins = actionsLayout->contentsMargins();
margins.setLeft(margins.left() + 5);
actionsLayout->setContentsMargins(margins);
for (QAction *action : m_actions) { for (QAction *action : m_actions) {
QTC_ASSERT(!action->icon().isNull(), continue); QTC_ASSERT(!action->icon().isNull(), continue);
auto button = new QToolButton; auto button = new QToolButton;

View File

@@ -119,7 +119,7 @@ IntroductionWidget::IntroductionWidget(QWidget *parent)
"<tr><td>Edit:</td><td>Work with code and navigate your project.</td></tr>" "<tr><td>Edit:</td><td>Work with code and navigate your project.</td></tr>"
"<tr><td>Design:</td><td>Work with UI designs for Qt Widgets or Qt Quick.</td></tr>" "<tr><td>Design:</td><td>Work with UI designs for Qt Widgets or Qt Quick.</td></tr>"
"<tr><td>Debug:</td><td>Analyze your application with a debugger or other " "<tr><td>Debug:</td><td>Analyze your application with a debugger or other "
"analyzer.</td></tr>" "analyzers.</td></tr>"
"<tr><td>Projects:</td><td>Manage project settings.</td></tr>" "<tr><td>Projects:</td><td>Manage project settings.</td></tr>"
"<tr><td>Help:</td><td>Browse the help database.</td></tr>" "<tr><td>Help:</td><td>Browse the help database.</td></tr>"
"</table></p>")}, "</table></p>")},

View File

@@ -246,8 +246,13 @@ struct Data // because we have a cycle dependency
modifiedTimeChecker, modifiedTimeChecker,
buildDependencyCollector, buildDependencyCollector,
database}; database};
ClangBackEnd::PchTaskGenerator pchTaskGenerator{buildDependencyProvider, pchTaskMerger}; ClangBackEnd::PchTaskGenerator pchTaskGenerator{buildDependencyProvider,
PchManagerServer clangPchManagerServer{includeWatcher, pchTaskGenerator, projectParts, generatedFiles}; pchTaskMerger,
progressCounter};
PchManagerServer clangPchManagerServer{includeWatcher,
pchTaskGenerator,
projectParts,
generatedFiles};
TaskScheduler systemTaskScheduler{pchCreatorManager, TaskScheduler systemTaskScheduler{pchCreatorManager,
pchTaskQueue, pchTaskQueue,
progressCounter, progressCounter,

View File

@@ -27,6 +27,7 @@
#include <clang/Tooling/Tooling.h> #include <clang/Tooling/Tooling.h>
#include <clang/Basic/DiagnosticOptions.h>
#include <clang/Frontend/CompilerInstance.h> #include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/FrontendActions.h> #include <clang/Frontend/FrontendActions.h>
#include <clang/Lex/PreprocessorOptions.h> #include <clang/Lex/PreprocessorOptions.h>
@@ -44,6 +45,9 @@ public:
bool BeginInvocation(clang::CompilerInstance &compilerInstance) override bool BeginInvocation(clang::CompilerInstance &compilerInstance) override
{ {
compilerInstance.getPreprocessorOpts().DisablePCHValidation = true; compilerInstance.getPreprocessorOpts().DisablePCHValidation = true;
compilerInstance.getPreprocessorOpts().AllowPCHWithCompilerErrors = true;
compilerInstance.getLangOpts().DelayedTemplateParsing = true;
compilerInstance.getDiagnosticOpts().ErrorLimit = 0;
std::unique_ptr<llvm::MemoryBuffer> Input = llvm::MemoryBuffer::getMemBuffer(m_fileContent); std::unique_ptr<llvm::MemoryBuffer> Input = llvm::MemoryBuffer::getMemBuffer(m_fileContent);
compilerInstance.getPreprocessorOpts().addRemappedFile(m_filePath, Input.release()); compilerInstance.getPreprocessorOpts().addRemappedFile(m_filePath, Input.release());

View File

@@ -76,8 +76,6 @@ bool PchCreator::generatePch(NativeFilePathView path, Utils::SmallStringView con
{ {
clang::tooling::ClangTool tool = m_clangTool.createOutputTool(); clang::tooling::ClangTool tool = m_clangTool.createOutputTool();
NativeFilePath headerFilePath{m_environment.pchBuildDirectory().toStdString(), "dummy.h"};
auto action = std::make_unique<GeneratePCHActionFactory>(llvm::StringRef{path.data(), auto action = std::make_unique<GeneratePCHActionFactory>(llvm::StringRef{path.data(),
path.size()}, path.size()},
llvm::StringRef{content.data(), llvm::StringRef{content.data(),
@@ -138,6 +136,16 @@ const ProjectPartPch &PchCreator::projectPartPch()
void PchCreator::setUnsavedFiles(const V2::FileContainers &fileContainers) void PchCreator::setUnsavedFiles(const V2::FileContainers &fileContainers)
{ {
m_generatedFilePathIds.clear();
m_generatedFilePathIds.reserve(fileContainers.size());
std::transform(fileContainers.begin(),
fileContainers.end(),
std::back_inserter(m_generatedFilePathIds),
[&](const V2::FileContainer &fileContainer) {
return m_filePathCache.filePathId(fileContainer.filePath);
});
std::sort(m_generatedFilePathIds.begin(), m_generatedFilePathIds.end());
m_clangTool.addUnsavedFiles(fileContainers); m_clangTool.addUnsavedFiles(fileContainers);
} }
@@ -159,7 +167,14 @@ void PchCreator::clear()
void PchCreator::doInMainThreadAfterFinished() void PchCreator::doInMainThreadAfterFinished()
{ {
m_clangPathwatcher.updateIdPaths({{m_projectPartPch.projectPartId, m_allInclues}}); FilePathIds existingIncludes;
existingIncludes.reserve(m_allInclues.size());
std::set_difference(m_allInclues.begin(),
m_allInclues.end(),
m_generatedFilePathIds.begin(),
m_generatedFilePathIds.end(),
std::back_inserter(existingIncludes));
m_clangPathwatcher.updateIdPaths({{m_projectPartPch.projectPartId, existingIncludes}});
m_pchManagerClient.precompiledHeadersUpdated(ProjectPartPchs{m_projectPartPch}); m_pchManagerClient.precompiledHeadersUpdated(ProjectPartPchs{m_projectPartPch});
} }

View File

@@ -98,6 +98,7 @@ private:
ProjectPartPch m_projectPartPch; ProjectPartPch m_projectPartPch;
FilePathCaching m_filePathCache; FilePathCaching m_filePathCache;
FilePathIds m_allInclues; FilePathIds m_allInclues;
FilePathIds m_generatedFilePathIds;
Environment &m_environment; Environment &m_environment;
PchManagerClientInterface &m_pchManagerClient; PchManagerClientInterface &m_pchManagerClient;
ClangPathWatcherInterface &m_clangPathwatcher; ClangPathWatcherInterface &m_clangPathwatcher;

View File

@@ -27,9 +27,10 @@
#include "builddependenciesproviderinterface.h" #include "builddependenciesproviderinterface.h"
#include "pchtasksmergerinterface.h" #include "pchtasksmergerinterface.h"
#include "usedmacrofilter.h" #include "usedmacrofilter.h"
#include <progresscounter.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
namespace ClangBackEnd { namespace ClangBackEnd {
@@ -40,6 +41,8 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts,
PchTaskSets pchTaskSets; PchTaskSets pchTaskSets;
pchTaskSets.reserve(projectParts.size()); pchTaskSets.reserve(projectParts.size());
m_progressCounter.addTotal(static_cast<int>(projectParts.size()));
for (auto &projectPart : projectParts) { for (auto &projectPart : projectParts) {
BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart); BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart);
UsedMacroFilter filter{buildDependency.includes, UsedMacroFilter filter{buildDependency.includes,
@@ -68,6 +71,7 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts,
projectPart.language, projectPart.language,
projectPart.languageVersion, projectPart.languageVersion,
projectPart.languageExtension}); projectPart.languageExtension});
m_progressCounter.addProgress(1);
} }
m_pchTasksMergerInterface.mergeTasks(std::move(pchTaskSets), std::move(toolChainArguments)); m_pchTasksMergerInterface.mergeTasks(std::move(pchTaskSets), std::move(toolChainArguments));

View File

@@ -35,14 +35,18 @@ namespace ClangBackEnd {
class PchTasksMergerInterface; class PchTasksMergerInterface;
class BuildDependenciesProviderInterface; class BuildDependenciesProviderInterface;
class ProgressCounter;
class PchTaskGenerator : public PchTaskGeneratorInterface class PchTaskGenerator : public PchTaskGeneratorInterface
{ {
public: public:
PchTaskGenerator(BuildDependenciesProviderInterface &buildDependenciesProvider, PchTaskGenerator(BuildDependenciesProviderInterface &buildDependenciesProvider,
PchTasksMergerInterface &pchTasksMergerInterface) PchTasksMergerInterface &pchTasksMergerInterface,
ProgressCounter &progressCounter)
: m_buildDependenciesProvider(buildDependenciesProvider) : m_buildDependenciesProvider(buildDependenciesProvider)
, m_pchTasksMergerInterface(pchTasksMergerInterface) , m_pchTasksMergerInterface(pchTasksMergerInterface)
, m_progressCounter(progressCounter)
{} {}
void addProjectParts(ProjectPartContainers &&projectParts, void addProjectParts(ProjectPartContainers &&projectParts,
@@ -52,7 +56,7 @@ public:
private: private:
BuildDependenciesProviderInterface &m_buildDependenciesProvider; BuildDependenciesProviderInterface &m_buildDependenciesProvider;
PchTasksMergerInterface &m_pchTasksMergerInterface; PchTasksMergerInterface &m_pchTasksMergerInterface;
ProgressCounter &m_progressCounter;
}; };
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -71,7 +71,7 @@ bool PchTasksMerger::hasDuplicates(const CompilerMacros &compilerMacros)
return first.key == second.key; return first.key == second.key;
}); });
return found == compilerMacros.end(); return found != compilerMacros.end();
} }
IncludeSearchPaths mergeIncludeSearchPaths(IncludeSearchPaths &&first, IncludeSearchPaths &&second) IncludeSearchPaths mergeIncludeSearchPaths(IncludeSearchPaths &&first, IncludeSearchPaths &&second)
@@ -89,7 +89,8 @@ bool PchTasksMerger::mergePchTasks(PchTask &firstTask, PchTask &secondTask)
CompilerMacros macros = mergeMacros(firstTask.compilerMacros, secondTask.compilerMacros); CompilerMacros macros = mergeMacros(firstTask.compilerMacros, secondTask.compilerMacros);
secondTask.isMerged = hasDuplicates(macros); secondTask.isMerged = !hasDuplicates(macros);
if (secondTask.isMerged && firstTask.language == secondTask.language) { if (secondTask.isMerged && firstTask.language == secondTask.language) {
firstTask.projectPartIds = merge(std::move(firstTask.projectPartIds), firstTask.projectPartIds = merge(std::move(firstTask.projectPartIds),

View File

@@ -93,8 +93,8 @@ public:
return std::tie(first.key, first.value) < std::tie(second.key, second.value); return std::tie(first.key, first.value) < std::tie(second.key, second.value);
}); });
systemCompilerMacros = filtercompilerMacros(indexedCompilerMacro, systemUsedMacros); systemCompilerMacros = filterCompilerMacros(indexedCompilerMacro, systemUsedMacros);
projectCompilerMacros = filtercompilerMacros(indexedCompilerMacro, projectUsedMacros); projectCompilerMacros = filterCompilerMacros(indexedCompilerMacro, projectUsedMacros);
} }
private: private:
@@ -150,10 +150,13 @@ private:
std::sort(filtertedMacros.begin(), filtertedMacros.end()); std::sort(filtertedMacros.begin(), filtertedMacros.end());
auto newEnd = std::unique(filtertedMacros.begin(), filtertedMacros.end());
filtertedMacros.erase(newEnd, filtertedMacros.end());
return filtertedMacros; return filtertedMacros;
} }
static CompilerMacros filtercompilerMacros(const CompilerMacros &indexedCompilerMacro, static CompilerMacros filterCompilerMacros(const CompilerMacros &indexedCompilerMacro,
const Utils::SmallStringVector &usedMacros) const Utils::SmallStringVector &usedMacros)
{ {
CompilerMacros filtertedCompilerMacros; CompilerMacros filtertedCompilerMacros;

View File

@@ -27,6 +27,7 @@
#include <clang/Frontend/CompilerInstance.h> #include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/FrontendActions.h> #include <clang/Frontend/FrontendActions.h>
#include <clang/Lex/PreprocessorOptions.h>
namespace ClangBackEnd { namespace ClangBackEnd {
@@ -100,6 +101,7 @@ newFrontendActionFactory(Factory *consumerFactory,
bool BeginInvocation(clang::CompilerInstance &compilerInstance) override bool BeginInvocation(clang::CompilerInstance &compilerInstance) override
{ {
compilerInstance.getLangOpts().DelayedTemplateParsing = false; compilerInstance.getLangOpts().DelayedTemplateParsing = false;
compilerInstance.getPreprocessorOpts().AllowPCHWithCompilerErrors = true;
return clang::ASTFrontendAction::BeginInvocation(compilerInstance); return clang::ASTFrontendAction::BeginInvocation(compilerInstance);
} }

View File

@@ -0,0 +1,37 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <utils/fileutils.h>
namespace ProjectExplorer {
class BuildConfiguration
{
public:
Utils::FileName buildDirectory() const { return {}; }
}; // namespace Target
} // namespace ProjectExplorer

View File

@@ -25,6 +25,8 @@
#pragma once #pragma once
#include "target.h"
#include <projectexplorer/kit.h> #include <projectexplorer/kit.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
@@ -35,13 +37,10 @@ class Project : public QObject {
public: public:
Project() = default; Project() = default;
Utils::FileName projectDirectory() const { Utils::FileName projectDirectory() const { return {}; }
return Utils::FileName();
}
Utils::FileName rootProjectDirectory() const { Utils::FileName rootProjectDirectory() const { return {}; }
return Utils::FileName();
} Target *activeTarget() const { return {}; }
}; };
} // namespace ProjectExplorer
}

View File

@@ -0,0 +1,39 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "buildconfiguration.h"
#include <utils/fileutils.h>
namespace ProjectExplorer {
class Target
{
public:
BuildConfiguration *activeBuildConfiguration() const { return {}; }
};
} // namespace ProjectExplorer

View File

@@ -408,6 +408,60 @@ TEST_F(ClangFormat, IndentIfBodyAndFormatBeforeIt)
"}")); "}"));
} }
TEST_F(ClangFormat, DoNotFormatAfterTheFirstColon)
{
insertLines({"{",
" Qt:",
"}"});
extendedIndenter.indentBlock(doc.findBlockByNumber(1), ':', TextEditor::TabSettings(), 9);
ASSERT_THAT(documentLines(), ElementsAre("{",
" Qt:",
"}"));
}
TEST_F(ClangFormat, OnlyIndentIncompleteStatementOnElectricalCharacter)
{
insertLines({"{bar();",
"foo()",
"}"});
extendedIndenter.indentBlock(doc.findBlockByNumber(1), '(', TextEditor::TabSettings(), 12);
ASSERT_THAT(documentLines(), ElementsAre("{bar();",
" foo()",
"}"));
}
TEST_F(ClangFormat, IndentAndFormatCompleteStatementOnSemicolon)
{
insertLines({"{bar();",
"foo();",
"}"});
extendedIndenter.indentBlock(doc.findBlockByNumber(1), ';', TextEditor::TabSettings(), 14);
ASSERT_THAT(documentLines(), ElementsAre("{",
" bar();",
" foo();",
"}"));
}
TEST_F(ClangFormat, IndentAndFormatCompleteStatementOnClosingScope)
{
insertLines({"{bar();",
"foo();",
"}"});
extendedIndenter.indentBlock(doc.findBlockByNumber(1), '}', TextEditor::TabSettings(), 16);
ASSERT_THAT(documentLines(), ElementsAre("{",
" bar();",
" foo();",
"}"));
}
TEST_F(ClangFormat, FormatBasicFile) TEST_F(ClangFormat, FormatBasicFile)
{ {
insertLines({"int main()", insertLines({"int main()",
@@ -415,7 +469,7 @@ TEST_F(ClangFormat, FormatBasicFile)
"int a;", "int a;",
"}"}); "}"});
indenter.format(cursor, TextEditor::TabSettings()); indenter.format(cursor);
ASSERT_THAT(documentLines(), ElementsAre("int main()", ASSERT_THAT(documentLines(), ElementsAre("int main()",
"{", "{",
@@ -430,7 +484,7 @@ TEST_F(ClangFormat, FormatEmptyLine)
"", "",
"}"}); "}"});
indenter.format(cursor, TextEditor::TabSettings()); indenter.format(cursor);
ASSERT_THAT(documentLines(), ElementsAre("int main() {}")); ASSERT_THAT(documentLines(), ElementsAre("int main() {}"));
} }
@@ -441,7 +495,7 @@ TEST_F(ClangFormat, FormatLambda)
"", "",
"});"}); "});"});
indenter.format(cursor, TextEditor::TabSettings()); indenter.format(cursor);
ASSERT_THAT(documentLines(), ElementsAre("int b = foo([]() {", ASSERT_THAT(documentLines(), ElementsAre("int b = foo([]() {",
"", "",
@@ -454,7 +508,7 @@ TEST_F(ClangFormat, FormatInitializerListInArguments)
"args,", "args,",
"{1, 2});"}); "{1, 2});"});
indenter.format(cursor, TextEditor::TabSettings()); indenter.format(cursor);
ASSERT_THAT(documentLines(), ElementsAre("foo(arg1, args, {1, 2});")); ASSERT_THAT(documentLines(), ElementsAre("foo(arg1, args, {1, 2});"));
} }
@@ -466,7 +520,7 @@ TEST_F(ClangFormat, FormatFunctionArgumentLambdaWithScope)
"", "",
"});"}); "});"});
indenter.format(cursor, TextEditor::TabSettings()); indenter.format(cursor);
ASSERT_THAT(documentLines(), ASSERT_THAT(documentLines(),
ElementsAre("foo([]() {", ElementsAre("foo([]() {",
@@ -481,7 +535,7 @@ TEST_F(ClangFormat, FormatScopeAsFunctionArgument)
"", "",
"});"}); "});"});
indenter.format(cursor, TextEditor::TabSettings()); indenter.format(cursor);
ASSERT_THAT(documentLines(), ASSERT_THAT(documentLines(),
ElementsAre("foo({", ElementsAre("foo({",
@@ -494,7 +548,7 @@ TEST_F(ClangFormat, FormatStructuredBinding)
insertLines({"auto [a,", insertLines({"auto [a,",
"b] = c;"}); "b] = c;"});
indenter.format(cursor, TextEditor::TabSettings()); indenter.format(cursor);
ASSERT_THAT(documentLines(), ElementsAre("auto [a, b] = c;")); ASSERT_THAT(documentLines(), ElementsAre("auto [a, b] = c;"));
} }
@@ -504,7 +558,7 @@ TEST_F(ClangFormat, FormatStringLiteralContinuation)
insertLines({"foo(bar, \"foo\"", insertLines({"foo(bar, \"foo\"",
"\"bar\");"}); "\"bar\");"});
indenter.format(cursor, TextEditor::TabSettings()); indenter.format(cursor);
ASSERT_THAT(documentLines(), ElementsAre("foo(bar,", ASSERT_THAT(documentLines(), ElementsAre("foo(bar,",
" \"foo\"", " \"foo\"",
@@ -517,7 +571,7 @@ TEST_F(ClangFormat, FormatTemplateparameters)
"B,", "B,",
"C>"}); "C>"});
indenter.format(cursor, TextEditor::TabSettings()); indenter.format(cursor);
ASSERT_THAT(documentLines(), ElementsAre("using Alias = Template<A, B, C>")); ASSERT_THAT(documentLines(), ElementsAre("using Alias = Template<A, B, C>"));
} }

View File

@@ -139,6 +139,7 @@ TYPED_TEST(CommandLineBuilder, CHeader)
ASSERT_THAT(builder.commandLine, ASSERT_THAT(builder.commandLine,
ElementsAre("clang", ElementsAre("clang",
"-DNOMINMAX",
"-x", "-x",
"c-header", "c-header",
"-std=c11", "-std=c11",
@@ -154,7 +155,7 @@ TYPED_TEST(CommandLineBuilder, CSource)
Builder<TypeParam> builder{this->emptyProjectInfo, {}, InputFileType::Source, "/source/file.c"}; Builder<TypeParam> builder{this->emptyProjectInfo, {}, InputFileType::Source, "/source/file.c"};
ASSERT_THAT(builder.commandLine, ASSERT_THAT(builder.commandLine,
ElementsAre("clang", "-x", "c", "-std=c11", "-nostdinc", "/source/file.c")); ElementsAre("clang", "-DNOMINMAX", "-x", "c", "-std=c11", "-nostdinc", "/source/file.c"));
} }
TYPED_TEST(CommandLineBuilder, ObjectiveCHeader) TYPED_TEST(CommandLineBuilder, ObjectiveCHeader)
@@ -167,6 +168,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCHeader)
ASSERT_THAT(builder.commandLine, ASSERT_THAT(builder.commandLine,
ElementsAre("clang", ElementsAre("clang",
"-DNOMINMAX",
"-x", "-x",
"objective-c-header", "objective-c-header",
"-std=c11", "-std=c11",
@@ -184,6 +186,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCSource)
ASSERT_THAT(builder.commandLine, ASSERT_THAT(builder.commandLine,
ElementsAre("clang", ElementsAre("clang",
"-DNOMINMAX",
"-x", "-x",
"objective-c", "objective-c",
"-std=c11", "-std=c11",
@@ -200,6 +203,7 @@ TYPED_TEST(CommandLineBuilder, CppHeader)
ASSERT_THAT(builder.commandLine, ASSERT_THAT(builder.commandLine,
ElementsAre("clang++", ElementsAre("clang++",
"-DNOMINMAX",
"-x", "-x",
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",
@@ -215,9 +219,15 @@ TYPED_TEST(CommandLineBuilder, CppSource)
Builder<TypeParam> builder{this->emptyProjectInfo, {}, InputFileType::Source, "/source/file.cpp"}; Builder<TypeParam> builder{this->emptyProjectInfo, {}, InputFileType::Source, "/source/file.cpp"};
ASSERT_THAT( ASSERT_THAT(builder.commandLine,
builder.commandLine, ElementsAre("clang++",
ElementsAre("clang++", "-x", "c++", "-std=c++98", "-nostdinc", "-nostdinc++", "/source/file.cpp")); "-DNOMINMAX",
"-x",
"c++",
"-std=c++98",
"-nostdinc",
"-nostdinc++",
"/source/file.cpp"));
} }
TYPED_TEST(CommandLineBuilder, ObjectiveCppHeader) TYPED_TEST(CommandLineBuilder, ObjectiveCppHeader)
@@ -230,6 +240,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCppHeader)
ASSERT_THAT(builder.commandLine, ASSERT_THAT(builder.commandLine,
ElementsAre("clang++", ElementsAre("clang++",
"-DNOMINMAX",
"-x", "-x",
"objective-c++-header", "objective-c++-header",
"-std=c++98", "-std=c++98",
@@ -248,6 +259,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCppSource)
ASSERT_THAT(builder.commandLine, ASSERT_THAT(builder.commandLine,
ElementsAre("clang++", ElementsAre("clang++",
"-DNOMINMAX",
"-x", "-x",
"objective-c++", "objective-c++",
"-std=c++98", "-std=c++98",
@@ -480,6 +492,7 @@ TYPED_TEST(CommandLineBuilder, IncludesOrder)
ASSERT_THAT(builder.commandLine, ASSERT_THAT(builder.commandLine,
ElementsAre("clang++", ElementsAre("clang++",
"-DNOMINMAX",
"-x", "-x",
"c++-header", "c++-header",
"-std=c++11", "-std=c++11",
@@ -505,7 +518,13 @@ TYPED_TEST(CommandLineBuilder, EmptySourceFile)
Builder<TypeParam> builder{this->emptyProjectInfo, {}, {}}; Builder<TypeParam> builder{this->emptyProjectInfo, {}, {}};
ASSERT_THAT(builder.commandLine, ASSERT_THAT(builder.commandLine,
ElementsAre("clang++", "-x", "c++-header", "-std=c++98", "-nostdinc", "-nostdinc++")); ElementsAre("clang++",
"-DNOMINMAX",
"-x",
"c++-header",
"-std=c++98",
"-nostdinc",
"-nostdinc++"));
} }
TYPED_TEST(CommandLineBuilder, SourceFile) TYPED_TEST(CommandLineBuilder, SourceFile)
@@ -514,6 +533,7 @@ TYPED_TEST(CommandLineBuilder, SourceFile)
ASSERT_THAT(builder.commandLine, ASSERT_THAT(builder.commandLine,
ElementsAre("clang++", ElementsAre("clang++",
"-DNOMINMAX",
"-x", "-x",
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",
@@ -529,6 +549,7 @@ TYPED_TEST(CommandLineBuilder, EmptyOutputFile)
ASSERT_THAT(builder.commandLine, ASSERT_THAT(builder.commandLine,
ElementsAre("clang++", ElementsAre("clang++",
"-DNOMINMAX",
"-x", "-x",
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",
@@ -547,6 +568,7 @@ TYPED_TEST(CommandLineBuilder, OutputFile)
ASSERT_THAT(builder.commandLine, ASSERT_THAT(builder.commandLine,
ElementsAre("clang++", ElementsAre("clang++",
"-DNOMINMAX",
"-x", "-x",
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",
@@ -568,6 +590,7 @@ TYPED_TEST(CommandLineBuilder, IncludePchPath)
ASSERT_THAT(builder.commandLine, ASSERT_THAT(builder.commandLine,
ElementsAre("clang++", ElementsAre("clang++",
"-DNOMINMAX",
"-x", "-x",
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",
@@ -590,6 +613,7 @@ TYPED_TEST(CommandLineBuilder, CompilerMacros)
ASSERT_THAT(builder.commandLine, ASSERT_THAT(builder.commandLine,
ElementsAre("clang++", ElementsAre("clang++",
"-DNOMINMAX",
"-x", "-x",
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",

View File

@@ -0,0 +1,115 @@
# .clang-format for Qt Creator
#
# This is for clang-format >= 5.0.
#
# The configuration below follows the Qt Creator Coding Rules [1] as closely as
# possible. For documentation of the options, see [2].
#
# Use ../../tests/manual/clang-format-for-qtc/test.cpp for documenting problems
# or testing changes.
#
# [1] https://doc-snapshots.qt.io/qtcreator-extending/coding-style.html
# [2] https://clang.llvm.org/docs/ClangFormatStyleOptions.html
#
---
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: DontAlign
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: true
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBinaryOperators: All
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 100
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- forever # avoids { wrapped to next line
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeCategories:
- Regex: '^<Q.*'
Priority: 200
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
# Do not add QT_BEGIN_NAMESPACE/QT_END_NAMESPACE as this will indent lines in between.
MacroBlockBegin: ""
MacroBlockEnd: ""
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 150
PenaltyBreakBeforeFirstCallParameter: 300
PenaltyBreakComment: 500
PenaltyBreakFirstLessLess: 400
PenaltyBreakString: 600
PenaltyExcessCharacter: 50
PenaltyReturnTypeOnItsOwnLine: 300
PointerAlignment: Right
ReflowComments: false
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: true
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: Never

View File

@@ -43,7 +43,7 @@ MATCHER_P(HasBuiltIn,
MATCHER_P(HasSystem, MATCHER_P(HasSystem,
path, path,
std::string(negation ? "isn't " : "is ") std::string(negation ? "isn't " : "is ")
+ PrintToString(HeaderPath{QString::fromUtf8(path), HeaderPathType::BuiltIn})) + PrintToString(HeaderPath{QString::fromUtf8(path), HeaderPathType::System}))
{ {
return arg.path == path && arg.type == HeaderPathType::System; return arg.path == path && arg.type == HeaderPathType::System;
} }
@@ -51,7 +51,7 @@ MATCHER_P(HasSystem,
MATCHER_P(HasFramework, MATCHER_P(HasFramework,
path, path,
std::string(negation ? "isn't " : "is ") std::string(negation ? "isn't " : "is ")
+ PrintToString(HeaderPath{QString::fromUtf8(path), HeaderPathType::BuiltIn})) + PrintToString(HeaderPath{QString::fromUtf8(path), HeaderPathType::Framework}))
{ {
return arg.path == path && arg.type == HeaderPathType::Framework; return arg.path == path && arg.type == HeaderPathType::Framework;
} }
@@ -59,7 +59,7 @@ MATCHER_P(HasFramework,
MATCHER_P(HasUser, MATCHER_P(HasUser,
path, path,
std::string(negation ? "isn't " : "is ") std::string(negation ? "isn't " : "is ")
+ PrintToString(HeaderPath{QString::fromUtf8(path), HeaderPathType::BuiltIn})) + PrintToString(HeaderPath{QString::fromUtf8(path), HeaderPathType::User}))
{ {
return arg.path == path && arg.type == HeaderPathType::User; return arg.path == path && arg.type == HeaderPathType::User;
} }
@@ -73,42 +73,60 @@ protected:
HeaderPath{"/builtin_path", HeaderPathType::BuiltIn}, HeaderPath{"/builtin_path", HeaderPathType::BuiltIn},
HeaderPath{"/system_path", HeaderPathType::System}, HeaderPath{"/system_path", HeaderPathType::System},
HeaderPath{"/framework_path", HeaderPathType::Framework}, HeaderPath{"/framework_path", HeaderPathType::Framework},
HeaderPath{"/user_path", HeaderPathType::User}}; HeaderPath{"/outside_project_user_path", HeaderPathType::User},
HeaderPath{"/build/user_path", HeaderPathType::User},
HeaderPath{"/buildb/user_path", HeaderPathType::User},
HeaderPath{"/projectb/user_path", HeaderPathType::User},
HeaderPath{"/project/user_path", HeaderPathType::User}};
projectPart.headerPaths = headerPaths; projectPart.headerPaths = headerPaths;
} }
protected: protected:
CppTools::ProjectPart projectPart; CppTools::ProjectPart projectPart;
CppTools::HeaderPathFilter filter{projectPart, CppTools::UseTweakedHeaderPaths::No}; CppTools::HeaderPathFilter filter{
projectPart, CppTools::UseTweakedHeaderPaths::No, {}, {}, "/project", "/build"};
}; };
TEST_F(HeaderPathFilter, BuiltIn) TEST_F(HeaderPathFilter, BuiltIn)
{ {
filter.process(); filter.process();
ASSERT_THAT(filter.builtInHeaderPaths, Contains(HasBuiltIn("/builtin_path"))); ASSERT_THAT(filter.builtInHeaderPaths, ElementsAre(HasBuiltIn("/builtin_path")));
} }
TEST_F(HeaderPathFilter, System) TEST_F(HeaderPathFilter, System)
{ {
filter.process(); filter.process();
ASSERT_THAT(filter.systemHeaderPaths, Contains(HasSystem("/system_path"))); ASSERT_THAT(filter.systemHeaderPaths,
ElementsAre(HasSystem("/system_path"),
HasFramework("/framework_path"),
HasUser("/outside_project_user_path"),
HasUser("/buildb/user_path"),
HasUser("/projectb/user_path")));
} }
TEST_F(HeaderPathFilter, User) TEST_F(HeaderPathFilter, User)
{ {
filter.process(); filter.process();
ASSERT_THAT(filter.userHeaderPaths, Contains(HasUser("/user_path"))); ASSERT_THAT(filter.userHeaderPaths,
ElementsAre(HasUser("/build/user_path"), HasUser("/project/user_path")));
} }
TEST_F(HeaderPathFilter, Framework) TEST_F(HeaderPathFilter, NoProjectPathSet)
{ {
CppTools::HeaderPathFilter filter{projectPart, CppTools::UseTweakedHeaderPaths::No};
filter.process(); filter.process();
ASSERT_THAT(filter.systemHeaderPaths, Contains(HasFramework("/framework_path"))); ASSERT_THAT(filter.userHeaderPaths,
ElementsAre(HasUser("/outside_project_user_path"),
HasUser("/build/user_path"),
HasUser("/buildb/user_path"),
HasUser("/projectb/user_path"),
HasUser("/project/user_path")));
} }
TEST_F(HeaderPathFilter, DontAddInvalidPath) TEST_F(HeaderPathFilter, DontAddInvalidPath)
@@ -119,9 +137,13 @@ TEST_F(HeaderPathFilter, DontAddInvalidPath)
AllOf(Field(&CppTools::HeaderPathFilter::builtInHeaderPaths, AllOf(Field(&CppTools::HeaderPathFilter::builtInHeaderPaths,
ElementsAre(HasBuiltIn("/builtin_path"))), ElementsAre(HasBuiltIn("/builtin_path"))),
Field(&CppTools::HeaderPathFilter::systemHeaderPaths, Field(&CppTools::HeaderPathFilter::systemHeaderPaths,
ElementsAre(HasSystem("/system_path"), HasFramework("/framework_path"))), ElementsAre(HasSystem("/system_path"),
HasFramework("/framework_path"),
HasUser("/outside_project_user_path"),
HasUser("/buildb/user_path"),
HasUser("/projectb/user_path"))),
Field(&CppTools::HeaderPathFilter::userHeaderPaths, Field(&CppTools::HeaderPathFilter::userHeaderPaths,
ElementsAre(HasUser("/user_path"))))); ElementsAre(HasUser("/build/user_path"), HasUser("/project/user_path")))));
} }
TEST_F(HeaderPathFilter, ClangHeadersPath) TEST_F(HeaderPathFilter, ClangHeadersPath)

View File

@@ -78,10 +78,7 @@ MATCHER_P2(HasIdAndType,
class PchCreator: public ::testing::Test class PchCreator: public ::testing::Test
{ {
protected: protected:
PchCreator() PchCreator() { creator.setUnsavedFiles({generatedFile}); }
{
creator.setUnsavedFiles({generatedFile});
}
ClangBackEnd::FilePathId id(ClangBackEnd::FilePathView path) ClangBackEnd::FilePathId id(ClangBackEnd::FilePathView path)
{ {
@@ -95,10 +92,9 @@ protected:
FilePath main2Path = TESTDATA_DIR "/builddependencycollector/project/main2.cpp"; FilePath main2Path = TESTDATA_DIR "/builddependencycollector/project/main2.cpp";
FilePath header1Path = TESTDATA_DIR "/builddependencycollector/project/header1.h"; FilePath header1Path = TESTDATA_DIR "/builddependencycollector/project/header1.h";
FilePath header2Path = TESTDATA_DIR "/builddependencycollector/project/header2.h"; FilePath header2Path = TESTDATA_DIR "/builddependencycollector/project/header2.h";
Utils::SmallStringView generatedFileName = "builddependencycollector/project/generated_file.h";
FilePath generatedFilePath = TESTDATA_DIR "/builddependencycollector/project/generated_file.h"; FilePath generatedFilePath = TESTDATA_DIR "/builddependencycollector/project/generated_file.h";
TestEnvironment environment; TestEnvironment environment;
FileContainer generatedFile{{TESTDATA_DIR, generatedFileName}, "#pragma once", {}}; FileContainer generatedFile{generatedFilePath.clone(), "#pragma once", {}};
NiceMock<MockPchManagerClient> mockPchManagerClient; NiceMock<MockPchManagerClient> mockPchManagerClient;
NiceMock<MockClangPathWatcher> mockClangPathWatcher; NiceMock<MockClangPathWatcher> mockClangPathWatcher;
ClangBackEnd::PchCreator creator{environment, database, mockPchManagerClient, mockClangPathWatcher}; ClangBackEnd::PchCreator creator{environment, database, mockPchManagerClient, mockClangPathWatcher};
@@ -107,7 +103,8 @@ protected:
{id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), {id(TESTDATA_DIR "/builddependencycollector/project/header2.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), id(TESTDATA_DIR "/builddependencycollector/external/external1.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external2.h")}, id(TESTDATA_DIR "/builddependencycollector/external/external2.h")},
{id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), {id(generatedFilePath),
id(TESTDATA_DIR "/builddependencycollector/project/header2.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), id(TESTDATA_DIR "/builddependencycollector/external/external1.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external2.h")}, id(TESTDATA_DIR "/builddependencycollector/external/external2.h")},
{}, {},
@@ -137,6 +134,7 @@ TEST_F(PchCreator, CreateProjectPartClangCompilerArguments)
ASSERT_THAT(arguments, ASSERT_THAT(arguments,
ElementsAre("clang++", ElementsAre("clang++",
"-DNOMINMAX",
"-x", "-x",
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",
@@ -160,6 +158,7 @@ TEST_F(PchCreator, CreateProjectPartClangCompilerArgumentsWithSystemPch)
ASSERT_THAT(arguments, ASSERT_THAT(arguments,
ElementsAre("clang++", ElementsAre("clang++",
"-DNOMINMAX",
"-x", "-x",
"c++-header", "c++-header",
"-std=c++98", "-std=c++98",

View File

@@ -29,6 +29,7 @@
#include "mockpchtasksmerger.h" #include "mockpchtasksmerger.h"
#include <pchtaskgenerator.h> #include <pchtaskgenerator.h>
#include <progresscounter.h>
namespace { namespace {
@@ -50,7 +51,11 @@ class PchTaskGenerator : public testing::Test
protected: protected:
NiceMock<MockBuildDependenciesProvider> mockBuildDependenciesProvider; NiceMock<MockBuildDependenciesProvider> mockBuildDependenciesProvider;
NiceMock<MockPchTasksMerger> mockPchTaskMerger; NiceMock<MockPchTasksMerger> mockPchTaskMerger;
ClangBackEnd::PchTaskGenerator generator{mockBuildDependenciesProvider, mockPchTaskMerger}; NiceMock<MockFunction<void(int, int)>> mockProgressCounterCallback;
ClangBackEnd::ProgressCounter progressCounter{mockProgressCounterCallback.AsStdFunction()};
ClangBackEnd::PchTaskGenerator generator{mockBuildDependenciesProvider,
mockPchTaskMerger,
progressCounter};
ClangBackEnd::ProjectPartContainer projectPart1{ ClangBackEnd::ProjectPartContainer projectPart1{
"ProjectPart1", "ProjectPart1",
{"--yi"}, {"--yi"},
@@ -132,6 +137,18 @@ TEST_F(PchTaskGenerator, AddProjectParts)
generator.addProjectParts({projectPart1}, {"ToolChainArgument"}); generator.addProjectParts({projectPart1}, {"ToolChainArgument"});
} }
TEST_F(PchTaskGenerator, ProgressCounter)
{
ON_CALL(mockBuildDependenciesProvider, create(_)).WillByDefault(Return(buildDependency));
EXPECT_CALL(mockProgressCounterCallback, Call(0, 3));
EXPECT_CALL(mockProgressCounterCallback, Call(1, 3));
EXPECT_CALL(mockProgressCounterCallback, Call(2, 3));
EXPECT_CALL(mockProgressCounterCallback, Call(3, 3));
generator.addProjectParts({projectPart1, projectPart1, projectPart1}, {"ToolChainArgument"});
}
TEST_F(PchTaskGenerator, RemoveProjectParts) TEST_F(PchTaskGenerator, RemoveProjectParts)
{ {
ON_CALL(mockBuildDependenciesProvider, create(_)).WillByDefault(Return(buildDependency)); ON_CALL(mockBuildDependenciesProvider, create(_)).WillByDefault(Return(buildDependency));

View File

@@ -173,7 +173,7 @@ TEST_F(PchTasksMerger, MacrosCanBeMerged)
CompilerMacros compilerMacros1{{"ER", "2", 2}, {"QI"}, {"SE", "4", 1}, {"SAN", "3", 3}}; CompilerMacros compilerMacros1{{"ER", "2", 2}, {"QI"}, {"SE", "4", 1}, {"SAN", "3", 3}};
CompilerMacros compilerMacros2{{"BA"}, {"ER", "2", 2}, {"YI", "1", 1}, {"SAN", "3", 3}}; CompilerMacros compilerMacros2{{"BA"}, {"ER", "2", 2}, {"YI", "1", 1}, {"SAN", "3", 3}};
auto canBeMerged = Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2)); auto canBeMerged = !Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2));
ASSERT_TRUE(canBeMerged); ASSERT_TRUE(canBeMerged);
} }
@@ -183,7 +183,7 @@ TEST_F(PchTasksMerger, MacrosCannotBeMergedBecauseDifferentValue)
CompilerMacros compilerMacros1{{"ER", "2", 2}, {"SE", "4", 1}, {"SAN", "3", 3}}; CompilerMacros compilerMacros1{{"ER", "2", 2}, {"SE", "4", 1}, {"SAN", "3", 3}};
CompilerMacros compilerMacros2{{"ER", "1", 2}, {"YI", "1", 1}, {"SAN", "3", 3}}; CompilerMacros compilerMacros2{{"ER", "1", 2}, {"YI", "1", 1}, {"SAN", "3", 3}};
auto canBeMerged = Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2)); auto canBeMerged = !Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2));
ASSERT_FALSE(canBeMerged); ASSERT_FALSE(canBeMerged);
} }
@@ -193,7 +193,7 @@ TEST_F(PchTasksMerger, MacrosCannotBeMergedBecauseUndefinedMacro)
CompilerMacros compilerMacros1{{"ER", "2", 2}, {"SE", "4", 1}, {"YI"}, {"SAN", "3", 3}}; CompilerMacros compilerMacros1{{"ER", "2", 2}, {"SE", "4", 1}, {"YI"}, {"SAN", "3", 3}};
CompilerMacros compilerMacros2{{"ER", "2", 2}, {"YI", "1", 1}, {"SAN", "3", 3}}; CompilerMacros compilerMacros2{{"ER", "2", 2}, {"YI", "1", 1}, {"SAN", "3", 3}};
auto canBeMerged = Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2)); auto canBeMerged = !Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2));
ASSERT_FALSE(canBeMerged); ASSERT_FALSE(canBeMerged);
} }

View File

@@ -86,6 +86,7 @@ protected:
projectPart.files.push_back(header2ProjectFile); projectPart.files.push_back(header2ProjectFile);
projectPart.files.push_back(source1ProjectFile); projectPart.files.push_back(source1ProjectFile);
projectPart.files.push_back(source2ProjectFile); projectPart.files.push_back(source2ProjectFile);
projectPart.files.push_back(nonActiveProjectFile);
projectPart.displayName = "projectb"; projectPart.displayName = "projectb";
projectPart.projectMacros = {{"FOO", "2"}, {"BAR", "1"}}; projectPart.projectMacros = {{"FOO", "2"}, {"BAR", "1"}};
projectPartId = projectPart.id(); projectPartId = projectPart.id();
@@ -94,15 +95,19 @@ protected:
projectPart2.files.push_back(header1ProjectFile); projectPart2.files.push_back(header1ProjectFile);
projectPart2.files.push_back(source2ProjectFile); projectPart2.files.push_back(source2ProjectFile);
projectPart2.files.push_back(source1ProjectFile); projectPart2.files.push_back(source1ProjectFile);
projectPart2.files.push_back(nonActiveProjectFile);
projectPart2.displayName = "projectaa"; projectPart2.displayName = "projectaa";
projectPart2.projectMacros = {{"BAR", "1"}, {"FOO", "2"}}; projectPart2.projectMacros = {{"BAR", "1"}, {"FOO", "2"}};
projectPartId2 = projectPart2.id(); projectPartId2 = projectPart2.id();
nonBuildingProjectPart.files.push_back(cannotBuildSourceProjectFile);
nonBuildingProjectPart.displayName = "nonbuilding";
nonBuildingProjectPart.selectedForBuilding = false;
Utils::SmallStringVector arguments{ClangPchManager::ProjectUpdater::toolChainArguments( Utils::SmallStringVector arguments{
&projectPart)}; ClangPchManager::ProjectUpdater::toolChainArguments(&projectPart)};
Utils::SmallStringVector arguments2{ClangPchManager::ProjectUpdater::toolChainArguments( Utils::SmallStringVector arguments2{
&projectPart2)}; ClangPchManager::ProjectUpdater::toolChainArguments(&projectPart2)};
expectedContainer = {projectPartId.clone(), expectedContainer = {projectPartId.clone(),
arguments.clone(), arguments.clone(),
@@ -143,9 +148,14 @@ protected:
CppTools::ProjectFile header1ProjectFile{QString(headerPaths[0]), CppTools::ProjectFile::CXXHeader}; CppTools::ProjectFile header1ProjectFile{QString(headerPaths[0]), CppTools::ProjectFile::CXXHeader};
CppTools::ProjectFile header2ProjectFile{QString(headerPaths[1]), CppTools::ProjectFile::CXXHeader}; CppTools::ProjectFile header2ProjectFile{QString(headerPaths[1]), CppTools::ProjectFile::CXXHeader};
CppTools::ProjectFile source1ProjectFile{QString(sourcePaths[0]), CppTools::ProjectFile::CXXSource}; CppTools::ProjectFile source1ProjectFile{QString(sourcePaths[0]), CppTools::ProjectFile::CXXSource};
CppTools::ProjectFile source2ProjectFile{QString(sourcePaths[1]), CppTools::ProjectFile::CXXSource}; CppTools::ProjectFile source2ProjectFile{QString(sourcePaths[1]),
CppTools::ProjectFile::CXXSource};
CppTools::ProjectFile cannotBuildSourceProjectFile{QString("/cannot/build"),
CppTools::ProjectFile::CXXSource};
CppTools::ProjectFile nonActiveProjectFile{QString("/foo"), CppTools::ProjectFile::CXXSource, false};
CppTools::ProjectPart projectPart; CppTools::ProjectPart projectPart;
CppTools::ProjectPart projectPart2; CppTools::ProjectPart projectPart2;
CppTools::ProjectPart nonBuildingProjectPart;
ProjectPartContainer expectedContainer; ProjectPartContainer expectedContainer;
ProjectPartContainer expectedContainer2; ProjectPartContainer expectedContainer2;
FileContainer generatedFile{{"/path/to", "header1.h"}, "content", {}}; FileContainer generatedFile{{"/path/to", "header1.h"}, "content", {}};
@@ -240,7 +250,8 @@ TEST_F(ProjectUpdater, ConvertProjectPartToProjectPartContainer)
TEST_F(ProjectUpdater, ConvertProjectPartToProjectPartContainersHaveSameSizeLikeProjectParts) TEST_F(ProjectUpdater, ConvertProjectPartToProjectPartContainersHaveSameSizeLikeProjectParts)
{ {
auto containers = updater.toProjectPartContainers({&projectPart, &projectPart}); auto containers = updater.toProjectPartContainers(
{&projectPart, &projectPart, &nonBuildingProjectPart});
ASSERT_THAT(containers, SizeIs(2)); ASSERT_THAT(containers, SizeIs(2));
} }

View File

@@ -267,6 +267,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesInCollector)
setFile(main1PathId, setFile(main1PathId,
ElementsAre("clang++", ElementsAre("clang++",
"-Wno-pragma-once-outside-header", "-Wno-pragma-once-outside-header",
"-DNOMINMAX",
"-x", "-x",
"c++", "c++",
"-std=c++14", "-std=c++14",
@@ -297,6 +298,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithPrecompiledHeaderInColl
setFile(main1PathId, setFile(main1PathId,
ElementsAre("clang++", ElementsAre("clang++",
"-Wno-pragma-once-outside-header", "-Wno-pragma-once-outside-header",
"-DNOMINMAX",
"-x", "-x",
"c++", "c++",
"-std=c++14", "-std=c++14",
@@ -330,6 +332,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithoutPrecompiledHeaderInC
setFile(main1PathId, setFile(main1PathId,
ElementsAre("clang++", ElementsAre("clang++",
"-Wno-pragma-once-outside-header", "-Wno-pragma-once-outside-header",
"-DNOMINMAX",
"-x", "-x",
"c++", "c++",
"-std=c++14", "-std=c++14",
@@ -510,6 +513,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithoutProjectPartArtifact)
setFile(main1PathId, setFile(main1PathId,
ElementsAre("clang++", ElementsAre("clang++",
"-Wno-pragma-once-outside-header", "-Wno-pragma-once-outside-header",
"-DNOMINMAX",
"-x", "-x",
"c++", "c++",
"-std=c++14", "-std=c++14",
@@ -562,6 +566,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithProjectPartArtifact)
setFile(Eq(main1PathId), setFile(Eq(main1PathId),
ElementsAre("clang++", ElementsAre("clang++",
"-Wno-pragma-once-outside-header", "-Wno-pragma-once-outside-header",
"-DNOMINMAX",
"-x", "-x",
"c++", "c++",
"-std=c++14", "-std=c++14",
@@ -616,6 +621,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderButGetsAnErrorForCollectingS
setFile(main1PathId, setFile(main1PathId,
ElementsAre("clang++", ElementsAre("clang++",
"-Wno-pragma-once-outside-header", "-Wno-pragma-once-outside-header",
"-DNOMINMAX",
"-x", "-x",
"c++", "c++",
"-std=c++14", "-std=c++14",
@@ -673,6 +679,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrder)
setFile(Eq(sourceFileIds[0]), setFile(Eq(sourceFileIds[0]),
ElementsAre("clang++", ElementsAre("clang++",
"-DFOO", "-DFOO",
"-DNOMINMAX",
"-x", "-x",
"c++", "c++",
"-std=c++14", "-std=c++14",
@@ -736,6 +743,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrderButGetsAnErrorForCollectingSy
setFile(Eq(sourceFileIds[0]), setFile(Eq(sourceFileIds[0]),
ElementsAre("clang++", ElementsAre("clang++",
"-DFOO", "-DFOO",
"-DNOMINMAX",
"-x", "-x",
"c++", "c++",
"-std=c++14", "-std=c++14",
@@ -779,6 +787,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathIsUsingPrecompiledHeader)
setFile(Eq(sourceFileIds[0]), setFile(Eq(sourceFileIds[0]),
ElementsAre("clang++", ElementsAre("clang++",
"-DFOO", "-DFOO",
"-DNOMINMAX",
"-x", "-x",
"c++", "c++",
"-std=c++14", "-std=c++14",
@@ -814,6 +823,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathIsNotUsingPrecompiledHeaderIfItNotExists)
setFile(Eq(sourceFileIds[0]), setFile(Eq(sourceFileIds[0]),
ElementsAre("clang++", ElementsAre("clang++",
"-DFOO", "-DFOO",
"-DNOMINMAX",
"-x", "-x",
"c++", "c++",
"-std=c++14", "-std=c++14",

View File

@@ -46,7 +46,15 @@ protected:
{3, SourceType::ProjectInclude, 0}, {3, SourceType::ProjectInclude, 0},
{4, SourceType::TopSystemInclude, 0}, {4, SourceType::TopSystemInclude, 0},
{5, SourceType::TopProjectInclude, 0}}; {5, SourceType::TopProjectInclude, 0}};
UsedMacros usedMacros{{"YI", 1}, {"ER", 2}, {"LIU", 2}, {"QI", 3}, {"SAN", 3}, {"SE", 4}, {"WU", 5}}; UsedMacros usedMacros{{"YI", 1},
{"ER", 2},
{"SE", 2},
{"LIU", 2},
{"QI", 3},
{"WU", 3},
{"SAN", 3},
{"SE", 4},
{"WU", 5}};
CompilerMacros compileMacros{{"YI", "1", 1}, CompilerMacros compileMacros{{"YI", "1", 1},
{"ER", "2", 2}, {"ER", "2", 2},
{"SAN", "3", 3}, {"SAN", "3", 3},