Merge remote-tracking branch 'origin/4.9'

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

View File

@@ -48,10 +48,11 @@ public:
FilePathView outputPath = {},
FilePathView 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) {

View File

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

View File

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

View File

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

View File

@@ -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 &currentBlock)
}
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,
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,
utf8Length,
block,
cursorPositionInEditor,
ReplacementsToKeep::All,
QChar::Null);
applyReplacements(block, toReplace);
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,
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,44 +546,39 @@ static int formattingRangeStart(const QTextBlock &currentBlock,
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 extraEmptySpaceOffset = 0;
int rangeStart = 0;
if (replacementsToKeep != ReplacementsToKeep::All) {
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore)
rangeStart = formattingRangeStart(block, buffer, lastSaveRevision());
rangeStart = formattingRangeStart(startBlock, buffer, lastSaveRevision());
extraEmptySpaceOffset = previousEmptyLinesLength(block);
int extraEmptySpaceOffset = previousEmptyLinesLength(startBlock);
utf8Offset -= extraEmptySpaceOffset;
buffer.remove(utf8Offset, extraEmptySpaceOffset);
adjustFormatStyleForLineBreak(style, replacementsToKeep);
modifyToIndentEmptyLines(buffer, utf8Offset, utf8Length, block, secondTry);
if (typedChar == QChar::Null && startBlock == endBlock) {
modifyToIndentEmptyLines(buffer, utf8Offset, startBlock, secondTry);
utf8Length = 0;
}
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) {
buffer.insert(utf8Offset - 1, " //");
extraEmptySpaceOffset -= 3;
utf8Offset += 3;
}
}
if (replacementsToKeep != ReplacementsToKeep::IndentAndBefore || utf8Offset < rangeStart)
rangeStart = utf8Offset;
@@ -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

View File

@@ -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);
int indentFor(const QTextBlock &block, int cursorPositionInEditor);
void indentBeforeCursor(const QTextBlock &block,
void indentBlocks(const QTextBlock &startBlock,
const QTextBlock &endBlock,
const QChar &typedChar,
int cursorPositionInEditor);
int indentFor(const QTextBlock &block, 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;

View File

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

View File

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

View File

@@ -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));
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,
void FixitsRefactoringFile::format(TextEditor::Indenter &indenter,
QTextDocument *doc,
const ReplacementOperation &op,
int currentIndex)
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

View File

@@ -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,
void format(TextEditor::Indenter &indenter,
QTextDocument *doc,
const ReplacementOperation &op,
int currentIndex);
const ReplacementOperations &operationsForFile,
int firstOperationIndex);
void shiftAffectedReplacements(const QString &fileName,
const TextEditor::Replacements &replacements,
int startIndex);

View File

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

View File

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

View File

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

View File

@@ -446,47 +446,40 @@ 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 (editedRange.first != -1)
formatRange(document(), indenter(), editedRange, tabSettings());
if (lastRange.startLine != -1)
editedRanges.push_back(lastRange);
if (!editedRanges.empty()) {
QTextCursor cursor(document());
cursor.joinPreviousEditBlock();
indenter()->format(editedRanges);
cursor.endEditBlock();
}
}
return TextEditor::TextDocument::save(errorString, fileName, autoSave);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -8085,11 +8085,20 @@ 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 {
if (d->m_contextHelpItem.isEmpty())
callback(fallbackWordUnderCursor);
else
callback(d->m_contextHelpItem);
}
}

View File

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

View File

@@ -119,7 +119,7 @@ IntroductionWidget::IntroductionWidget(QWidget *parent)
"<tr><td>Edit:</td><td>Work with code and navigate your project.</td></tr>"
"<tr><td>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>")},

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -25,6 +25,8 @@
#pragma once
#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

View File

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

View File

@@ -408,6 +408,60 @@ TEST_F(ClangFormat, IndentIfBodyAndFormatBeforeIt)
"}"));
}
TEST_F(ClangFormat, DoNotFormatAfterTheFirstColon)
{
insertLines({"{",
" Qt:",
"}"});
extendedIndenter.indentBlock(doc.findBlockByNumber(1), ':', TextEditor::TabSettings(), 9);
ASSERT_THAT(documentLines(), ElementsAre("{",
" Qt:",
"}"));
}
TEST_F(ClangFormat, OnlyIndentIncompleteStatementOnElectricalCharacter)
{
insertLines({"{bar();",
"foo()",
"}"});
extendedIndenter.indentBlock(doc.findBlockByNumber(1), '(', TextEditor::TabSettings(), 12);
ASSERT_THAT(documentLines(), ElementsAre("{bar();",
" foo()",
"}"));
}
TEST_F(ClangFormat, IndentAndFormatCompleteStatementOnSemicolon)
{
insertLines({"{bar();",
"foo();",
"}"});
extendedIndenter.indentBlock(doc.findBlockByNumber(1), ';', TextEditor::TabSettings(), 14);
ASSERT_THAT(documentLines(), ElementsAre("{",
" bar();",
" foo();",
"}"));
}
TEST_F(ClangFormat, IndentAndFormatCompleteStatementOnClosingScope)
{
insertLines({"{bar();",
"foo();",
"}"});
extendedIndenter.indentBlock(doc.findBlockByNumber(1), '}', TextEditor::TabSettings(), 16);
ASSERT_THAT(documentLines(), ElementsAre("{",
" bar();",
" foo();",
"}"));
}
TEST_F(ClangFormat, FormatBasicFile)
{
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>"));
}

View File

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

View File

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

View File

@@ -43,7 +43,7 @@ MATCHER_P(HasBuiltIn,
MATCHER_P(HasSystem,
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)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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