From 08e1fbbbfa8760e94922d69ab7397af64370081a Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 18 Feb 2019 14:22:39 +0100 Subject: [PATCH 01/12] qmake: add $$read_registry() function Fixes: QTCREATORBUG-21973 Written-by: Oswald Buddenhagen Reviewed-by: Simon Hausmann (cherry-picked from qtbase/f89ac0101ad4a6cb5339a3bfe132aad897eafc9d) Change-Id: I6f67eec7c715686074dd3bdc121170c26daf56da Reviewed-by: Joerg Bornemann --- src/plugins/qtsupport/qtsupport.qbs | 6 + src/shared/proparser/proparser.pri | 2 + src/shared/proparser/qmakebuiltins.cpp | 42 +++++- src/shared/proparser/registry.cpp | 158 +++++++++++++++++++++ src/shared/proparser/registry_p.h | 55 +++++++ tests/auto/profilewriter/profilewriter.qbs | 7 +- 6 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 src/shared/proparser/registry.cpp create mode 100644 src/shared/proparser/registry_p.h diff --git a/src/plugins/qtsupport/qtsupport.qbs b/src/plugins/qtsupport/qtsupport.qbs index d4a140b2aee..8be90315eb3 100644 --- a/src/plugins/qtsupport/qtsupport.qbs +++ b/src/plugins/qtsupport/qtsupport.qbs @@ -19,6 +19,10 @@ Project { "QMAKE_LIBRARY", "QMAKE_BUILTIN_PRFS", ]) + Properties { + condition: qbs.targetOS.contains("windows") + cpp.dynamicLibraries: "advapi32" + } Export { Depends { name: "ProParser" } @@ -48,6 +52,8 @@ Project { "qmakeparser.h", "qmakevfs.cpp", "qmakevfs.h", + "registry.cpp", + "registry_p.h", ] } diff --git a/src/shared/proparser/proparser.pri b/src/shared/proparser/proparser.pri index 53ab86cf575..5f02416ef7d 100644 --- a/src/shared/proparser/proparser.pri +++ b/src/shared/proparser/proparser.pri @@ -15,6 +15,7 @@ HEADERS += \ proitems.h \ prowriter.h \ qmakevfs.h \ + registry_p.h \ ioutils.h SOURCES += \ @@ -26,6 +27,7 @@ SOURCES += \ proitems.cpp \ prowriter.cpp \ qmakevfs.cpp \ + registry.cpp \ ioutils.cpp RESOURCES += proparser.qrc diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 096524e6dcd..ea7e308cc50 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -31,6 +31,10 @@ #include "qmakevfs.h" #include "ioutils.h" +#ifdef Q_OS_WIN +# include "registry_p.h" +#endif + #include #include #include @@ -88,7 +92,7 @@ enum ExpandFunc { E_UPPER, E_LOWER, E_TITLE, E_FILES, E_PROMPT, E_RE_ESCAPE, E_VAL_ESCAPE, E_REPLACE, E_SORT_DEPENDS, E_RESOLVE_DEPENDS, E_ENUMERATE_VARS, E_SHADOWED, E_ABSOLUTE_PATH, E_RELATIVE_PATH, E_CLEAN_PATH, - E_SYSTEM_PATH, E_SHELL_PATH, E_SYSTEM_QUOTE, E_SHELL_QUOTE, E_GETENV + E_SYSTEM_PATH, E_SHELL_PATH, E_SYSTEM_QUOTE, E_SHELL_QUOTE, E_GETENV, E_READ_REGISTRY, }; enum TestFunc { @@ -153,6 +157,7 @@ void QMakeEvaluator::initFunctionStatics() { "system_quote", E_SYSTEM_QUOTE }, { "shell_quote", E_SHELL_QUOTE }, { "getenv", E_GETENV }, + { "read_registry", E_READ_REGISTRY }, }; statics.expands.reserve((int)(sizeof(expandInits)/sizeof(expandInits[0]))); for (unsigned i = 0; i < sizeof(expandInits)/sizeof(expandInits[0]); ++i) @@ -1265,6 +1270,41 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( ret << val; } break; +#ifdef Q_OS_WIN + case E_READ_REGISTRY: { + HKEY tree; + const auto par = args.at(0); + if (!par.compare(QLatin1String("HKCU"), Qt::CaseInsensitive) + || !par.compare(QLatin1String("HKEY_CURRENT_USER"), Qt::CaseInsensitive)) { + tree = HKEY_CURRENT_USER; + } else if (!par.compare(QLatin1String("HKLM"), Qt::CaseInsensitive) + || !par.compare(QLatin1String("HKEY_LOCAL_MACHINE"), Qt::CaseInsensitive)) { + tree = HKEY_LOCAL_MACHINE; + } else { + evalError(fL1S("read_registry(): invalid or unsupported registry tree %1.") + .arg(par.toQString())); + goto rrfail; + } + int flags = 0; + if (args.count() > 2) { + const auto opt = args.at(2); + if (opt == "32" + || !opt.compare(QLatin1String("wow64_32key"), Qt::CaseInsensitive)) { + flags = KEY_WOW64_32KEY; + } else if (opt == "64" + || !opt.compare(QLatin1String("wow64_64key"), Qt::CaseInsensitive)) { + flags = KEY_WOW64_64KEY; + } else { + evalError(fL1S("read_registry(): invalid option %1.") + .arg(opt.toQString())); + goto rrfail; + } + } + ret << ProString(qt_readRegistryKey(tree, args.at(1).toQString(m_tmp1), flags)); + } + rrfail: + break; +#endif default: evalError(fL1S("Function '%1' is not implemented.").arg(func.toQString(m_tmp1))); break; diff --git a/src/shared/proparser/registry.cpp b/src/shared/proparser/registry.cpp new file mode 100644 index 00000000000..960b6f8e580 --- /dev/null +++ b/src/shared/proparser/registry.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the qmake application of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "registry_p.h" + +namespace QMakeInternal { + +#ifdef Q_OS_WIN32 +/* + Returns the path part of a registry key. + e.g. + For a key + "Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\ProductDir" + it returns + "Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\" +*/ +static QString keyPath(const QString &rKey) +{ + int idx = rKey.lastIndexOf(QLatin1Char('\\')); + if (idx == -1) + return QString(); + return rKey.left(idx + 1); +} + +/* + Returns the name part of a registry key. + e.g. + For a key + "Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\ProductDir" + it returns + "ProductDir" +*/ +static QString keyName(const QString &rKey) +{ + int idx = rKey.lastIndexOf(QLatin1Char('\\')); + if (idx == -1) + return rKey; + + QString res(rKey.mid(idx + 1)); + if (res == QLatin1String("Default") || res == QLatin1String(".")) + res = QString(); + return res; +} +#endif + +QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey, unsigned long options) +{ + QString result; + +#ifdef Q_OS_WIN32 + QString rSubkeyName = keyName(rSubkey); + QString rSubkeyPath = keyPath(rSubkey); + + HKEY handle = nullptr; + LONG res = RegOpenKeyEx(parentHandle, (wchar_t*)rSubkeyPath.utf16(), 0, + KEY_READ | options, &handle); + + if (res != ERROR_SUCCESS) + return QString(); + + // get the size and type of the value + DWORD dataType; + DWORD dataSize; + res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), nullptr, &dataType, nullptr, &dataSize); + if (res != ERROR_SUCCESS) { + RegCloseKey(handle); + return QString(); + } + + // get the value + QByteArray data(dataSize, 0); + res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), nullptr, nullptr, + reinterpret_cast(data.data()), &dataSize); + if (res != ERROR_SUCCESS) { + RegCloseKey(handle); + return QString(); + } + + switch (dataType) { + case REG_EXPAND_SZ: + case REG_SZ: { + result = QString::fromWCharArray(((const wchar_t *)data.constData())); + break; + } + + case REG_MULTI_SZ: { + QStringList l; + int i = 0; + for (;;) { + QString s = QString::fromWCharArray((const wchar_t *)data.constData() + i); + i += s.length() + 1; + + if (s.isEmpty()) + break; + l.append(s); + } + result = l.join(QLatin1String(", ")); + break; + } + + case REG_NONE: + case REG_BINARY: { + result = QString::fromWCharArray((const wchar_t *)data.constData(), data.size() / 2); + break; + } + + case REG_DWORD_BIG_ENDIAN: + case REG_DWORD: { + Q_ASSERT(data.size() == sizeof(int)); + int i; + memcpy((char*)&i, data.constData(), sizeof(int)); + result = QString::number(i); + break; + } + + default: + qWarning("QSettings: unknown data %u type in windows registry", quint32(dataType)); + break; + } + + RegCloseKey(handle); +#else + Q_UNUSED(parentHandle); + Q_UNUSED(rSubkey) + Q_UNUSED(options); +#endif + + return result; +} + +} // namespace QMakeInternal + diff --git a/src/shared/proparser/registry_p.h b/src/shared/proparser/registry_p.h new file mode 100644 index 00000000000..8defcbae959 --- /dev/null +++ b/src/shared/proparser/registry_p.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 + +#ifdef Q_OS_WIN32 + #include +#else + typedef void* HKEY; +#endif + +#include + +namespace QMakeInternal { + +/** + * Read a value from the Windows registry. + * + * If the key is not found, or the registry cannot be accessed (for example + * if this code is compiled for a platform other than Windows), a null + * string is returned. + * + * 32-bit code reads from the registry's 32 bit view (Wow6432Node), + * 64 bit code reads from the 64 bit view. + * Pass KEY_WOW64_32KEY to access the 32 bit view regardless of the + * application's architecture, KEY_WOW64_64KEY respectively. + */ +QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey, + unsigned long options = 0); + +} // namespace QMakeInternal diff --git a/tests/auto/profilewriter/profilewriter.qbs b/tests/auto/profilewriter/profilewriter.qbs index 7091472f308..a6fb8ca8794 100644 --- a/tests/auto/profilewriter/profilewriter.qbs +++ b/tests/auto/profilewriter/profilewriter.qbs @@ -18,7 +18,8 @@ QtcAutotest { "qmakeevaluator.h", "qmakeevaluator_p.h", "qmakeevaluator.cpp", "qmakeglobals.h", "qmakeglobals.cpp", "qmakeparser.h", "qmakeparser.cpp", - "qmakevfs.h", "qmakevfs.cpp" + "qmakevfs.h", "qmakevfs.cpp", + "registry_p.h", "registry.cpp", ] } Group { @@ -27,4 +28,8 @@ QtcAutotest { } cpp.includePaths: base.concat([proParserGroup.prefix]) cpp.defines: base.concat("QT_USE_FAST_OPERATOR_PLUS") + Properties { + condition: qbs.targetOS.contains("windows") + cpp.dynamicLibraries: "advapi32" + } } From be65a57935badcc19f844b36ccf1456f2000a96d Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Tue, 19 Feb 2019 12:46:38 +0100 Subject: [PATCH 02/12] ClangFormat: Fix unit-tests Amends dcf763c7ee. Change the logic in empty lines modification to properly indent all empty lines. Change-Id: Id945cf66915dfd192216660543594a7905426761 Reviewed-by: Marco Bubke --- .../clangformat/clangformatbaseindenter.cpp | 139 ++++++++++-------- .../clangformat/clangformatbaseindenter.h | 2 +- tests/unit/unittest/clangformat-test.cpp | 52 +++++-- 3 files changed, 119 insertions(+), 74 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 6d06b058122..da36731796a 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -39,7 +39,7 @@ namespace ClangFormat { static void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style, ReplacementsToKeep replacementsToKeep) { - style.MaxEmptyLinesToKeep = 2; + style.MaxEmptyLinesToKeep = 100; style.SortIncludes = false; style.SortUsingDeclarations = false; @@ -68,7 +68,6 @@ static clang::tooling::Replacements filteredReplacements( const clang::tooling::Replacements &replacements, int utf8Offset, int utf8Length, - int extraEmptySpaceOffset, ReplacementsToKeep replacementsToKeep) { clang::tooling::Replacements filtered; @@ -81,9 +80,6 @@ static clang::tooling::Replacements filteredReplacements( if (replacementDoesNotMatchRestriction) continue; - if (replacementOffset >= utf8Offset - 1) - replacementOffset += extraEmptySpaceOffset; - llvm::StringRef text = replacementsToKeep == ReplacementsToKeep::OnlyIndent ? clearExtraNewline(replacement.getReplacementText()) : replacement.getReplacementText(); @@ -147,18 +143,23 @@ static int previousEmptyLinesLength(const QTextBlock ¤tBlock) return length; } -static void modifyToIndentEmptyLines( - QByteArray &buffer, int utf8Offset, const QTextBlock &block, bool secondTry) +static int modifyToIndentEmptyLines(QByteArray &buffer, const QTextBlock &block, bool secondTry) { const QString blockText = block.text(); int firstNonWhitespace = Utils::indexOf(blockText, [](const QChar &ch) { return !ch.isSpace(); }); + int utf8Offset = Utils::Text::utf8NthLineOffset(block.document(), + buffer, + block.blockNumber() + 1); if (firstNonWhitespace > 0) utf8Offset += firstNonWhitespace; + else + utf8Offset += blockText.length(); const bool closingParenBlock = firstNonWhitespace >= 0 && blockText.at(firstNonWhitespace) == ')'; + int extraLength = 0; if (firstNonWhitespace < 0 || closingParenBlock) { //This extra text works for the most cases. QByteArray dummyText("a;a;"); @@ -174,6 +175,7 @@ static void modifyToIndentEmptyLines( dummyText = "&& a"; buffer.insert(utf8Offset, dummyText); + extraLength += dummyText.length(); } if (secondTry) { @@ -186,52 +188,61 @@ static void modifyToIndentEmptyLines( // unclosed parentheses. // TODO: Does it help to add different endings depending on the context? buffer.insert(nextLinePos, ')'); + extraLength += 1; } } + + return extraLength; } -static Utils::LineColumn utf16LineColumn(const QTextBlock &block, - int blockOffsetUtf8, - const QByteArray &utf8Buffer, - int utf8Offset) +static Utils::LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset) { - // If lastIndexOf('\n') returns -1 then we are fine to add 1 and get 0 offset. - const int lineStartUtf8Offset = utf8Offset == 0 - ? 0 - : utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1; - int line = block.blockNumber() + 1; // Init with the line corresponding the block. - - if (utf8Offset < blockOffsetUtf8) { - line -= static_cast(std::count(utf8Buffer.begin() + lineStartUtf8Offset, - utf8Buffer.begin() + blockOffsetUtf8, - '\n')); - } else { - line += static_cast(std::count(utf8Buffer.begin() + blockOffsetUtf8, - utf8Buffer.begin() + lineStartUtf8Offset, - '\n')); - } - - const QByteArray lineText = utf8Buffer.mid(lineStartUtf8Offset, - utf8Offset - lineStartUtf8Offset); - return Utils::LineColumn(line, QString::fromUtf8(lineText).size() + 1); + Utils::LineColumn lineColumn; + lineColumn.line = std::count(utf8Buffer.begin(), utf8Buffer.begin() + utf8Offset, '\n') + 1; + lineColumn.column = utf8Offset - utf8Buffer.lastIndexOf('\n', utf8Offset - 1); + return lineColumn; } -static TextEditor::Replacements utf16Replacements(const QTextBlock &block, - int blockOffsetUtf8, +static QString utf16LineLengthInUtf8Buffer(const QByteArray &utf8Buffer, int currentUtf8Offset) +{ + const int lineStartUtf8Offset = utf8Buffer.lastIndexOf('\n', currentUtf8Offset - 1) + 1; + const int lineEndUtf8Offset = utf8Buffer.indexOf('\n', currentUtf8Offset); + return QString::fromUtf8( + utf8Buffer.mid(lineStartUtf8Offset, lineEndUtf8Offset - lineStartUtf8Offset)); +} + +static bool isInsideModifiedLine(const QString &originalLine, + const QString &modifiedLine, + int column) +{ + // Track the cases when we have inserted extra text into the line to get the indentation. + return originalLine.length() < modifiedLine.length() && column != modifiedLine.length() + 1 + && (column > originalLine.length() || originalLine.trimmed().isEmpty() + || !modifiedLine.startsWith(originalLine)); +} + +static TextEditor::Replacements utf16Replacements(const QTextDocument *doc, const QByteArray &utf8Buffer, const clang::tooling::Replacements &replacements) { TextEditor::Replacements convertedReplacements; convertedReplacements.reserve(replacements.size()); + for (const clang::tooling::Replacement &replacement : replacements) { - const Utils::LineColumn lineColUtf16 = utf16LineColumn(block, - blockOffsetUtf8, - utf8Buffer, - static_cast( - replacement.getOffset())); + Utils::LineColumn lineColUtf16 = utf16LineColumn(utf8Buffer, + static_cast(replacement.getOffset())); if (!lineColUtf16.isValid()) continue; - const int utf16Offset = Utils::Text::positionInText(block.document(), + + const QString lineText = doc->findBlockByNumber(lineColUtf16.line - 1).text(); + const QString bufferLineText = utf16LineLengthInUtf8Buffer(utf8Buffer, + replacement.getOffset()); + if (isInsideModifiedLine(lineText, bufferLineText, lineColUtf16.column)) + continue; + + lineColUtf16.column = std::min(lineColUtf16.column, lineText.length() + 1); + + const int utf16Offset = Utils::Text::positionInText(doc, lineColUtf16.line, lineColUtf16.column); const int utf16Length = QString::fromUtf8( @@ -270,14 +281,11 @@ static QString selectedLines(QTextDocument *doc, const QTextBlock &startBlock, const QTextBlock &endBlock) { - QString text = Utils::Text::textAt(QTextCursor(doc), - startBlock.position(), - std::max(0, - endBlock.position() + endBlock.length() - - startBlock.position() - 1)); - while (!text.isEmpty() && text.rbegin()->isSpace()) - text.chop(1); - return text; + return Utils::Text::textAt(QTextCursor(doc), + startBlock.position(), + std::max(0, + endBlock.position() + endBlock.length() + - startBlock.position() - 1)); } ClangFormatBaseIndenter::ClangFormatBaseIndenter(QTextDocument *doc) @@ -358,10 +366,7 @@ TextEditor::Replacements ClangFormatBaseIndenter::format( 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); + const TextEditor::Replacements toReplace = utf16Replacements(m_doc, buffer, clangReplacements); applyReplacements(m_doc, toReplace); return toReplace; @@ -392,7 +397,7 @@ static bool doNotIndentInContext(QTextDocument *doc, int pos) return false; } -void ClangFormatBaseIndenter::indentBlocks(const QTextBlock &startBlock, +void ClangFormatBaseIndenter::indentBlocks(QTextBlock startBlock, const QTextBlock &endBlock, const QChar &typedChar, int cursorPositionInEditor) @@ -403,6 +408,15 @@ void ClangFormatBaseIndenter::indentBlocks(const QTextBlock &startBlock, return; } + if (startBlock.position() > 0) { + startBlock = startBlock.previous(); + while (startBlock.position() > 0 && startBlock.text().trimmed().isEmpty()) + startBlock = startBlock.previous(); + if (!startBlock.text().trimmed().isEmpty()) { + startBlock = startBlock.next(); + } + } + const int startBlockPosition = startBlock.position(); trimFirstNonEmptyBlock(startBlock); if (cursorPositionInEditor >= 0) @@ -564,22 +578,20 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer 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; - } - if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) { buffer.insert(utf8Offset - 1, " //"); - extraEmptySpaceOffset -= 3; utf8Offset += 3; } + adjustFormatStyleForLineBreak(style, replacementsToKeep); + if (typedChar == QChar::Null) { + for (int index = startBlock.blockNumber(); index <= endBlock.blockNumber(); ++index) { + utf8Length += modifyToIndentEmptyLines(buffer, + m_doc->findBlockByNumber(index), + secondTry); + } + } + if (replacementsToKeep != ReplacementsToKeep::IndentAndBefore || utf8Offset < rangeStart) rangeStart = utf8Offset; @@ -601,7 +613,6 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer clangReplacements, utf8Offset, utf8Length, - extraEmptySpaceOffset, replacementsToKeep); } const bool canTryAgain = replacementsToKeep == ReplacementsToKeep::OnlyIndent @@ -617,7 +628,7 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer true); } - return utf16Replacements(startBlock, originalOffsetUtf8, originalBuffer, filtered); + return utf16Replacements(m_doc, buffer, filtered); } } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatbaseindenter.h b/src/plugins/clangformat/clangformatbaseindenter.h index 272cbd648fd..360f27fbedc 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.h +++ b/src/plugins/clangformat/clangformatbaseindenter.h @@ -75,7 +75,7 @@ protected: private: void indent(const QTextCursor &cursor, const QChar &typedChar, int cursorPositionInEditor); - void indentBlocks(const QTextBlock &startBlock, + void indentBlocks(QTextBlock startBlock, const QTextBlock &endBlock, const QChar &typedChar, int cursorPositionInEditor); diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp index ea702f71a6e..c0ff7dcd2ce 100644 --- a/tests/unit/unittest/clangformat-test.cpp +++ b/tests/unit/unittest/clangformat-test.cpp @@ -331,6 +331,40 @@ TEST_F(ClangFormat, NoExtraIndentAfterBraceInitialization) "return 0;")); } +TEST_F(ClangFormat, IndentMultipleEmptyLines) +{ + insertLines({"{", + "", + "", + "", + "}"}); + + indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("{", + " ", + " ", + " ", + "}")); +} + +TEST_F(ClangFormat, IndentEmptyLineAndKeepPreviousEmptyLines) +{ + insertLines({"{", + " ", + " ", + "", + "}"}); + + indenter.indentBlock(doc.findBlockByNumber(3), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("{", + " ", + " ", + " ", + "}")); +} + TEST_F(ClangFormat, IndentFunctionBodyAndFormatBeforeIt) { insertLines({"int foo(int a, int b,", @@ -469,7 +503,7 @@ TEST_F(ClangFormat, FormatBasicFile) "int a;", "}"}); - indenter.format(cursor); + indenter.format({{1, 4}}); ASSERT_THAT(documentLines(), ElementsAre("int main()", "{", @@ -484,7 +518,7 @@ TEST_F(ClangFormat, FormatEmptyLine) "", "}"}); - indenter.format(cursor); + indenter.format({{1, 4}}); ASSERT_THAT(documentLines(), ElementsAre("int main() {}")); } @@ -495,7 +529,7 @@ TEST_F(ClangFormat, FormatLambda) "", "});"}); - indenter.format(cursor); + indenter.format({{1, 3}}); ASSERT_THAT(documentLines(), ElementsAre("int b = foo([]() {", "", @@ -508,7 +542,7 @@ TEST_F(ClangFormat, FormatInitializerListInArguments) "args,", "{1, 2});"}); - indenter.format(cursor); + indenter.format({{1, 3}}); ASSERT_THAT(documentLines(), ElementsAre("foo(arg1, args, {1, 2});")); } @@ -520,7 +554,7 @@ TEST_F(ClangFormat, FormatFunctionArgumentLambdaWithScope) "", "});"}); - indenter.format(cursor); + indenter.format({{1, 4}}); ASSERT_THAT(documentLines(), ElementsAre("foo([]() {", @@ -535,7 +569,7 @@ TEST_F(ClangFormat, FormatScopeAsFunctionArgument) "", "});"}); - indenter.format(cursor); + indenter.format({{1, 4}}); ASSERT_THAT(documentLines(), ElementsAre("foo({", @@ -548,7 +582,7 @@ TEST_F(ClangFormat, FormatStructuredBinding) insertLines({"auto [a,", "b] = c;"}); - indenter.format(cursor); + indenter.format({{1, 2}}); ASSERT_THAT(documentLines(), ElementsAre("auto [a, b] = c;")); } @@ -558,7 +592,7 @@ TEST_F(ClangFormat, FormatStringLiteralContinuation) insertLines({"foo(bar, \"foo\"", "\"bar\");"}); - indenter.format(cursor); + indenter.format({{1, 2}}); ASSERT_THAT(documentLines(), ElementsAre("foo(bar,", " \"foo\"", @@ -571,7 +605,7 @@ TEST_F(ClangFormat, FormatTemplateparameters) "B,", "C>"}); - indenter.format(cursor); + indenter.format({{1, 3}}); ASSERT_THAT(documentLines(), ElementsAre("using Alias = Template")); } From bfee82fa2c3509214332f97cfcc1d8a776fb4f8e Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 19 Feb 2019 12:50:49 +0100 Subject: [PATCH 03/12] Debugger: Add dumper for QSizePolicy Change-Id: Ib4d2597229f2808fcf79e76a9590b0e07989bfb9 Reviewed-by: hjk Reviewed-by: Christian Stenger --- share/qtcreator/debugger/dumper.py | 11 +++++++++-- share/qtcreator/debugger/qttypes.py | 27 ++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 2d2cba492cd..e1d04a03f79 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -833,6 +833,14 @@ class DumperBase: self.putType('int') self.putNumChild(0) + def putEnumItem(self, name, ival, typish): + buf = bytearray(struct.pack('i', ival)) + val = self.Value(self) + val.ldata = bytes(buf) + val.type = self.createType(typish) + with SubItem(self, name): + self.putItem(val) + def putBoolItem(self, name, value): with SubItem(self, name): self.putValue(value) @@ -855,8 +863,7 @@ class DumperBase: self.putField('keyencoded', key.encoding) self.putValue(value.value, value.encoding) - def putEnumValue(self, value, vals): - ival = value.integer() + def putEnumValue(self, ival, vals): nice = vals.get(ival, None) display = ('%d' % ival) if nice is None else ('%s (%d)' % (nice, ival)) self.putValue(display) diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index 2901c104010..91e38feaacc 100644 --- a/share/qtcreator/debugger/qttypes.py +++ b/share/qtcreator/debugger/qttypes.py @@ -194,7 +194,7 @@ def qdump_X_QModelIndex(d, value): #gdb.execute('call free($mi)') def qdump__Qt__ItemDataRole(d, value): - d.putEnumValue(value, { + d.putEnumValue(value.integer(), { 0 : "Qt::DisplayRole", 1 : "Qt::DecorationRole", 2 : "Qt::EditRole", @@ -1412,6 +1412,31 @@ def qdump__QSizeF(d, value): d.putPlainChildren(value) +def qdump__QSizePolicy__Policy(d, value): + d.putEnumValue(value.integer(), { + 0 : 'QSizePolicy::Fixed', + 1 : 'QSizePolicy::GrowFlag', + 2 : 'QSizePolicy::ExpandFlag', + 3 : 'QSizePolicy::MinimumExpanding (GrowFlag|ExpandFlag)', + 4 : 'QSizePolicy::ShrinkFlag', + 5 : 'QSizePolicy::Preferred (GrowFlag|ShrinkFlag)', + 7 : 'QSizePolicy::Expanding (GrowFlag|ShrinkFlag|ExpandFlag)', + 8 : 'QSizePolicy::IgnoreFlag', + 13 : 'QSizePolicy::Ignored (ShrinkFlag|GrowFlag|IgnoreFlag)', + }) + +def qdump__QSizePolicy(d, value): + bits = value.integer() + d.putEmptyValue(-99) + d.putNumChild(1) + if d.isExpanded(): + with Children(d): + d.putIntItem('horStretch', (bits >> 0) & 0xff) + d.putIntItem('verStretch', (bits >> 8) & 0xff) + d.putEnumItem('horPolicy', (bits >> 16) & 0xf, "QSizePolicy::Policy") + d.putEnumItem('verPolicy', (bits >> 20) & 0xf, "QSizePolicy::Policy") + + def qform__QStack(): return arrayForms() From caf675542613c3d8cd2a749a76a3fa2fa2395aee Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 19 Feb 2019 14:13:36 +0100 Subject: [PATCH 04/12] ClangPchManager: Optimize UsedMacroFilter We need only run one time over all elements. Change-Id: I98061014380874549b1976fe6d6a32af43fedfea Reviewed-by: Ivan Donchevskii --- .../source/usedmacrofilter.h | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h index fe08cf71ac9..6042895325a 100644 --- a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h +++ b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h @@ -53,6 +53,29 @@ inline OutputIterator set_greedy_intersection(InputIterator1 first1, return result; } +template +inline OutputIterator fill_with_second_values(InputIterator1 first1, + InputIterator1 last1, + InputIterator2 first2, + InputIterator2 last2, + OutputIterator result, + Compare comp) +{ + while (first1 != last1 && first2 != last2) + if (comp(*first1, *first2)) { + *result = *first1; + ++first1; + ++result; + } else if (comp(*first2, *first1)) + ++first2; + else { + *result = *first2; + ++first1; + ++result; + } + return result; +} + class UsedMacroFilter { public: @@ -160,7 +183,7 @@ private: const Utils::SmallStringVector &usedMacros) { CompilerMacros filtertedCompilerMacros; - filtertedCompilerMacros.reserve(indexedCompilerMacro.size() + usedMacros.size()); + filtertedCompilerMacros.reserve(usedMacros.size()); struct Compare { @@ -175,24 +198,13 @@ private: } }; - set_greedy_intersection(indexedCompilerMacro.begin(), - indexedCompilerMacro.end(), - usedMacros.begin(), + fill_with_second_values(usedMacros.begin(), usedMacros.end(), + indexedCompilerMacro.begin(), + indexedCompilerMacro.end(), std::back_inserter(filtertedCompilerMacros), Compare{}); - auto split = filtertedCompilerMacros.end(); - - std::set_difference(usedMacros.begin(), - usedMacros.end(), - filtertedCompilerMacros.begin(), - filtertedCompilerMacros.end(), - std::back_inserter(filtertedCompilerMacros), - Compare{}); - - std::inplace_merge(filtertedCompilerMacros.begin(), split, filtertedCompilerMacros.end()); - return filtertedCompilerMacros; } From 0f8612f20fba99c8dddbdd1d089756dca0255d9f Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Wed, 6 Feb 2019 16:17:03 +0100 Subject: [PATCH 05/12] Clang: Move unexported classes to Internal Change-Id: I3ea197b734f146d4b11431aaf927aed9be7d8756 Reviewed-by: Orgad Shaneh Reviewed-by: Ivan Donchevskii --- .../clangcodemodel/clangcurrentdocumentfilter.cpp | 3 ++- .../clangcodemodel/clangcurrentdocumentfilter.h | 2 ++ .../clangdiagnostictooltipwidget.cpp | 3 ++- .../clangcodemodel/clangeditordocumentparser.cpp | 2 ++ .../clangcodemodel/clangeditordocumentparser.h | 2 ++ .../clangcodemodel/clangfixitoperation.cpp | 5 +++-- src/plugins/clangcodemodel/clangfixitoperation.h | 5 +++-- .../clangfixitoperationsextractor.cpp | 2 ++ .../clangfixitoperationsextractor.h | 2 ++ .../clanghighlightingresultreporter.cpp | 2 ++ .../clanghighlightingresultreporter.h | 2 ++ .../clangpreprocessorassistproposalitem.cpp | 2 ++ .../clangpreprocessorassistproposalitem.h | 2 ++ .../clangcodemodel/clangrefactoringengine.cpp | 8 +++++--- .../clangcodemodel/clangrefactoringengine.h | 2 ++ src/plugins/clangcodemodel/clangtextmark.cpp | 4 ++-- src/plugins/clangcodemodel/clangtextmark.h | 2 ++ tests/unit/unittest/clangfixitoperation-test.cpp | 2 +- .../unittest/highlightingresultreporter-test.cpp | 15 ++++++++------- 19 files changed, 48 insertions(+), 19 deletions(-) diff --git a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp index 951c6efd530..702d4557b6b 100644 --- a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp +++ b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp @@ -48,6 +48,7 @@ #include namespace ClangCodeModel { +namespace Internal { ClangCurrentDocumentFilter::ClangCurrentDocumentFilter() { @@ -108,7 +109,6 @@ QList ClangCurrentDocumentFilter::matchesFor( if (!regexp.isValid()) return goodEntries; - using Internal::ClangEditorDocumentProcessor; ClangEditorDocumentProcessor *processor = ClangEditorDocumentProcessor::get(m_currentPath); if (!processor) return goodEntries; @@ -170,4 +170,5 @@ void ClangCurrentDocumentFilter::onCurrentEditorChanged(Core::IEditor *newCurren reset(); } +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h index e355862bdf2..891905fbda0 100644 --- a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h +++ b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h @@ -30,6 +30,7 @@ namespace Core { class IEditor; } namespace ClangCodeModel { +namespace Internal { class ClangCurrentDocumentFilter : public Core::ILocatorFilter { @@ -53,4 +54,5 @@ private: QString m_currentPath; }; +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp index af8c13e76d1..f2e52c1fd0e 100644 --- a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp +++ b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp @@ -46,6 +46,7 @@ using namespace ClangCodeModel; using Internal::ClangDiagnosticWidget; +using Internal::ClangFixItOperation; namespace { @@ -87,7 +88,7 @@ void openEditorAt(const ClangBackEnd::DiagnosticContainer &diagnostic) void applyFixit(const ClangBackEnd::DiagnosticContainer &diagnostic) { - ClangCodeModel::ClangFixItOperation operation(Utf8String(), diagnostic.fixIts); + ClangFixItOperation operation(Utf8String(), diagnostic.fixIts); operation.perform(); } diff --git a/src/plugins/clangcodemodel/clangeditordocumentparser.cpp b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp index 0d4195c538f..b892f393648 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentparser.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp @@ -26,6 +26,7 @@ #include "clangeditordocumentparser.h" namespace ClangCodeModel { +namespace Internal { ClangEditorDocumentParser::ClangEditorDocumentParser(const QString &filePath) : BaseEditorDocumentParser(filePath) @@ -46,4 +47,5 @@ void ClangEditorDocumentParser::updateImpl(const QFutureInterface &, setState(state_); } +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangeditordocumentparser.h b/src/plugins/clangcodemodel/clangeditordocumentparser.h index 28dd52a46a9..a5b2ff27bfe 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentparser.h +++ b/src/plugins/clangcodemodel/clangeditordocumentparser.h @@ -28,6 +28,7 @@ #include namespace ClangCodeModel { +namespace Internal { class ClangEditorDocumentParser : public CppTools::BaseEditorDocumentParser { @@ -41,4 +42,5 @@ private: const UpdateParams &updateParams) override; }; +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangfixitoperation.cpp b/src/plugins/clangcodemodel/clangfixitoperation.cpp index b123c9af457..a7170dc8817 100644 --- a/src/plugins/clangcodemodel/clangfixitoperation.cpp +++ b/src/plugins/clangcodemodel/clangfixitoperation.cpp @@ -32,6 +32,7 @@ #include namespace ClangCodeModel { +namespace Internal { using FileToFixits = QMap>; using FileToFixitsIterator = QMapIterator>; @@ -50,7 +51,7 @@ int ClangFixItOperation::priority() const return 10; } -QString ClangCodeModel::ClangFixItOperation::description() const +QString ClangFixItOperation::description() const { return QStringLiteral("Apply Fix: ") + fixItText.toString(); } @@ -120,5 +121,5 @@ Utils::ChangeSet ClangFixItOperation::toChangeSet( return changeSet; } +} // namespace Internal } // namespace ClangCodeModel - diff --git a/src/plugins/clangcodemodel/clangfixitoperation.h b/src/plugins/clangcodemodel/clangfixitoperation.h index 4f37f3d4793..7caf0cf6523 100644 --- a/src/plugins/clangcodemodel/clangfixitoperation.h +++ b/src/plugins/clangcodemodel/clangfixitoperation.h @@ -34,13 +34,13 @@ #include #include -namespace TextEditor -{ +namespace TextEditor { class RefactoringChanges; class RefactoringFile; } namespace ClangCodeModel { +namespace Internal { class ClangFixItOperation : public TextEditor::QuickFixOperation { @@ -67,4 +67,5 @@ private: QVector fixItContainers; }; +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangfixitoperationsextractor.cpp b/src/plugins/clangcodemodel/clangfixitoperationsextractor.cpp index 8ec6496794e..981a679a9bc 100644 --- a/src/plugins/clangcodemodel/clangfixitoperationsextractor.cpp +++ b/src/plugins/clangcodemodel/clangfixitoperationsextractor.cpp @@ -72,6 +72,7 @@ bool hasFixItAt(const QVector &fixits, } // anonymous namespace namespace ClangCodeModel { +namespace Internal { ClangFixItOperationsExtractor::ClangFixItOperationsExtractor( const QVector &diagnosticContainers) @@ -114,4 +115,5 @@ void ClangFixItOperationsExtractor::extractFromDiagnostic( } } +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangfixitoperationsextractor.h b/src/plugins/clangcodemodel/clangfixitoperationsextractor.h index ee2da9a4b21..77b5643f8b3 100644 --- a/src/plugins/clangcodemodel/clangfixitoperationsextractor.h +++ b/src/plugins/clangcodemodel/clangfixitoperationsextractor.h @@ -30,6 +30,7 @@ #include namespace ClangCodeModel { +namespace Internal { class ClangFixItOperationsExtractor { @@ -50,4 +51,5 @@ private: TextEditor::QuickFixOperations operations; }; +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp b/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp index 27eeea1af4a..46bdbc33ea5 100644 --- a/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp +++ b/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp @@ -144,6 +144,7 @@ TextEditor::HighlightingResult toHighlightingResult( } // anonymous namespace ClangCodeModel { +namespace Internal { HighlightingResultReporter::HighlightingResultReporter( const QVector &tokenInfos) @@ -219,4 +220,5 @@ QFuture HighlightingResultReporter::start() return future; } +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clanghighlightingresultreporter.h b/src/plugins/clangcodemodel/clanghighlightingresultreporter.h index 0f57bc10d8e..2c6e7a89a84 100644 --- a/src/plugins/clangcodemodel/clanghighlightingresultreporter.h +++ b/src/plugins/clangcodemodel/clanghighlightingresultreporter.h @@ -35,6 +35,7 @@ #include namespace ClangCodeModel { +namespace Internal { class HighlightingResultReporter: public QObject, @@ -67,4 +68,5 @@ private: unsigned m_flushLine = 0; }; +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.cpp b/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.cpp index 07fdaba9e54..72c6c2dd09c 100644 --- a/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.cpp +++ b/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.cpp @@ -30,6 +30,7 @@ #include namespace ClangCodeModel { +namespace Internal { bool ClangPreprocessorAssistProposalItem::prematurelyApplies(const QChar &typedCharacter) const { @@ -156,4 +157,5 @@ bool ClangPreprocessorAssistProposalItem::isInclude() const || m_completionOperator == CPlusPlus::T_ANGLE_STRING_LITERAL; } +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.h b/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.h index cbdb5383b04..1a5ee440a0d 100644 --- a/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.h +++ b/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.h @@ -31,6 +31,7 @@ #include namespace ClangCodeModel { +namespace Internal { class ClangPreprocessorAssistProposalItem final : public TextEditor::AssistProposalItemInterface { @@ -68,4 +69,5 @@ private: mutable QChar m_typedCharacter; }; +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangrefactoringengine.cpp b/src/plugins/clangcodemodel/clangrefactoringengine.cpp index bb985a650e4..ed9af84d660 100644 --- a/src/plugins/clangcodemodel/clangrefactoringengine.cpp +++ b/src/plugins/clangcodemodel/clangrefactoringengine.cpp @@ -30,13 +30,14 @@ #include namespace ClangCodeModel { +namespace Internal { void RefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &data, CppTools::ProjectPart *, RenameCallback &&renameSymbolsCallback) { - Internal::ClangEditorDocumentProcessor *processor = Internal::ClangEditorDocumentProcessor::get( - data.filePath().toString()); + ClangEditorDocumentProcessor *processor = ClangEditorDocumentProcessor::get( + data.filePath().toString()); const int startRevision = data.cursor().document()->revision(); using ClangBackEnd::SourceLocationsContainer; @@ -79,4 +80,5 @@ void RefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &data, m_watcher->setFuture(cursorFuture); } -} +} // namespace Internal +} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangrefactoringengine.h b/src/plugins/clangcodemodel/clangrefactoringengine.h index 79537f24df5..297c8ff2387 100644 --- a/src/plugins/clangcodemodel/clangrefactoringengine.h +++ b/src/plugins/clangcodemodel/clangrefactoringengine.h @@ -36,6 +36,7 @@ class RefactoringServerInterface; } namespace ClangCodeModel { +namespace Internal { class RefactoringEngine : public CppTools::RefactoringEngineInterface { @@ -60,4 +61,5 @@ private: std::unique_ptr m_watcher; }; +} // namespace Internal } // namespace ClangRefactoring diff --git a/src/plugins/clangcodemodel/clangtextmark.cpp b/src/plugins/clangcodemodel/clangtextmark.cpp index 61a4c7716c6..ddeb8623663 100644 --- a/src/plugins/clangcodemodel/clangtextmark.cpp +++ b/src/plugins/clangcodemodel/clangtextmark.cpp @@ -51,6 +51,7 @@ using namespace Utils; namespace ClangCodeModel { +namespace Internal { namespace { @@ -228,8 +229,6 @@ void ClangTextMark::updateIcon(bool valid) bool ClangTextMark::addToolTipContent(QLayout *target) const { - using Internal::ClangDiagnosticWidget; - QWidget *widget = ClangDiagnosticWidget::createWidget({m_diagnostic}, ClangDiagnosticWidget::ToolTip); target->addWidget(widget); @@ -243,5 +242,6 @@ void ClangTextMark::removedFromEditor() m_removedFromEditorHandler(this); } +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangtextmark.h b/src/plugins/clangcodemodel/clangtextmark.h index 00cadfb5c82..ae67bcef864 100644 --- a/src/plugins/clangcodemodel/clangtextmark.h +++ b/src/plugins/clangcodemodel/clangtextmark.h @@ -33,6 +33,7 @@ #include namespace ClangCodeModel { +namespace Internal { class ClangTextMark : public TextEditor::TextMark { @@ -56,4 +57,5 @@ private: RemovedFromEditorHandler m_removedFromEditorHandler; }; +} // namespace Internal } // namespace ClangCodeModel diff --git a/tests/unit/unittest/clangfixitoperation-test.cpp b/tests/unit/unittest/clangfixitoperation-test.cpp index 21b250fdebb..e8fa178014b 100644 --- a/tests/unit/unittest/clangfixitoperation-test.cpp +++ b/tests/unit/unittest/clangfixitoperation-test.cpp @@ -34,7 +34,7 @@ #include using ClangBackEnd::FixItContainer; -using ClangCodeModel::ClangFixItOperation; +using ClangCodeModel::Internal::ClangFixItOperation; using ::testing::PrintToString; diff --git a/tests/unit/unittest/highlightingresultreporter-test.cpp b/tests/unit/unittest/highlightingresultreporter-test.cpp index 29803783b17..dfe8dfbd2e0 100644 --- a/tests/unit/unittest/highlightingresultreporter-test.cpp +++ b/tests/unit/unittest/highlightingresultreporter-test.cpp @@ -43,6 +43,7 @@ using ClangBackEnd::Document; using ClangBackEnd::Documents; using ClangBackEnd::UnsavedFiles; using ClangBackEnd::ChunksReportedMonitor; +using ClangCodeModel::Internal::HighlightingResultReporter; namespace { @@ -86,7 +87,7 @@ QVector generateTokenInfos(uint count) TEST_F(HighlightingResultReporter, StartAndFinish) { - auto reporter = new ClangCodeModel::HighlightingResultReporter(noTokenInfos()); + auto reporter = new ::HighlightingResultReporter(noTokenInfos()); auto future = reporter->start(); @@ -96,7 +97,7 @@ TEST_F(HighlightingResultReporter, StartAndFinish) TEST_F(HighlightingResultReporter, ReportNothingIfNothingToReport) { - auto reporter = new ClangCodeModel::HighlightingResultReporter(generateTokenInfos(0)); + auto reporter = new ::HighlightingResultReporter(generateTokenInfos(0)); auto future = reporter->start(); @@ -106,7 +107,7 @@ TEST_F(HighlightingResultReporter, ReportNothingIfNothingToReport) TEST_F(HighlightingResultReporter, ReportSingleResultAsOneChunk) { - auto reporter = new ClangCodeModel::HighlightingResultReporter(generateTokenInfos(1)); + auto reporter = new ::HighlightingResultReporter(generateTokenInfos(1)); reporter->setChunkSize(1); auto future = reporter->start(); @@ -117,7 +118,7 @@ TEST_F(HighlightingResultReporter, ReportSingleResultAsOneChunk) TEST_F(HighlightingResultReporter, ReportRestIfChunkSizeNotReached) { - auto reporter = new ClangCodeModel::HighlightingResultReporter(generateTokenInfos(1)); + auto reporter = new ::HighlightingResultReporter(generateTokenInfos(1)); const int notReachedChunkSize = 100; reporter->setChunkSize(notReachedChunkSize); @@ -129,7 +130,7 @@ TEST_F(HighlightingResultReporter, ReportRestIfChunkSizeNotReached) TEST_F(HighlightingResultReporter, ReportChunksWithoutRest) { - auto reporter = new ClangCodeModel::HighlightingResultReporter(generateTokenInfos(4)); + auto reporter = new ::HighlightingResultReporter(generateTokenInfos(4)); reporter->setChunkSize(1); auto future = reporter->start(); @@ -140,7 +141,7 @@ TEST_F(HighlightingResultReporter, ReportChunksWithoutRest) TEST_F(HighlightingResultReporter, ReportSingleChunkAndRest) { - auto reporter = new ClangCodeModel::HighlightingResultReporter(generateTokenInfos(5)); + auto reporter = new ::HighlightingResultReporter(generateTokenInfos(5)); reporter->setChunkSize(2); auto future = reporter->start(); @@ -158,7 +159,7 @@ TEST_F(HighlightingResultReporter, ReportCompleteLines) TokenInfoContainer(1, 2, 1, types), TokenInfoContainer(2, 1, 1, types), }; - auto reporter = new ClangCodeModel::HighlightingResultReporter(tokenInfos); + auto reporter = new ::HighlightingResultReporter(tokenInfos); reporter->setChunkSize(1); auto future = reporter->start(); From d3ceb9ce622be629b5a02678c7d4d0c768d34245 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Tue, 19 Feb 2019 12:43:37 +0100 Subject: [PATCH 06/12] Unit-tests: Fix the debug build with MSVC Change-Id: I99fd6db6406b088cab0538b07cd20ca1427a5f71 Reviewed-by: Marco Bubke --- tests/unit/unittest/unittest.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 634a0a0e2b5..e3c9430acf0 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -33,6 +33,7 @@ CONFIG(release, debug|release):QMAKE_LFLAGS += -Wl,--strip-debug } gcc:!clang: QMAKE_CXXFLAGS += -Wno-noexcept-type +msvc: QMAKE_CXXFLAGS += /bigobj # create fake CppTools.json for the mime type definitions dependencyList = "\"Dependencies\" : []" From c134850255bad9617fa1150f925d97b464a9c241 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 19 Feb 2019 16:33:04 +0100 Subject: [PATCH 07/12] ProParser: Fix qmake build on Windows Change-Id: I08f5340df966887e826b44afea754cd76236c914 Reviewed-by: Christian Kandeler --- src/shared/proparser/proparser.pri | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shared/proparser/proparser.pri b/src/shared/proparser/proparser.pri index 5f02416ef7d..9bd8976dd7f 100644 --- a/src/shared/proparser/proparser.pri +++ b/src/shared/proparser/proparser.pri @@ -32,3 +32,4 @@ SOURCES += \ RESOURCES += proparser.qrc DEFINES += QMAKE_BUILTIN_PRFS QMAKE_OVERRIDE_PRFS +win32: LIBS *= -ladvapi32 From 064f43fecf99c30666256764f7a9d61162f74f48 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 19 Feb 2019 16:08:22 +0100 Subject: [PATCH 08/12] Dumper: Add dumper test for QSizePolicy Beside this fix handling of QSizePolicy for namespaced Qt. Change-Id: Icf4e3574f97653a7bd4d8b696c87c17ef4defefa Reviewed-by: hjk --- share/qtcreator/debugger/qttypes.py | 4 ++-- tests/auto/debugger/tst_dumpers.cpp | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index 91e38feaacc..6484d5f6838 100644 --- a/share/qtcreator/debugger/qttypes.py +++ b/share/qtcreator/debugger/qttypes.py @@ -1433,8 +1433,8 @@ def qdump__QSizePolicy(d, value): with Children(d): d.putIntItem('horStretch', (bits >> 0) & 0xff) d.putIntItem('verStretch', (bits >> 8) & 0xff) - d.putEnumItem('horPolicy', (bits >> 16) & 0xf, "QSizePolicy::Policy") - d.putEnumItem('verPolicy', (bits >> 20) & 0xf, "QSizePolicy::Policy") + d.putEnumItem('horPolicy', (bits >> 16) & 0xf, "@QSizePolicy::Policy") + d.putEnumItem('verPolicy', (bits >> 20) & 0xf, "@QSizePolicy::Policy") def qform__QStack(): diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 780fa4ec472..63f0f25bf40 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -5457,6 +5457,19 @@ void tst_Dumpers::dumper_data() + Check("e.e2", "(E::b2 | E::c2) (3)", "E::Enum2") + Check("e.e3", "(E::b3 | E::c3) (3)", "E::Enum3"); + QTest::newRow("QSizePolicy") + << Data("#include \n", + "QSizePolicy qsp1;\n" + "qsp1.setHorizontalStretch(6);\n" + "qsp1.setVerticalStretch(7);\n" + "QSizePolicy qsp2(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);\n") + + GuiProfile() + + NoCdbEngine + + Check("qsp1.horStretch", "6", "int") + + Check("qsp1.verStretch", "7", "int") + + Check("qsp2.horPolicy", "QSizePolicy::Preferred (GrowFlag|ShrinkFlag) (5)", "@QSizePolicy::Policy") + + Check("qsp2.verPolicy", "QSizePolicy::MinimumExpanding (GrowFlag|ExpandFlag) (3)", "@QSizePolicy::Policy"); + QTest::newRow("Array") << Data("", From 118c126f984debd3a39ea034179622da4d33fe7a Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Tue, 19 Feb 2019 14:30:52 +0100 Subject: [PATCH 09/12] ClangFormat: Refactor code Reorder some functions, remove code duplication. Change-Id: I33e118e567dee7db622bbc99e6a7c500db54e5c5 Reviewed-by: Marco Bubke --- src/libs/utils/textutils.cpp | 22 + src/libs/utils/textutils.h | 4 + .../clangformat/clangformatbaseindenter.cpp | 600 +++++++++--------- .../clangformat/clangformatbaseindenter.h | 10 +- 4 files changed, 319 insertions(+), 317 deletions(-) diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp index 21fb3caf511..0d8009fef89 100644 --- a/src/libs/utils/textutils.cpp +++ b/src/libs/utils/textutils.cpp @@ -165,5 +165,27 @@ int utf8NthLineOffset(const QTextDocument *textDocument, const QByteArray &buffe return utf8Offset; } +LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset) +{ + Utils::LineColumn lineColumn; + lineColumn.line = static_cast( + std::count(utf8Buffer.begin(), utf8Buffer.begin() + utf8Offset, '\n')) + + 1; + const int startOfLineOffset = utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1; + lineColumn.column = QString::fromUtf8( + utf8Buffer.mid(startOfLineOffset, utf8Offset - startOfLineOffset)) + .length() + + 1; + return lineColumn; +} + +QString utf16LineTextInUtf8Buffer(const QByteArray &utf8Buffer, int currentUtf8Offset) +{ + const int lineStartUtf8Offset = utf8Buffer.lastIndexOf('\n', currentUtf8Offset - 1) + 1; + const int lineEndUtf8Offset = utf8Buffer.indexOf('\n', currentUtf8Offset); + return QString::fromUtf8( + utf8Buffer.mid(lineStartUtf8Offset, lineEndUtf8Offset - lineStartUtf8Offset)); +} + } // Text } // Utils diff --git a/src/libs/utils/textutils.h b/src/libs/utils/textutils.h index 895023903ee..fb0efe3f15f 100644 --- a/src/libs/utils/textutils.h +++ b/src/libs/utils/textutils.h @@ -59,5 +59,9 @@ QTCREATOR_UTILS_EXPORT int utf8NthLineOffset(const QTextDocument *textDocument, const QByteArray &buffer, int line); +QTCREATOR_UTILS_EXPORT LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset); +QTCREATOR_UTILS_EXPORT QString utf16LineTextInUtf8Buffer(const QByteArray &utf8Buffer, + int currentUtf8Offset); + } // Text } // Utils diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index da36731796a..7a87eabcd79 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -36,8 +36,9 @@ namespace ClangFormat { -static void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style, - ReplacementsToKeep replacementsToKeep) +namespace { +void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style, + ReplacementsToKeep replacementsToKeep) { style.MaxEmptyLinesToKeep = 100; style.SortIncludes = false; @@ -56,28 +57,30 @@ static void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style, #endif } -static llvm::StringRef clearExtraNewline(llvm::StringRef text) +llvm::StringRef clearExtraNewline(llvm::StringRef text) { while (text.startswith("\n\n")) text = text.drop_front(); return text; } -static clang::tooling::Replacements filteredReplacements( - const QByteArray &buffer, - const clang::tooling::Replacements &replacements, - int utf8Offset, - int utf8Length, - ReplacementsToKeep replacementsToKeep) +clang::tooling::Replacements filteredReplacements(const QByteArray &buffer, + const clang::tooling::Replacements &replacements, + int utf8Offset, + int utf8Length, + ReplacementsToKeep replacementsToKeep) { clang::tooling::Replacements filtered; for (const clang::tooling::Replacement &replacement : replacements) { int replacementOffset = static_cast(replacement.getOffset()); - const bool replacementDoesNotMatchRestriction - = replacementOffset >= utf8Offset + utf8Length - || (replacementsToKeep == ReplacementsToKeep::OnlyIndent - && (replacementOffset < utf8Offset - 1 || buffer.at(replacementOffset) != '\n')); - if (replacementDoesNotMatchRestriction) + + // Skip everything after. + if (replacementOffset >= utf8Offset + utf8Length) + return filtered; + + const bool isNotIndentOrInRange = replacementOffset < utf8Offset - 1 + || buffer.at(replacementOffset) != '\n'; + if (isNotIndentOrInRange && replacementsToKeep == ReplacementsToKeep::OnlyIndent) continue; llvm::StringRef text = replacementsToKeep == ReplacementsToKeep::OnlyIndent @@ -102,17 +105,10 @@ static clang::tooling::Replacements filteredReplacements( return filtered; } -static void trimFirstNonEmptyBlock(const QTextBlock ¤tBlock) +void trimRHSWhitespace(const QTextBlock &block) { - QTextBlock prevBlock = currentBlock.previous(); - while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty()) - prevBlock = prevBlock.previous(); - - if (prevBlock.text().trimmed().isEmpty()) - return; - - const QString initialText = prevBlock.text(); - if (!initialText.at(initialText.size() - 1).isSpace()) + const QString initialText = block.text(); + if (!initialText.rbegin()->isSpace()) return; auto lastNonSpace = std::find_if_not(initialText.rbegin(), @@ -120,7 +116,7 @@ static void trimFirstNonEmptyBlock(const QTextBlock ¤tBlock) [](const QChar &letter) { return letter.isSpace(); }); const int extraSpaceCount = static_cast(std::distance(initialText.rbegin(), lastNonSpace)); - QTextCursor cursor(prevBlock); + QTextCursor cursor(block); cursor.beginEditBlock(); cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, @@ -130,20 +126,9 @@ static void trimFirstNonEmptyBlock(const QTextBlock ¤tBlock) cursor.endEditBlock(); } -// Returns the total langth of previous lines with pure whitespace. -static int previousEmptyLinesLength(const QTextBlock ¤tBlock) -{ - int length{0}; - QTextBlock prevBlock = currentBlock.previous(); - while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty()) { - length += prevBlock.text().length() + 1; - prevBlock = prevBlock.previous(); - } - - return length; -} - -static int modifyToIndentEmptyLines(QByteArray &buffer, const QTextBlock &block, bool secondTry) +// Add extra text in case of the empty line or the line starting with ')'. +// Track such extra pieces of text in isInsideModifiedLine(). +int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool secondTry) { const QString blockText = block.text(); int firstNonWhitespace = Utils::indexOf(blockText, @@ -195,48 +180,32 @@ static int modifyToIndentEmptyLines(QByteArray &buffer, const QTextBlock &block, return extraLength; } -static Utils::LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset) +bool isInsideModifiedLine(const QString &originalLine, const QString &modifiedLine, int column) { - Utils::LineColumn lineColumn; - lineColumn.line = std::count(utf8Buffer.begin(), utf8Buffer.begin() + utf8Offset, '\n') + 1; - lineColumn.column = utf8Offset - utf8Buffer.lastIndexOf('\n', utf8Offset - 1); - return lineColumn; -} - -static QString utf16LineLengthInUtf8Buffer(const QByteArray &utf8Buffer, int currentUtf8Offset) -{ - const int lineStartUtf8Offset = utf8Buffer.lastIndexOf('\n', currentUtf8Offset - 1) + 1; - const int lineEndUtf8Offset = utf8Buffer.indexOf('\n', currentUtf8Offset); - return QString::fromUtf8( - utf8Buffer.mid(lineStartUtf8Offset, lineEndUtf8Offset - lineStartUtf8Offset)); -} - -static bool isInsideModifiedLine(const QString &originalLine, - const QString &modifiedLine, - int column) -{ - // Track the cases when we have inserted extra text into the line to get the indentation. + // Detect the cases when we have inserted extra text into the line to get the indentation. return originalLine.length() < modifiedLine.length() && column != modifiedLine.length() + 1 && (column > originalLine.length() || originalLine.trimmed().isEmpty() || !modifiedLine.startsWith(originalLine)); } -static TextEditor::Replacements utf16Replacements(const QTextDocument *doc, - const QByteArray &utf8Buffer, - const clang::tooling::Replacements &replacements) +TextEditor::Replacements utf16Replacements(const QTextDocument *doc, + const QByteArray &utf8Buffer, + const clang::tooling::Replacements &replacements) { TextEditor::Replacements convertedReplacements; convertedReplacements.reserve(replacements.size()); for (const clang::tooling::Replacement &replacement : replacements) { - Utils::LineColumn lineColUtf16 = utf16LineColumn(utf8Buffer, - static_cast(replacement.getOffset())); + Utils::LineColumn lineColUtf16 = Utils::Text::utf16LineColumn(utf8Buffer, + static_cast( + replacement.getOffset())); if (!lineColUtf16.isValid()) continue; const QString lineText = doc->findBlockByNumber(lineColUtf16.line - 1).text(); - const QString bufferLineText = utf16LineLengthInUtf8Buffer(utf8Buffer, - replacement.getOffset()); + const QString bufferLineText + = Utils::Text::utf16LineTextInUtf8Buffer(utf8Buffer, + static_cast(replacement.getOffset())); if (isInsideModifiedLine(lineText, bufferLineText, lineColUtf16.column)) continue; @@ -257,7 +226,7 @@ static TextEditor::Replacements utf16Replacements(const QTextDocument *doc, return convertedReplacements; } -static void applyReplacements(QTextDocument *doc, const TextEditor::Replacements &replacements) +void applyReplacements(QTextDocument *doc, const TextEditor::Replacements &replacements) { if (replacements.empty()) return; @@ -277,9 +246,7 @@ static void applyReplacements(QTextDocument *doc, const TextEditor::Replacements } } -static QString selectedLines(QTextDocument *doc, - const QTextBlock &startBlock, - const QTextBlock &endBlock) +QString selectedLines(QTextDocument *doc, const QTextBlock &startBlock, const QTextBlock &endBlock) { return Utils::Text::textAt(QTextCursor(doc), startBlock.position(), @@ -288,19 +255,231 @@ static QString selectedLines(QTextDocument *doc, - startBlock.position() - 1)); } +int indentationForBlock(const TextEditor::Replacements &toReplace, + const QByteArray &buffer, + const QTextBlock ¤tBlock) +{ + const int utf8Offset = Utils::Text::utf8NthLineOffset(currentBlock.document(), + buffer, + currentBlock.blockNumber() + 1); + auto replacementIt = std::find_if(toReplace.begin(), + toReplace.end(), + [utf8Offset](const TextEditor::Replacement &replacement) { + return replacement.offset == utf8Offset - 1; + }); + if (replacementIt == toReplace.end()) + return -1; + + int afterLineBreak = replacementIt->text.lastIndexOf('\n'); + afterLineBreak = (afterLineBreak < 0) ? 0 : afterLineBreak + 1; + return static_cast(replacementIt->text.size() - afterLineBreak); +} + +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; + case ':': + // Do not indent when it's the first ':' and it's not the 'case' line. + if (text.contains(QLatin1String("case")) || text.contains(QLatin1String("default")) + || text.contains(QLatin1String("public")) || text.contains(QLatin1String("private")) + || text.contains(QLatin1String("protected")) || text.contains(QLatin1String("signals")) + || text.contains(QLatin1String("Q_SIGNALS"))) { + return false; + } + if (pos > 0 && doc->characterAt(pos - 1) != ':') + return true; + break; + } + + return false; +} + +QTextBlock reverseFindLastEmptyBlock(QTextBlock start) +{ + if (start.position() > 0) { + start = start.previous(); + while (start.position() > 0 && start.text().trimmed().isEmpty()) + start = start.previous(); + if (!start.text().trimmed().isEmpty()) + start = start.next(); + } + return start; +} + +int formattingRangeStart(const QTextBlock ¤tBlock, + const QByteArray &buffer, + int documentRevision) +{ + QTextBlock prevBlock = currentBlock.previous(); + while ((prevBlock.position() > 0 || prevBlock.length() > 0) + && prevBlock.revision() != documentRevision) { + // Find the first block with not matching revision. + prevBlock = prevBlock.previous(); + } + if (prevBlock.revision() == documentRevision) + prevBlock = prevBlock.next(); + + return Utils::Text::utf8NthLineOffset(prevBlock.document(), buffer, prevBlock.blockNumber() + 1); +} +} // namespace + ClangFormatBaseIndenter::ClangFormatBaseIndenter(QTextDocument *doc) : TextEditor::Indenter(doc) {} -TextEditor::IndentationForBlock ClangFormatBaseIndenter::indentationForBlocks( - const QVector &blocks, - const TextEditor::TabSettings & /*tabSettings*/, - int cursorPositionInEditor) +TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer, + const QTextBlock &startBlock, + const QTextBlock &endBlock, + ReplacementsToKeep replacementsToKeep, + const QChar &typedChar, + bool secondTry) const { - TextEditor::IndentationForBlock ret; - for (QTextBlock block : blocks) - ret.insert(block.blockNumber(), indentFor(block, cursorPositionInEditor)); - return ret; + QTC_ASSERT(replacementsToKeep != ReplacementsToKeep::All, return TextEditor::Replacements()); + + clang::format::FormatStyle style = styleForFile(); + QByteArray originalBuffer = buffer; + + int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, startBlock.blockNumber() + 1); + QTC_ASSERT(utf8Offset >= 0, return TextEditor::Replacements();); + int utf8Length = selectedLines(m_doc, startBlock, endBlock).toUtf8().size(); + + int rangeStart = 0; + if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) + rangeStart = formattingRangeStart(startBlock, buffer, lastSaveRevision()); + + if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) { + buffer.insert(utf8Offset - 1, " //"); + utf8Offset += 3; + } + + adjustFormatStyleForLineBreak(style, replacementsToKeep); + if (typedChar == QChar::Null) { + for (int index = startBlock.blockNumber(); index <= endBlock.blockNumber(); ++index) { + utf8Length += forceIndentWithExtraText(buffer, + m_doc->findBlockByNumber(index), + secondTry); + } + } + + if (replacementsToKeep != ReplacementsToKeep::IndentAndBefore || utf8Offset < rangeStart) + rangeStart = utf8Offset; + + unsigned int rangeLength = static_cast(utf8Offset + utf8Length - rangeStart); + std::vector ranges{{static_cast(rangeStart), rangeLength}}; + + clang::format::FormattingAttemptStatus status; + clang::tooling::Replacements clangReplacements = reformat(style, + buffer.data(), + ranges, + m_fileName.toString().toStdString(), + &status); + + clang::tooling::Replacements filtered; + if (status.FormatComplete) { + filtered = filteredReplacements(buffer, + clangReplacements, + utf8Offset, + utf8Length, + replacementsToKeep); + } + const bool canTryAgain = replacementsToKeep == ReplacementsToKeep::OnlyIndent + && typedChar == QChar::Null && !secondTry; + if (canTryAgain && filtered.empty()) { + return replacements(originalBuffer, + startBlock, + endBlock, + replacementsToKeep, + typedChar, + true); + } + + return utf16Replacements(m_doc, buffer, filtered); +} + +TextEditor::Replacements ClangFormatBaseIndenter::format( + const TextEditor::RangesInLines &rangesInLines) +{ + if (rangesInLines.empty()) + return TextEditor::Replacements(); + + const QByteArray buffer = m_doc->toPlainText().toUtf8(); + std::vector ranges; + ranges.reserve(rangesInLines.size()); + + for (auto &range : rangesInLines) { + const int utf8StartOffset = Utils::Text::utf8NthLineOffset(m_doc, buffer, range.startLine); + int utf8RangeLength = m_doc->findBlockByNumber(range.endLine - 1).text().toUtf8().size(); + if (range.endLine > range.startLine) { + utf8RangeLength += Utils::Text::utf8NthLineOffset(m_doc, buffer, range.endLine) + - utf8StartOffset; + } + ranges.emplace_back(static_cast(utf8StartOffset), + static_cast(utf8RangeLength)); + } + + clang::format::FormattingAttemptStatus status; + const clang::tooling::Replacements clangReplacements + = reformat(styleForFile(), buffer.data(), ranges, m_fileName.toString().toStdString(), &status); + const TextEditor::Replacements toReplace = utf16Replacements(m_doc, buffer, clangReplacements); + applyReplacements(m_doc, toReplace); + + return toReplace; +} + +TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlock, + const QTextBlock &endBlock, + const QByteArray &buffer, + const QChar &typedChar, + int cursorPositionInEditor) +{ + if (typedChar != QChar::Null && cursorPositionInEditor > 0 + && m_doc->characterAt(cursorPositionInEditor - 1) == typedChar + && doNotIndentInContext(m_doc, cursorPositionInEditor - 1)) { + return TextEditor::Replacements(); + } + + startBlock = reverseFindLastEmptyBlock(startBlock); + const int startBlockPosition = startBlock.position(); + if (startBlock.position() > 0) { + trimRHSWhitespace(startBlock.previous()); + if (cursorPositionInEditor >= 0) + cursorPositionInEditor += startBlock.position() - startBlockPosition; + } + + ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent; + if (formatWhileTyping() + && (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 + // the indented block - don't trigger extra formatting in this case. + // cursorPositionInEditor == -1 means the consition matches automatically. + + // Format only before newline or complete statement not to break code. + replacementsToKeep = ReplacementsToKeep::IndentAndBefore; + } + + return replacements(buffer, + startBlock, + endBlock, + replacementsToKeep, + typedChar); +} + +void ClangFormatBaseIndenter::indentBlocks(const QTextBlock &startBlock, + const QTextBlock &endBlock, + const QChar &typedChar, + int cursorPositionInEditor) +{ + const QByteArray buffer = m_doc->toPlainText().toUtf8(); + applyReplacements(m_doc, + indentsFor(startBlock, endBlock, buffer, typedChar, cursorPositionInEditor)); } void ClangFormatBaseIndenter::indent(const QTextCursor &cursor, @@ -332,126 +511,6 @@ void ClangFormatBaseIndenter::reindent(const QTextCursor &cursor, indent(cursor, QChar::Null, cursorPositionInEditor); } -TextEditor::Replacements ClangFormatBaseIndenter::format( - const TextEditor::RangesInLines &rangesInLines) -{ - if (rangesInLines.empty()) - return TextEditor::Replacements(); - - int utf8Offset = -1; - QTextBlock block; - - const QByteArray buffer = m_doc->toPlainText().toUtf8(); - std::vector ranges; - ranges.reserve(rangesInLines.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(utf8StartOffset), - static_cast(utf8RangeLength)); - - if (utf8Offset < 0) { - utf8Offset = utf8StartOffset; - block = m_doc->findBlockByNumber(range.startLine - 1); - } - } - - 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(m_doc, buffer, clangReplacements); - applyReplacements(m_doc, toReplace); - - return 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; - case ':': - // Do not indent when it's the first ':' and it's not the 'case' line. - if (text.contains(QLatin1String("case")) || text.contains(QLatin1String("default")) - || text.contains(QLatin1String("public")) || text.contains(QLatin1String("private")) - || text.contains(QLatin1String("protected")) || text.contains(QLatin1String("signals")) - || text.contains(QLatin1String("Q_SIGNALS"))) { - return false; - } - if (pos > 0 && doc->characterAt(pos - 1) != ':') - return true; - break; - } - - return false; -} - -void ClangFormatBaseIndenter::indentBlocks(QTextBlock startBlock, - const QTextBlock &endBlock, - const QChar &typedChar, - int cursorPositionInEditor) -{ - if (typedChar != QChar::Null && cursorPositionInEditor > 0 - && m_doc->characterAt(cursorPositionInEditor - 1) == typedChar - && doNotIndentInContext(m_doc, cursorPositionInEditor - 1)) { - return; - } - - if (startBlock.position() > 0) { - startBlock = startBlock.previous(); - while (startBlock.position() > 0 && startBlock.text().trimmed().isEmpty()) - startBlock = startBlock.previous(); - if (!startBlock.text().trimmed().isEmpty()) { - startBlock = startBlock.next(); - } - } - - const int startBlockPosition = startBlock.position(); - trimFirstNonEmptyBlock(startBlock); - if (cursorPositionInEditor >= 0) - cursorPositionInEditor += startBlock.position() - startBlockPosition; - - ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent; - if (formatWhileTyping() - && (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 - // the indented block - don't trigger extra formatting in this case. - // cursorPositionInEditor == -1 means the consition matches automatically. - - // Format only before newline or complete statement not to break code. - replacementsToKeep = ReplacementsToKeep::IndentAndBefore; - } - - const QByteArray buffer = m_doc->toPlainText().toUtf8(); - 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(m_doc, - replacements(buffer, - utf8Offset, - utf8Length, - startBlock, - endBlock, - replacementsToKeep, - typedChar)); -} - void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block, const QChar &typedChar, const TextEditor::TabSettings & /*tabSettings*/, @@ -460,35 +519,40 @@ void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block, indentBlocks(block, block, typedChar, 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;); - - const TextEditor::Replacements toReplace = replacements(buffer, - utf8Offset, - 0, - block, - block, - ReplacementsToKeep::OnlyIndent); - - if (toReplace.empty()) - return -1; - - const TextEditor::Replacement &replacement = toReplace.front(); - int afterLineBreak = replacement.text.lastIndexOf('\n'); - afterLineBreak = (afterLineBreak < 0) ? 0 : afterLineBreak + 1; - return static_cast(replacement.text.size() - afterLineBreak); -} - int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings & /*tabSettings*/, int cursorPositionInEditor) { - return indentFor(block, cursorPositionInEditor); + const QByteArray buffer = m_doc->toPlainText().toUtf8(); + TextEditor::Replacements toReplace = indentsFor(block, + block, + buffer, + QChar::Null, + cursorPositionInEditor); + if (toReplace.empty()) + return -1; + + return indentationForBlock(toReplace, buffer, block); +} + +TextEditor::IndentationForBlock ClangFormatBaseIndenter::indentationForBlocks( + const QVector &blocks, + const TextEditor::TabSettings & /*tabSettings*/, + int cursorPositionInEditor) +{ + TextEditor::IndentationForBlock ret; + if (blocks.isEmpty()) + return ret; + const QByteArray buffer = m_doc->toPlainText().toUtf8(); + TextEditor::Replacements toReplace = indentsFor(blocks.front(), + blocks.back(), + buffer, + QChar::Null, + cursorPositionInEditor); + + for (const QTextBlock &block : blocks) + ret.insert(block.blockNumber(), indentationForBlock(toReplace, buffer, block)); + return ret; } bool ClangFormatBaseIndenter::isElectricCharacter(const QChar &ch) const @@ -541,94 +605,4 @@ clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const return clang::format::getLLVMStyle(); } -static int formattingRangeStart(const QTextBlock ¤tBlock, - const QByteArray &buffer, - int documentRevision) -{ - QTextBlock prevBlock = currentBlock.previous(); - while ((prevBlock.position() > 0 || prevBlock.length() > 0) - && prevBlock.revision() != documentRevision) { - // Find the first block with not matching revision. - prevBlock = prevBlock.previous(); - } - if (prevBlock.revision() == documentRevision) - prevBlock = prevBlock.next(); - - return Utils::Text::utf8NthLineOffset(prevBlock.document(), buffer, prevBlock.blockNumber() + 1); -} - -TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer, - int utf8Offset, - int utf8Length, - const QTextBlock &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 rangeStart = 0; - if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) - rangeStart = formattingRangeStart(startBlock, buffer, lastSaveRevision()); - - if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) { - buffer.insert(utf8Offset - 1, " //"); - utf8Offset += 3; - } - - adjustFormatStyleForLineBreak(style, replacementsToKeep); - if (typedChar == QChar::Null) { - for (int index = startBlock.blockNumber(); index <= endBlock.blockNumber(); ++index) { - utf8Length += modifyToIndentEmptyLines(buffer, - m_doc->findBlockByNumber(index), - secondTry); - } - } - - if (replacementsToKeep != ReplacementsToKeep::IndentAndBefore || utf8Offset < rangeStart) - rangeStart = utf8Offset; - - unsigned int rangeLength = static_cast(utf8Offset + utf8Length - rangeStart); - - std::vector ranges{{static_cast(rangeStart), rangeLength}}; - - clang::format::FormattingAttemptStatus status; - - clang::tooling::Replacements clangReplacements = reformat(style, - buffer.data(), - ranges, - m_fileName.toString().toStdString(), - &status); - - clang::tooling::Replacements filtered; - if (status.FormatComplete) { - filtered = filteredReplacements(buffer, - clangReplacements, - utf8Offset, - utf8Length, - replacementsToKeep); - } - const bool canTryAgain = replacementsToKeep == ReplacementsToKeep::OnlyIndent - && typedChar == QChar::Null && !secondTry; - if (canTryAgain && filtered.empty()) { - return replacements(originalBuffer, - originalOffsetUtf8, - originalLengthUtf8, - startBlock, - endBlock, - replacementsToKeep, - typedChar, - true); - } - - return utf16Replacements(m_doc, buffer, filtered); -} - } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatbaseindenter.h b/src/plugins/clangformat/clangformatbaseindenter.h index 360f27fbedc..ed63ff6efa3 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.h +++ b/src/plugins/clangformat/clangformatbaseindenter.h @@ -75,14 +75,16 @@ protected: private: void indent(const QTextCursor &cursor, const QChar &typedChar, int cursorPositionInEditor); - void indentBlocks(QTextBlock startBlock, + void indentBlocks(const QTextBlock &startBlock, const QTextBlock &endBlock, const QChar &typedChar, int cursorPositionInEditor); - int indentFor(const QTextBlock &block, int cursorPositionInEditor); + TextEditor::Replacements indentsFor(QTextBlock startBlock, + const QTextBlock &endBlock, + const QByteArray &buffer, + const QChar &typedChar, + int cursorPositionInEditor); TextEditor::Replacements replacements(QByteArray buffer, - int utf8Offset, - int utf8Length, const QTextBlock &startBlock, const QTextBlock &endBlock, ReplacementsToKeep replacementsToKeep, From 808910792762c0c89cbf37c644a42505df02afb2 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 15 Feb 2019 15:03:52 +0100 Subject: [PATCH 10/12] Clang: Remove some namespace noise in clangtextmark.cpp Change-Id: I870338821f106b1066e43b76451ed79b130e612b Reviewed-by: Ivan Donchevskii --- src/plugins/clangcodemodel/clangtextmark.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/plugins/clangcodemodel/clangtextmark.cpp b/src/plugins/clangcodemodel/clangtextmark.cpp index ddeb8623663..e673df76220 100644 --- a/src/plugins/clangcodemodel/clangtextmark.cpp +++ b/src/plugins/clangcodemodel/clangtextmark.cpp @@ -48,6 +48,8 @@ #include #include +using namespace CppTools; +using namespace ClangCodeModel::Internal; using namespace Utils; namespace ClangCodeModel { @@ -76,9 +78,6 @@ static Core::Id categoryForSeverity(ClangBackEnd::DiagnosticSeverity severity) ProjectExplorer::Project *projectForCurrentEditor() { - using namespace CppTools; - using namespace ClangCodeModel::Internal; - const QString filePath = Utils::currentCppEditorDocumentFilePath(); if (filePath.isEmpty()) return nullptr; @@ -91,7 +90,7 @@ ProjectExplorer::Project *projectForCurrentEditor() return nullptr; } -void disableDiagnosticInConfig(CppTools::ClangDiagnosticConfig &config, +void disableDiagnosticInConfig(ClangDiagnosticConfig &config, const ClangBackEnd::DiagnosticContainer &diagnostic) { // Clang check @@ -117,9 +116,6 @@ void disableDiagnosticInConfig(CppTools::ClangDiagnosticConfig &config, void disableDiagnosticInCurrentProjectConfig(const ClangBackEnd::DiagnosticContainer &diagnostic) { - using namespace CppTools; - using namespace ClangCodeModel::Internal; - ProjectExplorer::Project *project = projectForCurrentEditor(); QTC_ASSERT(project, return ); @@ -198,7 +194,6 @@ ClangTextMark::ClangTextMark(const FileName &fileName, QAction *action = new QAction(); action->setIcon(QIcon::fromTheme("edit-copy", ::Utils::Icons::COPY.icon())); QObject::connect(action, &QAction::triggered, [diagnostic]() { - using namespace ClangCodeModel::Internal; const QString text = ClangDiagnosticWidget::createText({diagnostic}, ClangDiagnosticWidget::InfoBar); QApplication::clipboard()->setText(text, QClipboard::Clipboard); From 4e2c3a7d7242b773e516781bfa61f56a61bab102 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 15 Feb 2019 15:05:02 +0100 Subject: [PATCH 11/12] Clang: Do not suggest to remove warning from tidy ...if the tidy configuration is read from a file. Do not show the corresponding text mark action in this case. Change-Id: I6114304f41e3946d4041233031a9bc83eee13bba Reviewed-by: Ivan Donchevskii --- src/plugins/clangcodemodel/clangtextmark.cpp | 83 +++++++++++++++----- 1 file changed, 63 insertions(+), 20 deletions(-) diff --git a/src/plugins/clangcodemodel/clangtextmark.cpp b/src/plugins/clangcodemodel/clangtextmark.cpp index e673df76220..f756acf2d3e 100644 --- a/src/plugins/clangcodemodel/clangtextmark.cpp +++ b/src/plugins/clangcodemodel/clangtextmark.cpp @@ -90,28 +90,76 @@ ProjectExplorer::Project *projectForCurrentEditor() return nullptr; } +enum class DiagnosticType { Clang, Tidy, Clazy }; +DiagnosticType diagnosticType(const ClangBackEnd::DiagnosticContainer &diagnostic) + +{ + if (!diagnostic.disableOption.isEmpty()) + return DiagnosticType::Clang; + + const Utils::DiagnosticTextInfo textInfo(diagnostic.text); + if (Utils::DiagnosticTextInfo::isClazyOption(textInfo.option())) + return DiagnosticType::Clazy; + return DiagnosticType::Tidy; +} + void disableDiagnosticInConfig(ClangDiagnosticConfig &config, const ClangBackEnd::DiagnosticContainer &diagnostic) { - // Clang check - if (!diagnostic.disableOption.isEmpty()) { - config.setClangOptions(config.clangOptions() + QStringList(diagnostic.disableOption)); - return; - } - - // Clazy check using namespace ClangCodeModel::Utils; - DiagnosticTextInfo textInfo(diagnostic.text); - if (DiagnosticTextInfo::isClazyOption(textInfo.option())) { + + switch (diagnosticType(diagnostic)) { + case DiagnosticType::Clang: + config.setClangOptions(config.clangOptions() + QStringList(diagnostic.disableOption)); + break; + case DiagnosticType::Tidy: + config.setClangTidyChecks(config.clangTidyChecks() + QString(",-") + + DiagnosticTextInfo(diagnostic.text).option()); + break; + case DiagnosticType::Clazy: { + const DiagnosticTextInfo textInfo(diagnostic.text); const QString checkName = DiagnosticTextInfo::clazyCheckName(textInfo.option()); QStringList newChecks = config.clazyChecks().split(','); newChecks.removeOne(checkName); config.setClazyChecks(newChecks.join(',')); - return; + break; } + } +} - // Tidy check - config.setClangTidyChecks(config.clangTidyChecks() + QString(",-") + textInfo.option()); +ClangDiagnosticConfig diagnosticConfig(ClangProjectSettings &projectSettings, + CppCodeModelSettings &globalSettings) +{ + ProjectExplorer::Project *project = projectForCurrentEditor(); + QTC_ASSERT(project, return {}); + + // Get config id + Core::Id currentConfigId = projectSettings.warningConfigId(); + if (projectSettings.useGlobalConfig()) + currentConfigId = globalSettings.clangDiagnosticConfigId(); + + // Get config + ClangDiagnosticConfigsModel configsModel(globalSettings.clangCustomDiagnosticConfigs()); + QTC_ASSERT(configsModel.hasConfigWithId(currentConfigId), return {}); + return configsModel.configWithId(currentConfigId); +} + +bool isDiagnosticConfigChangable(ProjectExplorer::Project *project, + const ClangBackEnd::DiagnosticContainer &diagnostic) +{ + if (!project) + return false; + + ClangProjectSettings &projectSettings = ClangModelManagerSupport::instance()->projectSettings( + project); + const QSharedPointer globalSettings = codeModelSettings(); + const ClangDiagnosticConfig config = diagnosticConfig(projectSettings, *globalSettings); + + if (config.clangTidyMode() == ClangDiagnosticConfig::TidyMode::File + && diagnosticType(diagnostic) == DiagnosticType::Tidy) { + return false; + } + return true; } void disableDiagnosticInCurrentProjectConfig(const ClangBackEnd::DiagnosticContainer &diagnostic) @@ -124,15 +172,9 @@ void disableDiagnosticInCurrentProjectConfig(const ClangBackEnd::DiagnosticConta project); const QSharedPointer globalSettings = codeModelSettings(); - // Get config id - Core::Id currentConfigId = projectSettings.warningConfigId(); - if (projectSettings.useGlobalConfig()) - currentConfigId = globalSettings->clangDiagnosticConfigId(); - // Get config + ClangDiagnosticConfig config = diagnosticConfig(projectSettings, *globalSettings); ClangDiagnosticConfigsModel configsModel(globalSettings->clangCustomDiagnosticConfigs()); - QTC_ASSERT(configsModel.hasConfigWithId(currentConfigId), return ); - ClangDiagnosticConfig config = configsModel.configWithId(currentConfigId); // Create copy if needed if (config.isReadOnly()) { @@ -201,7 +243,8 @@ ClangTextMark::ClangTextMark(const FileName &fileName, actions << action; // Remove diagnostic warning action - if (projectForCurrentEditor()) { + ProjectExplorer::Project *project = projectForCurrentEditor(); + if (project && isDiagnosticConfigChangable(project, diagnostic)) { action = new QAction(); action->setIcon(::Utils::Icons::BROKEN.icon()); QObject::connect(action, &QAction::triggered, [diagnostic]() { From 2e58938404c7c54c741d976816d304cc8447cc56 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Mon, 4 Feb 2019 09:35:32 +0100 Subject: [PATCH 12/12] Recognize UNC paths as absolute (i.e. not relative) IoUtils::isRelativePath() didn't attempt to consider UNC paths, due to a belief that qmake fails on them so badly that it wasn't worth the extra code. However, it turns out Qt Creator's copy of this code does need to take this into account, so start the change off in qmake's version so as to keep in sync. This is a cherry pick from qtbase commit 4b4a288f5f88077d647d47e9bdd911edf6cdca72 Fixes: QTCREATORBUG-21881 Written-by: Edward Welbourne Change-Id: I3084b87c1d3ca6508255e94e04ac8db3ceaebb7e Reviewed-by: Nikolai Kosjar --- src/shared/proparser/ioutils.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/shared/proparser/ioutils.cpp b/src/shared/proparser/ioutils.cpp index 0552bd10972..f678ea9fb03 100644 --- a/src/shared/proparser/ioutils.cpp +++ b/src/shared/proparser/ioutils.cpp @@ -75,7 +75,12 @@ bool IoUtils::isRelativePath(const QString &path) && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) { return false; } - // (... unless, of course, they're UNC, which qmake fails on anyway) + // ... unless, of course, they're UNC: + if (path.length() >= 2 + && (path.at(0).unicode() == '\\' || path.at(0).unicode() == '/') + && path.at(1) == path.at(0)) { + return false; + } #else if (path.startsWith(QLatin1Char('/'))) return false;