forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/4.9'
Change-Id: I7bdb6a4658c5fca1a7e1dda5adbb5613dabc6d18
This commit is contained in:
@@ -48,10 +48,11 @@ public:
|
||||
FilePathView outputPath = {},
|
||||
FilePathView includePchPath = {})
|
||||
{
|
||||
commandLine.reserve(128);
|
||||
commandLine.reserve(1024);
|
||||
|
||||
addCompiler(projectInfo.language);
|
||||
addToolChainArguments(toolChainArguments);
|
||||
addExtraFlags();
|
||||
addLanguage(projectInfo, sourceType);
|
||||
addLanguageVersion(projectInfo);
|
||||
addNoStdIncAndNoStdLibInc(projectInfo.language);
|
||||
@@ -79,6 +80,8 @@ public:
|
||||
commandLine.emplace_back(argument);
|
||||
}
|
||||
|
||||
void addExtraFlags() { commandLine.emplace_back("-DNOMINMAX"); }
|
||||
|
||||
static const char *language(const ProjectInfo &projectInfo, InputFileType sourceType)
|
||||
{
|
||||
switch (projectInfo.language) {
|
||||
|
@@ -30,9 +30,9 @@ namespace V2 {
|
||||
|
||||
QDebug operator<<(QDebug debug, const FileContainer &container)
|
||||
{
|
||||
debug.nospace() << "FileContainer("
|
||||
<< container.filePath << ", "
|
||||
debug.nospace() << "FileContainer(" << container.filePath << ", "
|
||||
<< container.commandLineArguments << ", "
|
||||
<< container.unsavedFileContent.hasContent() << ", "
|
||||
<< container.documentRevision;
|
||||
|
||||
debug.nospace() << ")";
|
||||
|
@@ -140,6 +140,13 @@ QTextCursor wordStartCursor(const QTextCursor &textCursor)
|
||||
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)
|
||||
{
|
||||
if (textDocument->blockCount() < line)
|
||||
|
@@ -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 wordStartCursor(const QTextCursor &cursor);
|
||||
QTCREATOR_UTILS_EXPORT QString wordUnderCursor(const QTextCursor &cursor);
|
||||
|
||||
QTCREATOR_UTILS_EXPORT int utf8NthLineOffset(const QTextDocument *textDocument,
|
||||
const QByteArray &buffer,
|
||||
|
@@ -39,9 +39,6 @@ namespace ClangFormat {
|
||||
static void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style,
|
||||
ReplacementsToKeep replacementsToKeep)
|
||||
{
|
||||
if (replacementsToKeep == ReplacementsToKeep::All)
|
||||
return;
|
||||
|
||||
style.MaxEmptyLinesToKeep = 2;
|
||||
style.SortIncludes = false;
|
||||
style.SortUsingDeclarations = false;
|
||||
@@ -67,9 +64,10 @@ static llvm::StringRef clearExtraNewline(llvm::StringRef text)
|
||||
}
|
||||
|
||||
static clang::tooling::Replacements filteredReplacements(
|
||||
const QByteArray &buffer,
|
||||
const clang::tooling::Replacements &replacements,
|
||||
int offset,
|
||||
int utf8LineLengthBeforeCursor,
|
||||
int utf8Offset,
|
||||
int utf8Length,
|
||||
int extraEmptySpaceOffset,
|
||||
ReplacementsToKeep replacementsToKeep)
|
||||
{
|
||||
@@ -77,14 +75,13 @@ static clang::tooling::Replacements filteredReplacements(
|
||||
for (const clang::tooling::Replacement &replacement : replacements) {
|
||||
int replacementOffset = static_cast<int>(replacement.getOffset());
|
||||
const bool replacementDoesNotMatchRestriction
|
||||
= (replacementsToKeep == ReplacementsToKeep::OnlyIndent
|
||||
&& replacementOffset != offset - 1)
|
||||
|| (replacementsToKeep == ReplacementsToKeep::IndentAndBefore
|
||||
&& replacementOffset > offset + utf8LineLengthBeforeCursor - 1);
|
||||
= replacementOffset >= utf8Offset + utf8Length
|
||||
|| (replacementsToKeep == ReplacementsToKeep::OnlyIndent
|
||||
&& (replacementOffset < utf8Offset - 1 || buffer.at(replacementOffset) != '\n'));
|
||||
if (replacementDoesNotMatchRestriction)
|
||||
continue;
|
||||
|
||||
if (replacementOffset >= offset - 1)
|
||||
if (replacementOffset >= utf8Offset - 1)
|
||||
replacementOffset += extraEmptySpaceOffset;
|
||||
|
||||
llvm::StringRef text = replacementsToKeep == ReplacementsToKeep::OnlyIndent
|
||||
@@ -151,13 +148,13 @@ static int previousEmptyLinesLength(const QTextBlock ¤tBlock)
|
||||
}
|
||||
|
||||
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();
|
||||
int firstNonWhitespace = Utils::indexOf(blockText,
|
||||
[](const QChar &ch) { return !ch.isSpace(); });
|
||||
if (firstNonWhitespace > 0)
|
||||
offset += firstNonWhitespace;
|
||||
utf8Offset += firstNonWhitespace;
|
||||
|
||||
const bool closingParenBlock = firstNonWhitespace >= 0
|
||||
&& blockText.at(firstNonWhitespace) == ')';
|
||||
@@ -176,12 +173,11 @@ static void modifyToIndentEmptyLines(
|
||||
if (closingParenBlock || prevBlock.text().endsWith(','))
|
||||
dummyText = "&& a";
|
||||
|
||||
length += dummyText.length();
|
||||
buffer.insert(offset, dummyText);
|
||||
buffer.insert(utf8Offset, dummyText);
|
||||
}
|
||||
|
||||
if (secondTry) {
|
||||
int nextLinePos = buffer.indexOf('\n', offset);
|
||||
int nextLinePos = buffer.indexOf('\n', utf8Offset);
|
||||
if (nextLinePos < 0)
|
||||
nextLinePos = buffer.size() - 1;
|
||||
|
||||
@@ -190,7 +186,6 @@ static void modifyToIndentEmptyLines(
|
||||
// unclosed parentheses.
|
||||
// TODO: Does it help to add different endings depending on the context?
|
||||
buffer.insert(nextLinePos, ')');
|
||||
length += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,13 +246,13 @@ static TextEditor::Replacements utf16Replacements(const QTextBlock &block,
|
||||
return convertedReplacements;
|
||||
}
|
||||
|
||||
static void applyReplacements(const QTextBlock &block, const TextEditor::Replacements &replacements)
|
||||
static void applyReplacements(QTextDocument *doc, const TextEditor::Replacements &replacements)
|
||||
{
|
||||
if (replacements.empty())
|
||||
return;
|
||||
|
||||
int fullOffsetShift = 0;
|
||||
QTextCursor editCursor(block);
|
||||
QTextCursor editCursor(doc);
|
||||
for (const TextEditor::Replacement &replacement : replacements) {
|
||||
editCursor.beginEditBlock();
|
||||
editCursor.setPosition(replacement.offset + fullOffsetShift);
|
||||
@@ -305,24 +300,12 @@ void ClangFormatBaseIndenter::indent(const QTextCursor &cursor,
|
||||
int cursorPositionInEditor)
|
||||
{
|
||||
if (cursor.hasSelection()) {
|
||||
// Calling currentBlock.next() might be unsafe because we change the document.
|
||||
// Let's operate with block numbers instead.
|
||||
const int startNumber = m_doc->findBlock(cursor.selectionStart()).blockNumber();
|
||||
const int endNumber = m_doc->findBlock(cursor.selectionEnd()).blockNumber();
|
||||
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);
|
||||
}
|
||||
}
|
||||
indentBlocks(m_doc->findBlock(cursor.selectionStart()),
|
||||
m_doc->findBlock(cursor.selectionEnd()),
|
||||
typedChar,
|
||||
cursorPositionInEditor);
|
||||
} 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);
|
||||
}
|
||||
|
||||
TextEditor::Replacements ClangFormatBaseIndenter::format(const QTextCursor &cursor,
|
||||
int cursorPositionInEditor)
|
||||
TextEditor::Replacements ClangFormatBaseIndenter::format(
|
||||
const TextEditor::RangesInLines &rangesInLines)
|
||||
{
|
||||
int utf8Offset;
|
||||
int utf8Length;
|
||||
if (rangesInLines.empty())
|
||||
return TextEditor::Replacements();
|
||||
|
||||
int utf8Offset = -1;
|
||||
QTextBlock block;
|
||||
|
||||
const QByteArray buffer = m_doc->toPlainText().toUtf8();
|
||||
if (cursor.hasSelection()) {
|
||||
block = m_doc->findBlock(cursor.selectionStart());
|
||||
const QTextBlock end = m_doc->findBlock(cursor.selectionEnd());
|
||||
utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
|
||||
QTC_ASSERT(utf8Offset >= 0, return TextEditor::Replacements(););
|
||||
utf8Length = selectedLines(m_doc, block, end).toUtf8().size();
|
||||
} else {
|
||||
block = cursor.block();
|
||||
utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
|
||||
QTC_ASSERT(utf8Offset >= 0, return TextEditor::Replacements(););
|
||||
std::vector<clang::tooling::Range> ranges;
|
||||
ranges.reserve(rangesInLines.size());
|
||||
|
||||
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,
|
||||
utf8Offset,
|
||||
utf8Length,
|
||||
block,
|
||||
cursorPositionInEditor,
|
||||
ReplacementsToKeep::All,
|
||||
QChar::Null);
|
||||
applyReplacements(block, toReplace);
|
||||
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,
|
||||
buffer,
|
||||
clangReplacements);
|
||||
applyReplacements(m_doc, 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)
|
||||
{
|
||||
const QChar character = doc->characterAt(pos);
|
||||
const QTextBlock currentBlock = doc->findBlock(pos);
|
||||
const QString text = currentBlock.text().left(pos - currentBlock.position());
|
||||
// NOTE: check if "<<" and ">>" always work correctly.
|
||||
switch (character.toLatin1()) {
|
||||
default:
|
||||
break;
|
||||
@@ -419,33 +387,30 @@ static bool doNotIndentInContext(QTextDocument *doc, int pos)
|
||||
if (pos > 0 && doc->characterAt(pos - 1) != ':')
|
||||
return true;
|
||||
break;
|
||||
case '<':
|
||||
case '>':
|
||||
// "<<" and ">>" could be problematic
|
||||
if (pos > 0 && doc->characterAt(pos - 1) == character)
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
|
||||
const QChar &typedChar,
|
||||
int cursorPositionInEditor)
|
||||
void ClangFormatBaseIndenter::indentBlocks(const QTextBlock &startBlock,
|
||||
const QTextBlock &endBlock,
|
||||
const QChar &typedChar,
|
||||
int cursorPositionInEditor)
|
||||
{
|
||||
QTextBlock currentBlock = block;
|
||||
const int blockPosition = currentBlock.position();
|
||||
trimFirstNonEmptyBlock(currentBlock);
|
||||
|
||||
if (typedChar != QChar::Null && cursorPositionInEditor > 0
|
||||
&& m_doc->characterAt(cursorPositionInEditor - 1) == typedChar
|
||||
&& doNotIndentInContext(m_doc, cursorPositionInEditor - 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int startBlockPosition = startBlock.position();
|
||||
trimFirstNonEmptyBlock(startBlock);
|
||||
if (cursorPositionInEditor >= 0)
|
||||
cursorPositionInEditor += startBlock.position() - startBlockPosition;
|
||||
|
||||
ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent;
|
||||
if (formatWhileTyping()
|
||||
&& (cursorPositionInEditor == -1 || cursorPositionInEditor >= blockPosition)
|
||||
&& (cursorPositionInEditor == -1 || cursorPositionInEditor >= startBlockPosition)
|
||||
&& (typedChar == QChar::Null || typedChar == ';' || typedChar == '}')) {
|
||||
// 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
|
||||
@@ -453,26 +418,23 @@ void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
|
||||
// cursorPositionInEditor == -1 means the consition matches automatically.
|
||||
|
||||
// Format only before newline or complete statement not to break code.
|
||||
if (cursorPositionInEditor >= 0)
|
||||
cursorPositionInEditor += currentBlock.position() - blockPosition;
|
||||
else
|
||||
cursorPositionInEditor = currentBlock.position();
|
||||
|
||||
indentBeforeCursor(currentBlock, typedChar, cursorPositionInEditor);
|
||||
return;
|
||||
replacementsToKeep = ReplacementsToKeep::IndentAndBefore;
|
||||
}
|
||||
|
||||
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;);
|
||||
const int utf8Length = selectedLines(m_doc, startBlock, endBlock).toUtf8().size();
|
||||
|
||||
applyReplacements(currentBlock,
|
||||
applyReplacements(m_doc,
|
||||
replacements(buffer,
|
||||
utf8Offset,
|
||||
0,
|
||||
currentBlock,
|
||||
cursorPositionInEditor,
|
||||
ReplacementsToKeep::OnlyIndent,
|
||||
utf8Length,
|
||||
startBlock,
|
||||
endBlock,
|
||||
replacementsToKeep,
|
||||
typedChar));
|
||||
}
|
||||
|
||||
@@ -481,12 +443,13 @@ void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
|
||||
const TextEditor::TabSettings & /*tabSettings*/,
|
||||
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);
|
||||
|
||||
const QByteArray buffer = m_doc->toPlainText().toUtf8();
|
||||
const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
|
||||
QTC_ASSERT(utf8Offset >= 0, return 0;);
|
||||
@@ -495,7 +458,7 @@ int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, int cursorPositi
|
||||
utf8Offset,
|
||||
0,
|
||||
block,
|
||||
cursorPositionInEditor,
|
||||
block,
|
||||
ReplacementsToKeep::OnlyIndent);
|
||||
|
||||
if (toReplace.empty())
|
||||
@@ -535,10 +498,19 @@ void ClangFormatBaseIndenter::formatOrIndent(const QTextCursor &cursor,
|
||||
const TextEditor::TabSettings & /*tabSettings*/,
|
||||
int cursorPositionInEditor)
|
||||
{
|
||||
if (formatCodeInsteadOfIndent())
|
||||
format(cursor, cursorPositionInEditor);
|
||||
else
|
||||
if (formatCodeInsteadOfIndent()) {
|
||||
QTextBlock start;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const
|
||||
@@ -574,43 +546,38 @@ static int formattingRangeStart(const QTextBlock ¤tBlock,
|
||||
TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer,
|
||||
int utf8Offset,
|
||||
int utf8Length,
|
||||
const QTextBlock &block,
|
||||
int cursorPositionInEditor,
|
||||
const QTextBlock &startBlock,
|
||||
const QTextBlock &endBlock,
|
||||
ReplacementsToKeep replacementsToKeep,
|
||||
const QChar &typedChar,
|
||||
bool secondTry) const
|
||||
{
|
||||
QTC_ASSERT(replacementsToKeep != ReplacementsToKeep::All, return TextEditor::Replacements());
|
||||
|
||||
clang::format::FormatStyle style = styleForFile();
|
||||
|
||||
int originalOffsetUtf8 = utf8Offset;
|
||||
int originalLengthUtf8 = utf8Length;
|
||||
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 rangeStart = 0;
|
||||
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore)
|
||||
rangeStart = formattingRangeStart(startBlock, buffer, lastSaveRevision());
|
||||
|
||||
int extraEmptySpaceOffset = previousEmptyLinesLength(startBlock);
|
||||
utf8Offset -= extraEmptySpaceOffset;
|
||||
buffer.remove(utf8Offset, extraEmptySpaceOffset);
|
||||
|
||||
adjustFormatStyleForLineBreak(style, replacementsToKeep);
|
||||
if (typedChar == QChar::Null && startBlock == endBlock) {
|
||||
modifyToIndentEmptyLines(buffer, utf8Offset, startBlock, secondTry);
|
||||
utf8Length = 0;
|
||||
}
|
||||
|
||||
int extraEmptySpaceOffset = 0;
|
||||
int rangeStart = 0;
|
||||
if (replacementsToKeep != ReplacementsToKeep::All) {
|
||||
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore)
|
||||
rangeStart = formattingRangeStart(block, buffer, lastSaveRevision());
|
||||
|
||||
extraEmptySpaceOffset = previousEmptyLinesLength(block);
|
||||
utf8Offset -= extraEmptySpaceOffset;
|
||||
buffer.remove(utf8Offset, extraEmptySpaceOffset);
|
||||
|
||||
adjustFormatStyleForLineBreak(style, replacementsToKeep);
|
||||
modifyToIndentEmptyLines(buffer, utf8Offset, utf8Length, block, secondTry);
|
||||
|
||||
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) {
|
||||
buffer.insert(utf8Offset - 1, " //");
|
||||
extraEmptySpaceOffset -= 3;
|
||||
utf8Offset += 3;
|
||||
}
|
||||
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) {
|
||||
buffer.insert(utf8Offset - 1, " //");
|
||||
extraEmptySpaceOffset -= 3;
|
||||
utf8Offset += 3;
|
||||
}
|
||||
|
||||
if (replacementsToKeep != ReplacementsToKeep::IndentAndBefore || utf8Offset < rangeStart)
|
||||
@@ -630,9 +597,10 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer
|
||||
|
||||
clang::tooling::Replacements filtered;
|
||||
if (status.FormatComplete) {
|
||||
filtered = filteredReplacements(clangReplacements,
|
||||
filtered = filteredReplacements(buffer,
|
||||
clangReplacements,
|
||||
utf8Offset,
|
||||
utf8LineLengthBeforeCursor,
|
||||
utf8Length,
|
||||
extraEmptySpaceOffset,
|
||||
replacementsToKeep);
|
||||
}
|
||||
@@ -642,14 +610,14 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer
|
||||
return replacements(originalBuffer,
|
||||
originalOffsetUtf8,
|
||||
originalLengthUtf8,
|
||||
block,
|
||||
cursorPositionInEditor,
|
||||
startBlock,
|
||||
endBlock,
|
||||
replacementsToKeep,
|
||||
typedChar,
|
||||
true);
|
||||
}
|
||||
|
||||
return utf16Replacements(block, originalOffsetUtf8, originalBuffer, filtered);
|
||||
return utf16Replacements(startBlock, originalOffsetUtf8, originalBuffer, filtered);
|
||||
}
|
||||
|
||||
} // namespace ClangFormat
|
||||
|
@@ -53,9 +53,8 @@ public:
|
||||
void formatOrIndent(const QTextCursor &cursor,
|
||||
const TextEditor::TabSettings &tabSettings,
|
||||
int cursorPositionInEditor = -1) override;
|
||||
TextEditor::Replacements format(const QTextCursor &cursor,
|
||||
const TextEditor::TabSettings &tabSettings,
|
||||
int cursorPositionInEditor = -1) override;
|
||||
TextEditor::Replacements format(
|
||||
const TextEditor::RangesInLines &rangesInLines = TextEditor::RangesInLines()) override;
|
||||
|
||||
void indentBlock(const QTextBlock &block,
|
||||
const QChar &typedChar,
|
||||
@@ -75,18 +74,17 @@ protected:
|
||||
virtual int lastSaveRevision() const { return 0; }
|
||||
|
||||
private:
|
||||
TextEditor::Replacements format(const QTextCursor &cursor, int cursorPositionInEditor);
|
||||
void indent(const QTextCursor &cursor, const QChar &typedChar, int cursorPositionInEditor);
|
||||
void indentBlock(const QTextBlock &block, const QChar &typedChar, int cursorPositionInEditor);
|
||||
void indentBlocks(const QTextBlock &startBlock,
|
||||
const QTextBlock &endBlock,
|
||||
const QChar &typedChar,
|
||||
int cursorPositionInEditor);
|
||||
int indentFor(const QTextBlock &block, int cursorPositionInEditor);
|
||||
void indentBeforeCursor(const QTextBlock &block,
|
||||
const QChar &typedChar,
|
||||
int cursorPositionInEditor);
|
||||
TextEditor::Replacements replacements(QByteArray buffer,
|
||||
int utf8Offset,
|
||||
int utf8Length,
|
||||
const QTextBlock &block,
|
||||
int cursorPositionInEditor,
|
||||
const QTextBlock &startBlock,
|
||||
const QTextBlock &endBlock,
|
||||
ReplacementsToKeep replacementsToKeep,
|
||||
const QChar &typedChar = QChar::Null,
|
||||
bool secondTry = false) const;
|
||||
|
@@ -37,6 +37,9 @@
|
||||
#include <cpptools/compileroptionsbuilder.h>
|
||||
#include <cpptools/projectpart.h>
|
||||
#include <cpptools/headerpathfilter.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <projectexplorer/buildconfiguration.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
@@ -140,8 +143,10 @@ HeaderAndSources ProjectUpdater::headerAndSourcesFromProjectPart(
|
||||
HeaderAndSources headerAndSources;
|
||||
headerAndSources.reserve(std::size_t(projectPart->files.size()) * 3 / 2);
|
||||
|
||||
for (const CppTools::ProjectFile &projectFile : projectPart->files)
|
||||
addToHeaderAndSources(headerAndSources, projectFile);
|
||||
for (const CppTools::ProjectFile &projectFile : projectPart->files) {
|
||||
if (projectFile.active)
|
||||
addToHeaderAndSources(headerAndSources, projectFile);
|
||||
}
|
||||
|
||||
std::sort(headerAndSources.sources.begin(), headerAndSources.sources.end());
|
||||
std::sort(headerAndSources.headers.begin(), headerAndSources.headers.end());
|
||||
@@ -231,6 +236,21 @@ ClangBackEnd::IncludeSearchPaths convertToIncludeSearchPaths(
|
||||
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
|
||||
|
||||
ProjectUpdater::SystemAndProjectIncludeSearchPaths ProjectUpdater::createIncludeSearchPaths(
|
||||
@@ -239,7 +259,9 @@ ProjectUpdater::SystemAndProjectIncludeSearchPaths ProjectUpdater::createInclude
|
||||
CppTools::HeaderPathFilter filter(projectPart,
|
||||
CppTools::UseTweakedHeaderPaths::Yes,
|
||||
CLANG_VERSION,
|
||||
CLANG_RESOURCE_DIR);
|
||||
CLANG_RESOURCE_DIR,
|
||||
projectDirectory(projectPart.project),
|
||||
buildDirectory(projectPart.project));
|
||||
filter.process();
|
||||
|
||||
return {convertToIncludeSearchPaths(filter.systemHeaderPaths, filter.builtInHeaderPaths),
|
||||
@@ -277,6 +299,13 @@ ClangBackEnd::ProjectPartContainers ProjectUpdater::toProjectPartContainers(
|
||||
std::vector<ClangBackEnd::ProjectPartContainer> projectPartContainers;
|
||||
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(),
|
||||
projectParts.end(),
|
||||
std::back_inserter(projectPartContainers),
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include "pchmanagerprojectupdater.h"
|
||||
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <projectexplorer/extracompiler.h>
|
||||
|
||||
#include <filecontainerv2.h>
|
||||
|
||||
@@ -49,8 +50,9 @@ CLANGPCHMANAGER_EXPORT std::vector<ClangBackEnd::V2::FileContainer> createGenera
|
||||
CLANGPCHMANAGER_EXPORT std::vector<CppTools::ProjectPart*> createProjectParts(ProjectExplorer::Project *project);
|
||||
}
|
||||
|
||||
template <typename ProjectUpdaterType>
|
||||
class QtCreatorProjectUpdater : public ProjectUpdaterType
|
||||
template<typename ProjectUpdaterType>
|
||||
class QtCreatorProjectUpdater : public ProjectUpdaterType,
|
||||
public ProjectExplorer::ExtraCompilerFactoryObserver
|
||||
{
|
||||
public:
|
||||
template <typename ClientType>
|
||||
@@ -90,6 +92,15 @@ public:
|
||||
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:
|
||||
void connectToCppModelManager()
|
||||
{
|
||||
|
@@ -89,6 +89,10 @@ bool FixitsRefactoringFile::apply()
|
||||
= CppTools::CppCodeStyleSettings::currentProjectTabSettings();
|
||||
|
||||
// Apply changes
|
||||
std::unique_ptr<TextEditor::Indenter> indenter;
|
||||
QString lastFilename;
|
||||
ReplacementOperations operationsForFile;
|
||||
|
||||
for (int i=0; i < m_replacementOperations.size(); ++i) {
|
||||
ReplacementOperation &op = *m_replacementOperations[i];
|
||||
if (op.apply) {
|
||||
@@ -103,15 +107,19 @@ bool FixitsRefactoringFile::apply()
|
||||
|
||||
// Apply
|
||||
QTextDocument *doc = document(op.fileName);
|
||||
std::unique_ptr<TextEditor::Indenter> indenter(factory->createIndenter(doc));
|
||||
indenter->setFileName(Utils::FileName::fromString(op.fileName));
|
||||
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));
|
||||
}
|
||||
|
||||
QTextCursor cursor(doc);
|
||||
cursor.setPosition(op.pos);
|
||||
cursor.setPosition(op.pos + op.length, QTextCursor::KeepAnchor);
|
||||
cursor.insertText(op.text);
|
||||
|
||||
tryToFormat(*indenter, tabSettings, doc, op, i);
|
||||
operationsForFile.push_back(&op);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,28 +138,29 @@ bool FixitsRefactoringFile::apply()
|
||||
return true;
|
||||
}
|
||||
|
||||
void FixitsRefactoringFile::tryToFormat(TextEditor::Indenter &indenter,
|
||||
const TextEditor::TabSettings &tabSettings,
|
||||
QTextDocument *doc,
|
||||
const ReplacementOperation &op,
|
||||
int currentIndex)
|
||||
void FixitsRefactoringFile::format(TextEditor::Indenter &indenter,
|
||||
QTextDocument *doc,
|
||||
const ReplacementOperations &operationsForFile,
|
||||
int firstOperationIndex)
|
||||
{
|
||||
QTextCursor cursor(doc);
|
||||
cursor.beginEditBlock();
|
||||
cursor.setPosition(op.pos);
|
||||
cursor.movePosition(QTextCursor::Right,
|
||||
QTextCursor::KeepAnchor,
|
||||
op.text.length());
|
||||
const Replacements replacements = indenter.format(cursor, tabSettings);
|
||||
cursor.endEditBlock();
|
||||
if (operationsForFile.isEmpty())
|
||||
return;
|
||||
|
||||
TextEditor::RangesInLines ranges;
|
||||
for (int i = 0; i < operationsForFile.size(); ++i) {
|
||||
const ReplacementOperation &op = *operationsForFile.at(i);
|
||||
const int start = doc->findBlock(op.pos).blockNumber() + 1;
|
||||
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())
|
||||
return;
|
||||
|
||||
if (hasIntersection(op.fileName, replacements, currentIndex + 1))
|
||||
doc->undo(&cursor);
|
||||
else
|
||||
shiftAffectedReplacements(op.fileName, replacements, currentIndex + 1);
|
||||
shiftAffectedReplacements(operationsForFile.front()->fileName,
|
||||
replacements,
|
||||
firstOperationIndex + 1);
|
||||
}
|
||||
|
||||
QTextDocument *FixitsRefactoringFile::document(const QString &filePath) const
|
||||
|
@@ -67,11 +67,10 @@ private:
|
||||
QTextDocument *document(const QString &filePath) const;
|
||||
void shiftAffectedReplacements(const ReplacementOperation &op, int startIndex);
|
||||
|
||||
void tryToFormat(TextEditor::Indenter &indenter,
|
||||
const TextEditor::TabSettings &tabSettings,
|
||||
QTextDocument *doc,
|
||||
const ReplacementOperation &op,
|
||||
int currentIndex);
|
||||
void format(TextEditor::Indenter &indenter,
|
||||
QTextDocument *doc,
|
||||
const ReplacementOperations &operationsForFile,
|
||||
int firstOperationIndex);
|
||||
void shiftAffectedReplacements(const QString &fileName,
|
||||
const TextEditor::Replacements &replacements,
|
||||
int startIndex);
|
||||
|
@@ -300,8 +300,8 @@ ClangTidyClazyTool::ClangTidyClazyTool()
|
||||
});
|
||||
connect(m_applyFixitsButton, &QToolButton::clicked, [this]() {
|
||||
QVector<DiagnosticItem *> diagnosticItems;
|
||||
m_diagnosticModel->rootItem()->forChildrenAtLevel(2, [&](TreeItem *item){
|
||||
diagnosticItems += static_cast<DiagnosticItem *>(item);
|
||||
m_diagnosticModel->forItemsAtLevel<2>([&](DiagnosticItem *item){
|
||||
diagnosticItems += item;
|
||||
});
|
||||
|
||||
ApplyFixIts(diagnosticItems).apply(m_diagnosticModel);
|
||||
|
@@ -81,7 +81,7 @@ private:
|
||||
};
|
||||
|
||||
ClangToolsDiagnosticModel::ClangToolsDiagnosticModel(QObject *parent)
|
||||
: Utils::TreeModel<>(parent)
|
||||
: ClangToolsDiagnosticModelBase(parent)
|
||||
, m_filesWatcher(std::make_unique<QFileSystemWatcher>())
|
||||
{
|
||||
setHeader({tr("Diagnostic")});
|
||||
@@ -146,7 +146,7 @@ void ClangToolsDiagnosticModel::clear()
|
||||
m_filePathToItem.clear();
|
||||
m_diagnostics.clear();
|
||||
clearAndSetupCache();
|
||||
Utils::TreeModel<>::clear();
|
||||
ClangToolsDiagnosticModelBase::clear();
|
||||
}
|
||||
|
||||
void ClangToolsDiagnosticModel::updateItems(const DiagnosticItem *changedItem)
|
||||
@@ -174,10 +174,9 @@ void ClangToolsDiagnosticModel::clearAndSetupCache()
|
||||
|
||||
void ClangToolsDiagnosticModel::onFileChanged(const QString &path)
|
||||
{
|
||||
rootItem()->forChildrenAtLevel(2, [&](Utils::TreeItem *item){
|
||||
auto diagnosticItem = static_cast<DiagnosticItem *>(item);
|
||||
if (diagnosticItem->diagnostic().location.filePath == path)
|
||||
diagnosticItem->setFixItStatus(FixitStatus::Invalidated);
|
||||
forItemsAtLevel<2>([&](DiagnosticItem *item){
|
||||
if (item->diagnostic().location.filePath == path)
|
||||
item->setFixItStatus(FixitStatus::Invalidated);
|
||||
});
|
||||
removeWatchedPath(path);
|
||||
}
|
||||
@@ -623,9 +622,10 @@ bool DiagnosticFilterModel::filterAcceptsRow(int sourceRow,
|
||||
|
||||
// DiagnosticItem
|
||||
Utils::TreeItem *parentItem = model->itemForIndex(sourceParent);
|
||||
if (auto filePathItem = dynamic_cast<FilePathItem *>(parentItem)) {
|
||||
auto diagnosticItem = dynamic_cast<DiagnosticItem *>(filePathItem->childAt(sourceRow));
|
||||
QTC_ASSERT(diagnosticItem, return false);
|
||||
QTC_ASSERT(parentItem, return true);
|
||||
if (parentItem->level() == 1) {
|
||||
auto filePathItem = static_cast<FilePathItem *>(parentItem);
|
||||
auto diagnosticItem = static_cast<DiagnosticItem *>(filePathItem->childAt(sourceRow));
|
||||
|
||||
// Is the diagnostic explicitly suppressed?
|
||||
const Diagnostic &diag = diagnosticItem->diagnostic();
|
||||
@@ -651,11 +651,12 @@ bool DiagnosticFilterModel::lessThan(const QModelIndex &l, const QModelIndex &r)
|
||||
{
|
||||
auto model = static_cast<ClangToolsDiagnosticModel *>(sourceModel());
|
||||
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) {
|
||||
bool result = false;
|
||||
if (dynamic_cast<DiagnosticItem *>(itemLeft)) {
|
||||
if (itemLeft->level() == 2) {
|
||||
using Debugger::DiagnosticLocation;
|
||||
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)
|
||||
< std::tie(rightLoc.line, rightLoc.column, rightText);
|
||||
} else if (auto left = dynamic_cast<ExplainingStepItem *>(itemLeft)) {
|
||||
const auto right = dynamic_cast<ExplainingStepItem *>(model->itemForIndex(r));
|
||||
} else if (itemLeft->level() == 3) {
|
||||
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();
|
||||
} else {
|
||||
QTC_CHECK(false && "Unexpected item");
|
||||
|
@@ -100,7 +100,11 @@ private:
|
||||
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
|
||||
|
||||
|
@@ -446,46 +446,39 @@ TextEditor::TabSettings CppEditorDocument::tabSettings() const
|
||||
return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings());
|
||||
}
|
||||
|
||||
static int formatRange(QTextDocument *doc,
|
||||
TextEditor::Indenter *indenter,
|
||||
std::pair<int, int> editedRange,
|
||||
const TextEditor::TabSettings &tabSettings)
|
||||
{
|
||||
QTextCursor cursor(doc);
|
||||
cursor.setPosition(editedRange.first);
|
||||
cursor.setPosition(editedRange.second, QTextCursor::KeepAnchor);
|
||||
const int oldBlockCount = doc->blockCount();
|
||||
indenter->format(cursor, tabSettings);
|
||||
return doc->blockCount() - oldBlockCount;
|
||||
}
|
||||
|
||||
bool CppEditorDocument::save(QString *errorString, const QString &fileName, bool autoSave)
|
||||
{
|
||||
if (indenter()->formatOnSave()) {
|
||||
QTextCursor cursor(document());
|
||||
cursor.joinPreviousEditBlock();
|
||||
if (indenter()->formatOnSave() && !autoSave) {
|
||||
auto *layout = qobject_cast<TextEditor::TextDocumentLayout *>(document()->documentLayout());
|
||||
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) {
|
||||
const QTextBlock block = document()->findBlockByNumber(i);
|
||||
if (block.revision() == documentRevision) {
|
||||
if (editedRange.first != -1)
|
||||
i += formatRange(document(), indenter(), editedRange, tabSettings());
|
||||
if (lastRange.startLine != -1)
|
||||
editedRanges.push_back(lastRange);
|
||||
|
||||
editedRange = std::make_pair(-1, -1);
|
||||
lastRange.startLine = lastRange.endLine = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// block.revision() != documentRevision
|
||||
if (editedRange.first == -1)
|
||||
editedRange.first = block.position();
|
||||
editedRange.second = block.position() + block.length();
|
||||
if (lastRange.startLine == -1)
|
||||
lastRange.startLine = block.blockNumber() + 1;
|
||||
lastRange.endLine = block.blockNumber() + 1;
|
||||
}
|
||||
|
||||
if (lastRange.startLine != -1)
|
||||
editedRanges.push_back(lastRange);
|
||||
|
||||
if (!editedRanges.empty()) {
|
||||
QTextCursor cursor(document());
|
||||
cursor.joinPreviousEditBlock();
|
||||
indenter()->format(editedRanges);
|
||||
cursor.endEditBlock();
|
||||
}
|
||||
if (editedRange.first != -1)
|
||||
formatRange(document(), indenter(), editedRange, tabSettings());
|
||||
cursor.endEditBlock();
|
||||
}
|
||||
|
||||
return TextEditor::TextDocument::save(errorString, fileName, autoSave);
|
||||
|
@@ -48,6 +48,11 @@ void HeaderPathFilter::process()
|
||||
tweakHeaderPaths();
|
||||
}
|
||||
|
||||
bool HeaderPathFilter::isProjectHeaderPath(const QString &path) const
|
||||
{
|
||||
return path.startsWith(projectDirectory) || path.startsWith(buildDirectory);
|
||||
}
|
||||
|
||||
void HeaderPathFilter::filterHeaderPath(const ProjectExplorer::HeaderPath &headerPath)
|
||||
{
|
||||
if (headerPath.path.isEmpty())
|
||||
@@ -62,7 +67,10 @@ void HeaderPathFilter::filterHeaderPath(const ProjectExplorer::HeaderPath &heade
|
||||
systemHeaderPaths.push_back(headerPath);
|
||||
break;
|
||||
case HeaderPathType::User:
|
||||
userHeaderPaths.push_back(headerPath);
|
||||
if (isProjectHeaderPath(headerPath.path))
|
||||
userHeaderPaths.push_back(headerPath);
|
||||
else
|
||||
systemHeaderPaths.push_back(headerPath);
|
||||
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
|
||||
|
@@ -34,11 +34,15 @@ class CPPTOOLS_EXPORT HeaderPathFilter
|
||||
public:
|
||||
HeaderPathFilter(const ProjectPart &projectPart,
|
||||
UseTweakedHeaderPaths useTweakedHeaderPaths = UseTweakedHeaderPaths::Yes,
|
||||
const QString &clangVersion = QString(),
|
||||
const QString &clangResourceDirectory = QString())
|
||||
const QString &clangVersion = {},
|
||||
const QString &clangResourceDirectory = {},
|
||||
const QString &projectDirectory = {},
|
||||
const QString &buildDirectory = {})
|
||||
: projectPart{projectPart}
|
||||
, clangVersion{clangVersion}
|
||||
, clangResourceDirectory{clangResourceDirectory}
|
||||
, projectDirectory(ensurePathWithSlashEnding(projectDirectory))
|
||||
, buildDirectory(ensurePathWithSlashEnding(buildDirectory))
|
||||
, useTweakedHeaderPaths{useTweakedHeaderPaths}
|
||||
{}
|
||||
|
||||
@@ -49,6 +53,10 @@ private:
|
||||
|
||||
void tweakHeaderPaths();
|
||||
|
||||
bool isProjectHeaderPath(const QString &path) const;
|
||||
|
||||
static QString ensurePathWithSlashEnding(const QString &path);
|
||||
|
||||
public:
|
||||
ProjectExplorer::HeaderPaths builtInHeaderPaths;
|
||||
ProjectExplorer::HeaderPaths systemHeaderPaths;
|
||||
@@ -56,6 +64,8 @@ public:
|
||||
const ProjectPart &projectPart;
|
||||
const QString clangVersion;
|
||||
const QString clangResourceDirectory;
|
||||
const QString projectDirectory;
|
||||
const QString buildDirectory;
|
||||
const UseTweakedHeaderPaths useTweakedHeaderPaths;
|
||||
};
|
||||
|
||||
|
@@ -1451,8 +1451,9 @@ void DebuggerPluginPrivate::updatePresetState()
|
||||
if (startupRunConfigName.isEmpty() && startupProject)
|
||||
startupRunConfigName = startupProject->displayName();
|
||||
|
||||
// Restrict width, otherwise Creator gets too wide, see QTCREATORBUG-21885
|
||||
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.setText(canRun ? startToolTip : tr("Start Debugging"));
|
||||
|
@@ -52,7 +52,7 @@ namespace ProjectExplorer {
|
||||
|
||||
Q_GLOBAL_STATIC(QThreadPool, s_extraCompilerThreadPool);
|
||||
Q_GLOBAL_STATIC(QList<ExtraCompilerFactory *>, factories);
|
||||
|
||||
Q_GLOBAL_STATIC(QVector<ExtraCompilerFactoryObserver *>, observers);
|
||||
class ExtraCompilerPrivate
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -320,6 +321,14 @@ ExtraCompilerFactory::~ExtraCompilerFactory()
|
||||
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()
|
||||
{
|
||||
return *factories();
|
||||
@@ -455,4 +464,14 @@ void ProcessExtraCompiler::cleanUp()
|
||||
setCompileTime(QDateTime::currentDateTime());
|
||||
}
|
||||
|
||||
ExtraCompilerFactoryObserver::ExtraCompilerFactoryObserver()
|
||||
{
|
||||
observers->push_back(this);
|
||||
}
|
||||
|
||||
ExtraCompilerFactoryObserver::~ExtraCompilerFactoryObserver()
|
||||
{
|
||||
observers->removeOne(this);
|
||||
}
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
|
@@ -137,6 +137,20 @@ private:
|
||||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -147,8 +161,14 @@ public:
|
||||
virtual FileType sourceType() const = 0;
|
||||
virtual QString sourceTag() const = 0;
|
||||
|
||||
virtual ExtraCompiler *create(const Project *project, const Utils::FileName &source,
|
||||
const Utils::FileNameList &targets) = 0;
|
||||
virtual ExtraCompiler *create(const Project *project,
|
||||
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();
|
||||
};
|
||||
|
@@ -1143,14 +1143,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
|
||||
mprojectContextMenu->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(
|
||||
tr("Close All Files"), tr("Close All Files in Project \"%1\""),
|
||||
Utils::ParameterAction::EnabledWithParameter, this);
|
||||
@@ -1160,6 +1152,14 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
|
||||
cmd->setDescription(dd->m_closeProjectFilesActionContextMenu->text());
|
||||
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
|
||||
dd->m_filePropertiesAction = new QAction(tr("Properties..."), this);
|
||||
cmd = ActionManager::registerAction(dd->m_filePropertiesAction, Constants::FILEPROPERTIES,
|
||||
@@ -1854,18 +1854,15 @@ void ProjectExplorerPluginPrivate::setStartupProject(Project *project)
|
||||
bool ProjectExplorerPluginPrivate::closeAllFilesInProject(const Project *project)
|
||||
{
|
||||
QTC_ASSERT(project, return false);
|
||||
const Utils::FileNameList filesInProject = project->files(Project::AllFiles);
|
||||
QList<IDocument *> openFiles = DocumentModel::openedDocuments();
|
||||
Utils::erase(openFiles, [filesInProject](const IDocument *doc) {
|
||||
return !filesInProject.contains(doc->filePath());
|
||||
Utils::erase(openFiles, [project](const IDocument *doc) {
|
||||
return !project->isKnownFile(doc->filePath());
|
||||
});
|
||||
for (const Project * const otherProject : SessionManager::projects()) {
|
||||
if (otherProject == project)
|
||||
continue;
|
||||
const Utils::FileNameList filesInOtherProject
|
||||
= otherProject->files(Project::AllFiles);
|
||||
Utils::erase(openFiles, [filesInOtherProject](const IDocument *doc) {
|
||||
return filesInOtherProject.contains(doc->filePath());
|
||||
Utils::erase(openFiles, [otherProject](const IDocument *doc) {
|
||||
return otherProject->isKnownFile(doc->filePath());
|
||||
});
|
||||
}
|
||||
return EditorManager::closeDocuments(openFiles);
|
||||
|
@@ -149,6 +149,8 @@ ExtraCompiler *QScxmlcGeneratorFactory::create(
|
||||
const Project *project, const Utils::FileName &source,
|
||||
const Utils::FileNameList &targets)
|
||||
{
|
||||
annouceCreation(project, source, targets);
|
||||
|
||||
return new QScxmlcGenerator(project, source, targets, this);
|
||||
}
|
||||
|
||||
|
@@ -100,6 +100,8 @@ ExtraCompiler *UicGeneratorFactory::create(const Project *project,
|
||||
const Utils::FileName &source,
|
||||
const Utils::FileNameList &targets)
|
||||
{
|
||||
annouceCreation(project, source, targets);
|
||||
|
||||
return new UicGenerator(project, source, targets, this);
|
||||
}
|
||||
|
||||
|
@@ -203,7 +203,9 @@ void AbstractRemoteLinuxDeployService::handleDeviceSetupDone(bool success)
|
||||
} else {
|
||||
connect(d->connection, &SshConnection::connected,
|
||||
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)
|
||||
d->connection->connectToHost();
|
||||
}
|
||||
|
@@ -58,6 +58,15 @@ public:
|
||||
|
||||
using Replacements = std::vector<Replacement>;
|
||||
|
||||
class RangeInLines
|
||||
{
|
||||
public:
|
||||
int startLine;
|
||||
int endLine;
|
||||
};
|
||||
|
||||
using RangesInLines = std::vector<RangeInLines>;
|
||||
|
||||
class Indenter
|
||||
{
|
||||
public:
|
||||
@@ -91,9 +100,7 @@ public:
|
||||
}
|
||||
|
||||
// By default just calls indent with default settings.
|
||||
virtual Replacements format(const QTextCursor &/*cursor*/,
|
||||
const TabSettings &/*tabSettings*/,
|
||||
int /*cursorPositionInEditor*/ = -1)
|
||||
virtual Replacements format(const RangesInLines & /*rangesInLines*/ = RangesInLines())
|
||||
{
|
||||
return Replacements();
|
||||
}
|
||||
|
@@ -8085,12 +8085,21 @@ void BaseTextEditor::setContextHelp(const HelpItem &item)
|
||||
|
||||
void TextEditorWidget::contextHelpItem(const IContext::HelpCallback &callback)
|
||||
{
|
||||
const QString fallbackWordUnderCursor = Text::wordUnderCursor(textCursor());
|
||||
if (d->m_contextHelpItem.isEmpty() && !d->m_hoverHandlers.isEmpty()) {
|
||||
d->m_hoverHandlers.first()->contextHelpId(this,
|
||||
Text::wordStartCursor(textCursor()).position(),
|
||||
callback);
|
||||
[fallbackWordUnderCursor, callback](const HelpItem &item) {
|
||||
if (item.isEmpty())
|
||||
callback(fallbackWordUnderCursor);
|
||||
else
|
||||
callback(item);
|
||||
});
|
||||
} else {
|
||||
callback(d->m_contextHelpItem);
|
||||
if (d->m_contextHelpItem.isEmpty())
|
||||
callback(fallbackWordUnderCursor);
|
||||
else
|
||||
callback(d->m_contextHelpItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -291,6 +291,9 @@ void TextMark::addToToolTipLayout(QGridLayout *target) const
|
||||
// Right column: action icons/button
|
||||
if (!m_actions.isEmpty()) {
|
||||
auto actionsLayout = new QHBoxLayout;
|
||||
QMargins margins = actionsLayout->contentsMargins();
|
||||
margins.setLeft(margins.left() + 5);
|
||||
actionsLayout->setContentsMargins(margins);
|
||||
for (QAction *action : m_actions) {
|
||||
QTC_ASSERT(!action->icon().isNull(), continue);
|
||||
auto button = new QToolButton;
|
||||
|
@@ -119,7 +119,7 @@ IntroductionWidget::IntroductionWidget(QWidget *parent)
|
||||
"<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>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>Help:</td><td>Browse the help database.</td></tr>"
|
||||
"</table></p>")},
|
||||
|
Submodule src/shared/qbs updated: 6fcbc1a996...bceae1097f
@@ -246,8 +246,13 @@ struct Data // because we have a cycle dependency
|
||||
modifiedTimeChecker,
|
||||
buildDependencyCollector,
|
||||
database};
|
||||
ClangBackEnd::PchTaskGenerator pchTaskGenerator{buildDependencyProvider, pchTaskMerger};
|
||||
PchManagerServer clangPchManagerServer{includeWatcher, pchTaskGenerator, projectParts, generatedFiles};
|
||||
ClangBackEnd::PchTaskGenerator pchTaskGenerator{buildDependencyProvider,
|
||||
pchTaskMerger,
|
||||
progressCounter};
|
||||
PchManagerServer clangPchManagerServer{includeWatcher,
|
||||
pchTaskGenerator,
|
||||
projectParts,
|
||||
generatedFiles};
|
||||
TaskScheduler systemTaskScheduler{pchCreatorManager,
|
||||
pchTaskQueue,
|
||||
progressCounter,
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <clang/Tooling/Tooling.h>
|
||||
|
||||
#include <clang/Basic/DiagnosticOptions.h>
|
||||
#include <clang/Frontend/CompilerInstance.h>
|
||||
#include <clang/Frontend/FrontendActions.h>
|
||||
#include <clang/Lex/PreprocessorOptions.h>
|
||||
@@ -44,6 +45,9 @@ public:
|
||||
bool BeginInvocation(clang::CompilerInstance &compilerInstance) override
|
||||
{
|
||||
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);
|
||||
compilerInstance.getPreprocessorOpts().addRemappedFile(m_filePath, Input.release());
|
||||
|
||||
|
@@ -76,8 +76,6 @@ bool PchCreator::generatePch(NativeFilePathView path, Utils::SmallStringView con
|
||||
{
|
||||
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(),
|
||||
path.size()},
|
||||
llvm::StringRef{content.data(),
|
||||
@@ -138,6 +136,16 @@ const ProjectPartPch &PchCreator::projectPartPch()
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -159,7 +167,14 @@ void PchCreator::clear()
|
||||
|
||||
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});
|
||||
}
|
||||
|
||||
|
@@ -98,6 +98,7 @@ private:
|
||||
ProjectPartPch m_projectPartPch;
|
||||
FilePathCaching m_filePathCache;
|
||||
FilePathIds m_allInclues;
|
||||
FilePathIds m_generatedFilePathIds;
|
||||
Environment &m_environment;
|
||||
PchManagerClientInterface &m_pchManagerClient;
|
||||
ClangPathWatcherInterface &m_clangPathwatcher;
|
||||
|
@@ -27,9 +27,10 @@
|
||||
|
||||
#include "builddependenciesproviderinterface.h"
|
||||
#include "pchtasksmergerinterface.h"
|
||||
|
||||
#include "usedmacrofilter.h"
|
||||
|
||||
#include <progresscounter.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
@@ -40,6 +41,8 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts,
|
||||
PchTaskSets pchTaskSets;
|
||||
pchTaskSets.reserve(projectParts.size());
|
||||
|
||||
m_progressCounter.addTotal(static_cast<int>(projectParts.size()));
|
||||
|
||||
for (auto &projectPart : projectParts) {
|
||||
BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart);
|
||||
UsedMacroFilter filter{buildDependency.includes,
|
||||
@@ -68,6 +71,7 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts,
|
||||
projectPart.language,
|
||||
projectPart.languageVersion,
|
||||
projectPart.languageExtension});
|
||||
m_progressCounter.addProgress(1);
|
||||
}
|
||||
|
||||
m_pchTasksMergerInterface.mergeTasks(std::move(pchTaskSets), std::move(toolChainArguments));
|
||||
|
@@ -35,14 +35,18 @@ namespace ClangBackEnd {
|
||||
class PchTasksMergerInterface;
|
||||
|
||||
class BuildDependenciesProviderInterface;
|
||||
class ProgressCounter;
|
||||
|
||||
class PchTaskGenerator : public PchTaskGeneratorInterface
|
||||
{
|
||||
public:
|
||||
PchTaskGenerator(BuildDependenciesProviderInterface &buildDependenciesProvider,
|
||||
PchTasksMergerInterface &pchTasksMergerInterface)
|
||||
PchTasksMergerInterface &pchTasksMergerInterface,
|
||||
ProgressCounter &progressCounter)
|
||||
: m_buildDependenciesProvider(buildDependenciesProvider)
|
||||
, m_pchTasksMergerInterface(pchTasksMergerInterface)
|
||||
, m_progressCounter(progressCounter)
|
||||
|
||||
{}
|
||||
|
||||
void addProjectParts(ProjectPartContainers &&projectParts,
|
||||
@@ -52,7 +56,7 @@ public:
|
||||
private:
|
||||
BuildDependenciesProviderInterface &m_buildDependenciesProvider;
|
||||
PchTasksMergerInterface &m_pchTasksMergerInterface;
|
||||
ProgressCounter &m_progressCounter;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
@@ -71,7 +71,7 @@ bool PchTasksMerger::hasDuplicates(const CompilerMacros &compilerMacros)
|
||||
return first.key == second.key;
|
||||
});
|
||||
|
||||
return found == compilerMacros.end();
|
||||
return found != compilerMacros.end();
|
||||
}
|
||||
|
||||
IncludeSearchPaths mergeIncludeSearchPaths(IncludeSearchPaths &&first, IncludeSearchPaths &&second)
|
||||
@@ -89,7 +89,8 @@ bool PchTasksMerger::mergePchTasks(PchTask &firstTask, PchTask &secondTask)
|
||||
|
||||
CompilerMacros macros = mergeMacros(firstTask.compilerMacros, secondTask.compilerMacros);
|
||||
|
||||
secondTask.isMerged = hasDuplicates(macros);
|
||||
secondTask.isMerged = !hasDuplicates(macros);
|
||||
|
||||
|
||||
if (secondTask.isMerged && firstTask.language == secondTask.language) {
|
||||
firstTask.projectPartIds = merge(std::move(firstTask.projectPartIds),
|
||||
|
@@ -93,8 +93,8 @@ public:
|
||||
return std::tie(first.key, first.value) < std::tie(second.key, second.value);
|
||||
});
|
||||
|
||||
systemCompilerMacros = filtercompilerMacros(indexedCompilerMacro, systemUsedMacros);
|
||||
projectCompilerMacros = filtercompilerMacros(indexedCompilerMacro, projectUsedMacros);
|
||||
systemCompilerMacros = filterCompilerMacros(indexedCompilerMacro, systemUsedMacros);
|
||||
projectCompilerMacros = filterCompilerMacros(indexedCompilerMacro, projectUsedMacros);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -150,10 +150,13 @@ private:
|
||||
|
||||
std::sort(filtertedMacros.begin(), filtertedMacros.end());
|
||||
|
||||
auto newEnd = std::unique(filtertedMacros.begin(), filtertedMacros.end());
|
||||
filtertedMacros.erase(newEnd, filtertedMacros.end());
|
||||
|
||||
return filtertedMacros;
|
||||
}
|
||||
|
||||
static CompilerMacros filtercompilerMacros(const CompilerMacros &indexedCompilerMacro,
|
||||
static CompilerMacros filterCompilerMacros(const CompilerMacros &indexedCompilerMacro,
|
||||
const Utils::SmallStringVector &usedMacros)
|
||||
{
|
||||
CompilerMacros filtertedCompilerMacros;
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <clang/Frontend/CompilerInstance.h>
|
||||
#include <clang/Frontend/FrontendActions.h>
|
||||
#include <clang/Lex/PreprocessorOptions.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
@@ -100,6 +101,7 @@ newFrontendActionFactory(Factory *consumerFactory,
|
||||
bool BeginInvocation(clang::CompilerInstance &compilerInstance) override
|
||||
{
|
||||
compilerInstance.getLangOpts().DelayedTemplateParsing = false;
|
||||
compilerInstance.getPreprocessorOpts().AllowPCHWithCompilerErrors = true;
|
||||
|
||||
return clang::ASTFrontendAction::BeginInvocation(compilerInstance);
|
||||
}
|
||||
|
37
tests/unit/mockup/projectexplorer/buildconfiguration.h
Normal file
37
tests/unit/mockup/projectexplorer/buildconfiguration.h
Normal 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
|
@@ -25,6 +25,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "target.h"
|
||||
|
||||
#include <projectexplorer/kit.h>
|
||||
|
||||
#include <utils/fileutils.h>
|
||||
@@ -35,13 +37,10 @@ class Project : public QObject {
|
||||
public:
|
||||
Project() = default;
|
||||
|
||||
Utils::FileName projectDirectory() const {
|
||||
return Utils::FileName();
|
||||
}
|
||||
Utils::FileName projectDirectory() const { return {}; }
|
||||
|
||||
Utils::FileName rootProjectDirectory() const {
|
||||
return Utils::FileName();
|
||||
}
|
||||
Utils::FileName rootProjectDirectory() const { return {}; }
|
||||
|
||||
Target *activeTarget() const { return {}; }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace ProjectExplorer
|
||||
|
39
tests/unit/mockup/projectexplorer/target.h
Normal file
39
tests/unit/mockup/projectexplorer/target.h
Normal 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
|
@@ -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)
|
||||
{
|
||||
insertLines({"int main()",
|
||||
@@ -415,7 +469,7 @@ TEST_F(ClangFormat, FormatBasicFile)
|
||||
"int a;",
|
||||
"}"});
|
||||
|
||||
indenter.format(cursor, TextEditor::TabSettings());
|
||||
indenter.format(cursor);
|
||||
|
||||
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() {}"));
|
||||
}
|
||||
@@ -441,7 +495,7 @@ TEST_F(ClangFormat, FormatLambda)
|
||||
"",
|
||||
"});"});
|
||||
|
||||
indenter.format(cursor, TextEditor::TabSettings());
|
||||
indenter.format(cursor);
|
||||
|
||||
ASSERT_THAT(documentLines(), ElementsAre("int b = foo([]() {",
|
||||
"",
|
||||
@@ -454,7 +508,7 @@ TEST_F(ClangFormat, FormatInitializerListInArguments)
|
||||
"args,",
|
||||
"{1, 2});"});
|
||||
|
||||
indenter.format(cursor, TextEditor::TabSettings());
|
||||
indenter.format(cursor);
|
||||
|
||||
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(),
|
||||
ElementsAre("foo([]() {",
|
||||
@@ -481,7 +535,7 @@ TEST_F(ClangFormat, FormatScopeAsFunctionArgument)
|
||||
"",
|
||||
"});"});
|
||||
|
||||
indenter.format(cursor, TextEditor::TabSettings());
|
||||
indenter.format(cursor);
|
||||
|
||||
ASSERT_THAT(documentLines(),
|
||||
ElementsAre("foo({",
|
||||
@@ -494,7 +548,7 @@ TEST_F(ClangFormat, FormatStructuredBinding)
|
||||
insertLines({"auto [a,",
|
||||
"b] = c;"});
|
||||
|
||||
indenter.format(cursor, TextEditor::TabSettings());
|
||||
indenter.format(cursor);
|
||||
|
||||
ASSERT_THAT(documentLines(), ElementsAre("auto [a, b] = c;"));
|
||||
}
|
||||
@@ -504,7 +558,7 @@ TEST_F(ClangFormat, FormatStringLiteralContinuation)
|
||||
insertLines({"foo(bar, \"foo\"",
|
||||
"\"bar\");"});
|
||||
|
||||
indenter.format(cursor, TextEditor::TabSettings());
|
||||
indenter.format(cursor);
|
||||
|
||||
ASSERT_THAT(documentLines(), ElementsAre("foo(bar,",
|
||||
" \"foo\"",
|
||||
@@ -517,7 +571,7 @@ TEST_F(ClangFormat, FormatTemplateparameters)
|
||||
"B,",
|
||||
"C>"});
|
||||
|
||||
indenter.format(cursor, TextEditor::TabSettings());
|
||||
indenter.format(cursor);
|
||||
|
||||
ASSERT_THAT(documentLines(), ElementsAre("using Alias = Template<A, B, C>"));
|
||||
}
|
||||
|
@@ -139,6 +139,7 @@ TYPED_TEST(CommandLineBuilder, CHeader)
|
||||
|
||||
ASSERT_THAT(builder.commandLine,
|
||||
ElementsAre("clang",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c-header",
|
||||
"-std=c11",
|
||||
@@ -154,7 +155,7 @@ TYPED_TEST(CommandLineBuilder, CSource)
|
||||
Builder<TypeParam> builder{this->emptyProjectInfo, {}, InputFileType::Source, "/source/file.c"};
|
||||
|
||||
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)
|
||||
@@ -167,6 +168,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCHeader)
|
||||
|
||||
ASSERT_THAT(builder.commandLine,
|
||||
ElementsAre("clang",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"objective-c-header",
|
||||
"-std=c11",
|
||||
@@ -184,6 +186,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCSource)
|
||||
|
||||
ASSERT_THAT(builder.commandLine,
|
||||
ElementsAre("clang",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"objective-c",
|
||||
"-std=c11",
|
||||
@@ -200,6 +203,7 @@ TYPED_TEST(CommandLineBuilder, CppHeader)
|
||||
|
||||
ASSERT_THAT(builder.commandLine,
|
||||
ElementsAre("clang++",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++-header",
|
||||
"-std=c++98",
|
||||
@@ -215,9 +219,15 @@ TYPED_TEST(CommandLineBuilder, CppSource)
|
||||
|
||||
Builder<TypeParam> builder{this->emptyProjectInfo, {}, InputFileType::Source, "/source/file.cpp"};
|
||||
|
||||
ASSERT_THAT(
|
||||
builder.commandLine,
|
||||
ElementsAre("clang++", "-x", "c++", "-std=c++98", "-nostdinc", "-nostdinc++", "/source/file.cpp"));
|
||||
ASSERT_THAT(builder.commandLine,
|
||||
ElementsAre("clang++",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++",
|
||||
"-std=c++98",
|
||||
"-nostdinc",
|
||||
"-nostdinc++",
|
||||
"/source/file.cpp"));
|
||||
}
|
||||
|
||||
TYPED_TEST(CommandLineBuilder, ObjectiveCppHeader)
|
||||
@@ -230,6 +240,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCppHeader)
|
||||
|
||||
ASSERT_THAT(builder.commandLine,
|
||||
ElementsAre("clang++",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"objective-c++-header",
|
||||
"-std=c++98",
|
||||
@@ -248,6 +259,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCppSource)
|
||||
|
||||
ASSERT_THAT(builder.commandLine,
|
||||
ElementsAre("clang++",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"objective-c++",
|
||||
"-std=c++98",
|
||||
@@ -480,6 +492,7 @@ TYPED_TEST(CommandLineBuilder, IncludesOrder)
|
||||
|
||||
ASSERT_THAT(builder.commandLine,
|
||||
ElementsAre("clang++",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++-header",
|
||||
"-std=c++11",
|
||||
@@ -505,7 +518,13 @@ TYPED_TEST(CommandLineBuilder, EmptySourceFile)
|
||||
Builder<TypeParam> builder{this->emptyProjectInfo, {}, {}};
|
||||
|
||||
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)
|
||||
@@ -514,6 +533,7 @@ TYPED_TEST(CommandLineBuilder, SourceFile)
|
||||
|
||||
ASSERT_THAT(builder.commandLine,
|
||||
ElementsAre("clang++",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++-header",
|
||||
"-std=c++98",
|
||||
@@ -529,6 +549,7 @@ TYPED_TEST(CommandLineBuilder, EmptyOutputFile)
|
||||
|
||||
ASSERT_THAT(builder.commandLine,
|
||||
ElementsAre("clang++",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++-header",
|
||||
"-std=c++98",
|
||||
@@ -547,6 +568,7 @@ TYPED_TEST(CommandLineBuilder, OutputFile)
|
||||
|
||||
ASSERT_THAT(builder.commandLine,
|
||||
ElementsAre("clang++",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++-header",
|
||||
"-std=c++98",
|
||||
@@ -568,6 +590,7 @@ TYPED_TEST(CommandLineBuilder, IncludePchPath)
|
||||
|
||||
ASSERT_THAT(builder.commandLine,
|
||||
ElementsAre("clang++",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++-header",
|
||||
"-std=c++98",
|
||||
@@ -590,6 +613,7 @@ TYPED_TEST(CommandLineBuilder, CompilerMacros)
|
||||
|
||||
ASSERT_THAT(builder.commandLine,
|
||||
ElementsAre("clang++",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++-header",
|
||||
"-std=c++98",
|
||||
|
115
tests/unit/unittest/data/clangformat/.clang-format
Normal file
115
tests/unit/unittest/data/clangformat/.clang-format
Normal 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
|
@@ -43,7 +43,7 @@ MATCHER_P(HasBuiltIn,
|
||||
MATCHER_P(HasSystem,
|
||||
path,
|
||||
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;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ MATCHER_P(HasSystem,
|
||||
MATCHER_P(HasFramework,
|
||||
path,
|
||||
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;
|
||||
}
|
||||
@@ -59,7 +59,7 @@ MATCHER_P(HasFramework,
|
||||
MATCHER_P(HasUser,
|
||||
path,
|
||||
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;
|
||||
}
|
||||
@@ -73,42 +73,60 @@ protected:
|
||||
HeaderPath{"/builtin_path", HeaderPathType::BuiltIn},
|
||||
HeaderPath{"/system_path", HeaderPathType::System},
|
||||
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;
|
||||
}
|
||||
|
||||
protected:
|
||||
CppTools::ProjectPart projectPart;
|
||||
CppTools::HeaderPathFilter filter{projectPart, CppTools::UseTweakedHeaderPaths::No};
|
||||
CppTools::HeaderPathFilter filter{
|
||||
projectPart, CppTools::UseTweakedHeaderPaths::No, {}, {}, "/project", "/build"};
|
||||
};
|
||||
|
||||
TEST_F(HeaderPathFilter, BuiltIn)
|
||||
{
|
||||
filter.process();
|
||||
|
||||
ASSERT_THAT(filter.builtInHeaderPaths, Contains(HasBuiltIn("/builtin_path")));
|
||||
ASSERT_THAT(filter.builtInHeaderPaths, ElementsAre(HasBuiltIn("/builtin_path")));
|
||||
}
|
||||
|
||||
TEST_F(HeaderPathFilter, System)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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();
|
||||
|
||||
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)
|
||||
@@ -119,9 +137,13 @@ TEST_F(HeaderPathFilter, DontAddInvalidPath)
|
||||
AllOf(Field(&CppTools::HeaderPathFilter::builtInHeaderPaths,
|
||||
ElementsAre(HasBuiltIn("/builtin_path"))),
|
||||
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,
|
||||
ElementsAre(HasUser("/user_path")))));
|
||||
ElementsAre(HasUser("/build/user_path"), HasUser("/project/user_path")))));
|
||||
}
|
||||
|
||||
TEST_F(HeaderPathFilter, ClangHeadersPath)
|
||||
|
@@ -78,10 +78,7 @@ MATCHER_P2(HasIdAndType,
|
||||
class PchCreator: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
PchCreator()
|
||||
{
|
||||
creator.setUnsavedFiles({generatedFile});
|
||||
}
|
||||
PchCreator() { creator.setUnsavedFiles({generatedFile}); }
|
||||
|
||||
ClangBackEnd::FilePathId id(ClangBackEnd::FilePathView path)
|
||||
{
|
||||
@@ -95,10 +92,9 @@ protected:
|
||||
FilePath main2Path = TESTDATA_DIR "/builddependencycollector/project/main2.cpp";
|
||||
FilePath header1Path = TESTDATA_DIR "/builddependencycollector/project/header1.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";
|
||||
TestEnvironment environment;
|
||||
FileContainer generatedFile{{TESTDATA_DIR, generatedFileName}, "#pragma once", {}};
|
||||
FileContainer generatedFile{generatedFilePath.clone(), "#pragma once", {}};
|
||||
NiceMock<MockPchManagerClient> mockPchManagerClient;
|
||||
NiceMock<MockClangPathWatcher> mockClangPathWatcher;
|
||||
ClangBackEnd::PchCreator creator{environment, database, mockPchManagerClient, mockClangPathWatcher};
|
||||
@@ -107,7 +103,8 @@ protected:
|
||||
{id(TESTDATA_DIR "/builddependencycollector/project/header2.h"),
|
||||
id(TESTDATA_DIR "/builddependencycollector/external/external1.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/external2.h")},
|
||||
{},
|
||||
@@ -137,6 +134,7 @@ TEST_F(PchCreator, CreateProjectPartClangCompilerArguments)
|
||||
|
||||
ASSERT_THAT(arguments,
|
||||
ElementsAre("clang++",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++-header",
|
||||
"-std=c++98",
|
||||
@@ -160,6 +158,7 @@ TEST_F(PchCreator, CreateProjectPartClangCompilerArgumentsWithSystemPch)
|
||||
|
||||
ASSERT_THAT(arguments,
|
||||
ElementsAre("clang++",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++-header",
|
||||
"-std=c++98",
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include "mockpchtasksmerger.h"
|
||||
|
||||
#include <pchtaskgenerator.h>
|
||||
#include <progresscounter.h>
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -50,7 +51,11 @@ class PchTaskGenerator : public testing::Test
|
||||
protected:
|
||||
NiceMock<MockBuildDependenciesProvider> mockBuildDependenciesProvider;
|
||||
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{
|
||||
"ProjectPart1",
|
||||
{"--yi"},
|
||||
@@ -132,6 +137,18 @@ TEST_F(PchTaskGenerator, AddProjectParts)
|
||||
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)
|
||||
{
|
||||
ON_CALL(mockBuildDependenciesProvider, create(_)).WillByDefault(Return(buildDependency));
|
||||
|
@@ -173,7 +173,7 @@ TEST_F(PchTasksMerger, MacrosCanBeMerged)
|
||||
CompilerMacros compilerMacros1{{"ER", "2", 2}, {"QI"}, {"SE", "4", 1}, {"SAN", "3", 3}};
|
||||
CompilerMacros compilerMacros2{{"BA"}, {"ER", "2", 2}, {"YI", "1", 1}, {"SAN", "3", 3}};
|
||||
|
||||
auto canBeMerged = Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2));
|
||||
auto canBeMerged = !Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2));
|
||||
|
||||
ASSERT_TRUE(canBeMerged);
|
||||
}
|
||||
@@ -183,7 +183,7 @@ TEST_F(PchTasksMerger, MacrosCannotBeMergedBecauseDifferentValue)
|
||||
CompilerMacros compilerMacros1{{"ER", "2", 2}, {"SE", "4", 1}, {"SAN", "3", 3}};
|
||||
CompilerMacros compilerMacros2{{"ER", "1", 2}, {"YI", "1", 1}, {"SAN", "3", 3}};
|
||||
|
||||
auto canBeMerged = Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2));
|
||||
auto canBeMerged = !Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2));
|
||||
|
||||
ASSERT_FALSE(canBeMerged);
|
||||
}
|
||||
@@ -193,7 +193,7 @@ TEST_F(PchTasksMerger, MacrosCannotBeMergedBecauseUndefinedMacro)
|
||||
CompilerMacros compilerMacros1{{"ER", "2", 2}, {"SE", "4", 1}, {"YI"}, {"SAN", "3", 3}};
|
||||
CompilerMacros compilerMacros2{{"ER", "2", 2}, {"YI", "1", 1}, {"SAN", "3", 3}};
|
||||
|
||||
auto canBeMerged = Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2));
|
||||
auto canBeMerged = !Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2));
|
||||
|
||||
ASSERT_FALSE(canBeMerged);
|
||||
}
|
||||
|
@@ -86,6 +86,7 @@ protected:
|
||||
projectPart.files.push_back(header2ProjectFile);
|
||||
projectPart.files.push_back(source1ProjectFile);
|
||||
projectPart.files.push_back(source2ProjectFile);
|
||||
projectPart.files.push_back(nonActiveProjectFile);
|
||||
projectPart.displayName = "projectb";
|
||||
projectPart.projectMacros = {{"FOO", "2"}, {"BAR", "1"}};
|
||||
projectPartId = projectPart.id();
|
||||
@@ -94,15 +95,19 @@ protected:
|
||||
projectPart2.files.push_back(header1ProjectFile);
|
||||
projectPart2.files.push_back(source2ProjectFile);
|
||||
projectPart2.files.push_back(source1ProjectFile);
|
||||
projectPart2.files.push_back(nonActiveProjectFile);
|
||||
projectPart2.displayName = "projectaa";
|
||||
projectPart2.projectMacros = {{"BAR", "1"}, {"FOO", "2"}};
|
||||
projectPartId2 = projectPart2.id();
|
||||
|
||||
nonBuildingProjectPart.files.push_back(cannotBuildSourceProjectFile);
|
||||
nonBuildingProjectPart.displayName = "nonbuilding";
|
||||
nonBuildingProjectPart.selectedForBuilding = false;
|
||||
|
||||
Utils::SmallStringVector arguments{ClangPchManager::ProjectUpdater::toolChainArguments(
|
||||
&projectPart)};
|
||||
Utils::SmallStringVector arguments2{ClangPchManager::ProjectUpdater::toolChainArguments(
|
||||
&projectPart2)};
|
||||
Utils::SmallStringVector arguments{
|
||||
ClangPchManager::ProjectUpdater::toolChainArguments(&projectPart)};
|
||||
Utils::SmallStringVector arguments2{
|
||||
ClangPchManager::ProjectUpdater::toolChainArguments(&projectPart2)};
|
||||
|
||||
expectedContainer = {projectPartId.clone(),
|
||||
arguments.clone(),
|
||||
@@ -143,9 +148,14 @@ protected:
|
||||
CppTools::ProjectFile header1ProjectFile{QString(headerPaths[0]), CppTools::ProjectFile::CXXHeader};
|
||||
CppTools::ProjectFile header2ProjectFile{QString(headerPaths[1]), CppTools::ProjectFile::CXXHeader};
|
||||
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 projectPart2;
|
||||
CppTools::ProjectPart nonBuildingProjectPart;
|
||||
ProjectPartContainer expectedContainer;
|
||||
ProjectPartContainer expectedContainer2;
|
||||
FileContainer generatedFile{{"/path/to", "header1.h"}, "content", {}};
|
||||
@@ -240,7 +250,8 @@ TEST_F(ProjectUpdater, ConvertProjectPartToProjectPartContainer)
|
||||
|
||||
TEST_F(ProjectUpdater, ConvertProjectPartToProjectPartContainersHaveSameSizeLikeProjectParts)
|
||||
{
|
||||
auto containers = updater.toProjectPartContainers({&projectPart, &projectPart});
|
||||
auto containers = updater.toProjectPartContainers(
|
||||
{&projectPart, &projectPart, &nonBuildingProjectPart});
|
||||
|
||||
ASSERT_THAT(containers, SizeIs(2));
|
||||
}
|
||||
|
@@ -267,6 +267,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesInCollector)
|
||||
setFile(main1PathId,
|
||||
ElementsAre("clang++",
|
||||
"-Wno-pragma-once-outside-header",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++",
|
||||
"-std=c++14",
|
||||
@@ -297,6 +298,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithPrecompiledHeaderInColl
|
||||
setFile(main1PathId,
|
||||
ElementsAre("clang++",
|
||||
"-Wno-pragma-once-outside-header",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++",
|
||||
"-std=c++14",
|
||||
@@ -330,6 +332,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithoutPrecompiledHeaderInC
|
||||
setFile(main1PathId,
|
||||
ElementsAre("clang++",
|
||||
"-Wno-pragma-once-outside-header",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++",
|
||||
"-std=c++14",
|
||||
@@ -510,6 +513,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithoutProjectPartArtifact)
|
||||
setFile(main1PathId,
|
||||
ElementsAre("clang++",
|
||||
"-Wno-pragma-once-outside-header",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++",
|
||||
"-std=c++14",
|
||||
@@ -562,6 +566,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithProjectPartArtifact)
|
||||
setFile(Eq(main1PathId),
|
||||
ElementsAre("clang++",
|
||||
"-Wno-pragma-once-outside-header",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++",
|
||||
"-std=c++14",
|
||||
@@ -616,6 +621,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderButGetsAnErrorForCollectingS
|
||||
setFile(main1PathId,
|
||||
ElementsAre("clang++",
|
||||
"-Wno-pragma-once-outside-header",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++",
|
||||
"-std=c++14",
|
||||
@@ -673,6 +679,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrder)
|
||||
setFile(Eq(sourceFileIds[0]),
|
||||
ElementsAre("clang++",
|
||||
"-DFOO",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++",
|
||||
"-std=c++14",
|
||||
@@ -736,6 +743,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrderButGetsAnErrorForCollectingSy
|
||||
setFile(Eq(sourceFileIds[0]),
|
||||
ElementsAre("clang++",
|
||||
"-DFOO",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++",
|
||||
"-std=c++14",
|
||||
@@ -779,6 +787,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathIsUsingPrecompiledHeader)
|
||||
setFile(Eq(sourceFileIds[0]),
|
||||
ElementsAre("clang++",
|
||||
"-DFOO",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++",
|
||||
"-std=c++14",
|
||||
@@ -814,6 +823,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathIsNotUsingPrecompiledHeaderIfItNotExists)
|
||||
setFile(Eq(sourceFileIds[0]),
|
||||
ElementsAre("clang++",
|
||||
"-DFOO",
|
||||
"-DNOMINMAX",
|
||||
"-x",
|
||||
"c++",
|
||||
"-std=c++14",
|
||||
|
@@ -46,7 +46,15 @@ protected:
|
||||
{3, SourceType::ProjectInclude, 0},
|
||||
{4, SourceType::TopSystemInclude, 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},
|
||||
{"ER", "2", 2},
|
||||
{"SAN", "3", 3},
|
||||
|
Reference in New Issue
Block a user