diff options
author | Eike Ziller <eike.ziller@qt.io> | 2019-03-14 15:14:40 +0100 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2019-03-14 15:51:15 +0100 |
commit | c53ccceff1e1642b7704fa8b0681604c25a833a0 (patch) | |
tree | 7258d63fba4dabd6f9e2f2f36089ce45df7fe3af | |
parent | 62cafc1782369cde0605fbd6b1182a83d5473a12 (diff) | |
parent | 429eb73ace5909e228a58bf8b067823e2be44212 (diff) |
Merge remote-tracking branch 'origin/4.9'
Conflicts:
qbs/modules/qtc/qtc.qbs
qtcreator.pri
src/plugins/debugger/debuggerkitinformation.cpp
src/plugins/languageclient/languageclientmanager.cpp
src/plugins/plugins.pro
src/plugins/projectexplorer/kit.cpp
src/plugins/projectexplorer/kitmanager.cpp
Change-Id: I66fb941202991f35f7d7761430b21e42dfc678a8
154 files changed, 2209 insertions, 1066 deletions
diff --git a/.clang-format b/.clang-format index 953e0b44cd..97f7f2b234 100644 --- a/.clang-format +++ b/.clang-format @@ -8,6 +8,8 @@ # Use ../../tests/manual/clang-format-for-qtc/test.cpp for documenting problems # or testing changes. # +# In case you update this configuration please also update the qtcStyle() in src\plugins\clangformat\clangformatutils.cpp +# # [1] https://doc-snapshots.qt.io/qtcreator-extending/coding-style.html # [2] https://clang.llvm.org/docs/ClangFormatStyleOptions.html # @@ -34,9 +34,10 @@ Prerequisites: * Python 3.5 or later (optional, needed for the python enabled debug helper) * On Mac OS X: latest Xcode * On Linux: g++ 5.3 or later -* LLVM/Clang 6.0.0 or later (optional, needed for the Clang Code Model, see the - section "Get LLVM/Clang for the Clang Code Model") - * CMake (only for manual builds of LLVM/Clang) +* LLVM/Clang 7.0.0 or later (optional, needed for the Clang Code Model, Clang Tools, ClangFormat, + Clang PCH Manager and Clang Refactoring plugins, see the section + "Get LLVM/Clang for the Clang Code Model") +* CMake (only for manual builds of LLVM/Clang) * Qbs 1.7.x (optional, sources also contain Qbs itself) The installed toolchains have to match the one Qt was compiled with. @@ -49,6 +50,10 @@ You can build Qt Creator with export QBS_INSTALL_DIR=/path/to/qbs # Optional, needed for the Python enabled dumper on Windows set PYTHON_INSTALL_DIR=C:\path\to\python + # Optional, needed to use system KSyntaxHighlighting: + set KSYNTAXHIGHLIGHTING_LIB_DIR to folder holding the KSyntaxHighlighting library + # if automatic deducing of include folder fails set KSYNTAXHIGHLIGHTING_INCLUDE_DIR as well + # both variables can also be passed as qmake variables cd $SOURCE_DIRECTORY qmake -r @@ -220,7 +225,7 @@ or using shadow builds. ## Get LLVM/Clang for the Clang Code Model The Clang Code Model depends on the LLVM/Clang libraries. The currently -supported LLVM/Clang version is 6.0. +supported LLVM/Clang version is 7.0. ### Prebuilt LLVM/Clang packages @@ -247,9 +252,9 @@ GCC 4 binaries. On Ubuntu, you can download the package from http://apt.llvm.org/ with: wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo apt-add-repository "deb http://apt.llvm.org/`lsb_release -cs`/ llvm-toolchain-`lsb_release -cs`-6.0 main" + sudo apt-add-repository "deb http://apt.llvm.org/`lsb_release -cs`/ llvm-toolchain-`lsb_release -cs`-7.0 main" sudo apt-get update - sudo apt-get install llvm-6.0 libclang-6.0-dev + sudo apt-get install llvm-7.0 libclang-7.0-dev There is a workaround to set _GLIBCXX_USE_CXX11_ABI to 1 or 0, but we recommend to download the package from http://apt.llvm.org/. diff --git a/dist/changes-4.9.0.md b/dist/changes-4.9.0.md index 5bc79fca88..1397bfe03c 100644 --- a/dist/changes-4.9.0.md +++ b/dist/changes-4.9.0.md @@ -52,6 +52,10 @@ QMake Projects * Fixed updating of `LD_LIBRARY_PATH` environment variable (QTCREATORBUG-21475) * Fixed updating of project tree in case of wildcards in corresponding QMake variable (QTCREATORBUG-21603) +* Fixed issues with project tree when files are directly added to `RESOURCES` + (QTCREATORBUG-20103) +* Fixed that importing build unnecessarily created temporary kit + (QTCREATORBUG-18153) CMake Projects @@ -78,6 +82,8 @@ C++ Support * Clang Code Model * Added buttons for copying and ignoring diagnostics to tooltip * Fixed issue with high memory consumption (QTCREATORBUG-19543) + * Fixed inconsistency between `Follow Symbol` and `Ctrl + Click` + (QTCREATORBUG-21637) * Clang Format * Added option to format code instead of only indenting code @@ -98,6 +104,9 @@ Nim Support Debugging +* Fixed that debugger toolbar could force large minimum window size + (QTCREATORBUG-21885) +* Added pretty printing of `QSizePolicy` * GDB * Added support for rvalue references in function arguments * LLDB @@ -167,6 +176,7 @@ Windows * Added support for MSVC 2019 * Changed toolchain detection to use `vswhere` by default, which is recommended by Microsoft +* Fixed issue with UNC paths in `.pro` files (QTCREATORBUG-21881) Linux diff --git a/qtcreator.pro b/qtcreator.pro index 71be6dac37..e5f2951634 100644 --- a/qtcreator.pro +++ b/qtcreator.pro @@ -109,15 +109,19 @@ linux { macx { APPBUNDLE = "$$OUT_PWD/bin/$${IDE_APP_TARGET}.app" - BINDIST_SOURCE = "$$OUT_PWD/bin/$${IDE_APP_TARGET}.app" + BINDIST_SOURCE.release = "$$OUT_PWD/bin/$${IDE_APP_TARGET}.app" + BINDIST_SOURCE.debug = "$$OUT_PWD/bin" + BINDIST_EXCLUDE_ARG.debug = "--exclude-toplevel" deployqt.commands = $$PWD/scripts/deployqtHelper_mac.sh \"$${APPBUNDLE}\" \"$$[QT_INSTALL_BINS]\" \"$$[QT_INSTALL_TRANSLATIONS]\" \"$$[QT_INSTALL_PLUGINS]\" \"$$[QT_INSTALL_IMPORTS]\" \"$$[QT_INSTALL_QML]\" codesign.commands = codesign --deep -s \"$(SIGNING_IDENTITY)\" $(SIGNING_FLAGS) \"$${APPBUNDLE}\" dmg.commands = python -u \"$$PWD/scripts/makedmg.py\" \"$${BASENAME}.dmg\" \"Qt Creator\" \"$$IDE_SOURCE_TREE\" \"$$OUT_PWD/bin\" #dmg.depends = deployqt QMAKE_EXTRA_TARGETS += codesign dmg } else { - BINDIST_SOURCE = "$(INSTALL_ROOT)$$QTC_PREFIX" - BINDIST_EXCLUDE_ARG = "--exclude-toplevel" + BINDIST_SOURCE.release = "$(INSTALL_ROOT)$$QTC_PREFIX" + BINDIST_EXCLUDE_ARG.release = "--exclude-toplevel" + BINDIST_SOURCE.debug = $${BINDIST_SOURCE.release} + BINDIST_EXCLUDE_ARG.debug = $${BINDIST_EXCLUDE_ARG.release} deployqt.commands = python -u $$PWD/scripts/deployqt.py -i \"$(INSTALL_ROOT)$$QTC_PREFIX/bin/$${IDE_APP_TARGET}\" \"$(QMAKE)\" deployqt.depends = install win32 { @@ -140,9 +144,9 @@ isEmpty(INSTALLER_ARCHIVE_FROM_ENV) { INSTALLER_ARCHIVE_DEBUG = $$INSTALLER_ARCHIVE INSTALLER_ARCHIVE_DEBUG ~= s/(.*)[.]7z/\1-debug.7z -bindist.commands = python -u $$PWD/scripts/createDistPackage.py $$OUT_PWD/$${BASENAME}.7z \"$$BINDIST_SOURCE\" -bindist_installer.commands = python -u $$PWD/scripts/createDistPackage.py $$BINDIST_EXCLUDE_ARG $${INSTALLER_ARCHIVE} \"$$BINDIST_SOURCE\" -bindist_debug.commands = python -u $$PWD/scripts/createDistPackage.py --debug $$BINDIST_EXCLUDE_ARG $${INSTALLER_ARCHIVE_DEBUG} \"$$BINDIST_SOURCE\" +bindist.commands = python -u $$PWD/scripts/createDistPackage.py $$OUT_PWD/$${BASENAME}.7z \"$${BINDIST_SOURCE.release}\" +bindist_installer.commands = python -u $$PWD/scripts/createDistPackage.py $${BINDIST_EXCLUDE_ARG.release} $${INSTALLER_ARCHIVE} \"$${BINDIST_SOURCE.release}\" +bindist_debug.commands = python -u $$PWD/scripts/createDistPackage.py --debug $${BINDIST_EXCLUDE_ARG.debug} $${INSTALLER_ARCHIVE_DEBUG} \"$${BINDIST_SOURCE.debug}\" win32 { deployqt.commands ~= s,/,\\\\,g diff --git a/scripts/flake2tasks.py b/scripts/flake2tasks.py new file mode 100755 index 0000000000..a98cbf69ec --- /dev/null +++ b/scripts/flake2tasks.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +############################################################################ +# +# 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. +# +############################################################################ + +''' +flake2tasks.py - Convert flake8 warnings into Qt Creator task files. + +SYNOPSIS + + flake2tasks.py < logfile > taskfile +''' + +import sys +import re + +if __name__ == '__main__': + pattern = re.compile(r'^([^:]+):(\d+):\d+: E\d+ (.*)$') + while True: + line = sys.stdin.readline().rstrip() + if not line: + break + match = pattern.match(line) + if match: + file_name = match.group(1).replace('\\', '/') + line_number = match.group(2) + text = match.group(3) + output = "{}\t{}\twarn\t{}".format(file_name, line_number, text) + print(output) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index a961569cd0..cf19c1eac8 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -957,6 +957,12 @@ class Dumper(DumperBase): return self.report('pid="%s"' % self.process.GetProcessID()) self.reportState('enginerunandinferiorrunok') + if self.target is not None: + broadcaster = self.target.GetBroadcaster() + listener = self.debugger.GetListener() + broadcaster.AddListener(listener, lldb.SBTarget.eBroadcastBitBreakpointChanged) + listener.StartListeningForEvents(broadcaster, lldb.SBTarget.eBroadcastBitBreakpointChanged) + def loop(self): event = lldb.SBEvent() @@ -1116,6 +1122,11 @@ class Dumper(DumperBase): # logview pane feature. self.report('token(\"%s\")' % args["token"]) + + def reportBreakpointUpdate(self, bp): + self.report('breakpointmodified={%s}' % self.describeBreakpoint(bp)) + + def readRawMemory(self, address, size): if size == 0: return bytes() @@ -1288,7 +1299,20 @@ class Dumper(DumperBase): self.process.Kill() self.reportResult('', args) + + def handleBreakpointEvent(self, event): + eventType = lldb.SBBreakpoint.GetBreakpointEventTypeFromEvent(event) + # handle only the resolved locations for now.. + if eventType & lldb.eBreakpointEventTypeLocationsResolved: + bp = lldb.SBBreakpoint.GetBreakpointFromEvent(event) + if bp is not None: + self.reportBreakpointUpdate(bp) + + def handleEvent(self, event): + if lldb.SBBreakpoint.EventIsBreakpointEvent(event): + self.handleBreakpointEvent(event) + return out = lldb.SBStream() event.GetDescription(out) #warn("EVENT: %s" % event) diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json index 0f1ce91cf7..16c2646ce5 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json @@ -3,7 +3,7 @@ "supportedProjectTypes": [ "PythonProject" ], "id": "U.QtForPythonApplicationEmpty", "category": "F.Application", - "trDescription": "Creates a Qt for Python application that only the main code for a QApplication", + "trDescription": "Creates a Qt for Python application that contains only the main code for a QApplication.", "trDisplayName": "Qt for Python - Empty", "trDisplayCategory": "Application", "icon": "icon.png", diff --git a/src/app/app.pro b/src/app/app.pro index 89b9554a9f..712563419e 100644 --- a/src/app/app.pro +++ b/src/app/app.pro @@ -5,8 +5,9 @@ TEMPLATE = app CONFIG += qtc_runnable sliced_bundle TARGET = $$IDE_APP_TARGET DESTDIR = $$IDE_APP_PATH -VERSION = $$QTCREATOR_VERSION QT -= testlib +# work around QTBUG-74265 +win32: VERSION= HEADERS += ../tools/qtcreatorcrashhandler/crashhandlersetup.h SOURCES += main.cpp ../tools/qtcreatorcrashhandler/crashhandlersetup.cpp diff --git a/src/libs/clangsupport/commandlinebuilder.h b/src/libs/clangsupport/commandlinebuilder.h index 7367f08036..9de1da68d3 100644 --- a/src/libs/clangsupport/commandlinebuilder.h +++ b/src/libs/clangsupport/commandlinebuilder.h @@ -51,6 +51,7 @@ public: commandLine.reserve(1024); addCompiler(projectInfo.language); + disableWarnings(); addToolChainArguments(toolChainArguments); addExtraFlags(); addLanguage(projectInfo, sourceType); @@ -74,6 +75,8 @@ public: commandLine.emplace_back("clang"); } + void disableWarnings() { commandLine.emplace_back("-w"); } + void addToolChainArguments(const Utils::SmallStringVector &toolChainArguments) { for (Utils::SmallStringView argument : toolChainArguments) diff --git a/src/libs/clangsupport/refactoringdatabaseinitializer.h b/src/libs/clangsupport/refactoringdatabaseinitializer.h index cce203f0d4..f6d64a81d3 100644 --- a/src/libs/clangsupport/refactoringdatabaseinitializer.h +++ b/src/libs/clangsupport/refactoringdatabaseinitializer.h @@ -143,6 +143,8 @@ public: const Sqlite::Column &projectPartIdColumn = table.addColumn("projectPartId", Sqlite::ColumnType::Integer); const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer); table.addColumn("sourceType", Sqlite::ColumnType::Integer); + table.addColumn("pchCreationTimeStamp", Sqlite::ColumnType::Integer); + table.addColumn("hasMissingIncludes", Sqlite::ColumnType::Integer); table.addUniqueIndex({sourceIdColumn, projectPartIdColumn}); table.addIndex({projectPartIdColumn}); @@ -168,11 +170,11 @@ public: Sqlite::Table table; table.setUseIfNotExists(true); table.setName("fileStatuses"); - table.addColumn("sourceId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); + table.addColumn("sourceId", + Sqlite::ColumnType::Integer, + Sqlite::Contraint::PrimaryKey); table.addColumn("size", Sqlite::ColumnType::Integer); table.addColumn("lastModified", Sqlite::ColumnType::Integer); - table.addColumn("buildDependencyTimeStamp", Sqlite::ColumnType::Integer); - table.addColumn("isInPrecompiledHeader", Sqlite::ColumnType::Integer); table.initialize(database); } diff --git a/src/libs/cplusplus/ExpressionUnderCursor.cpp b/src/libs/cplusplus/ExpressionUnderCursor.cpp index e176cbde35..6df396d8cf 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.cpp +++ b/src/libs/cplusplus/ExpressionUnderCursor.cpp @@ -264,7 +264,7 @@ int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) const break; } else if (tk.is(T_LPAREN) || tk.is(T_LBRACE)) { return scanner.startPosition() + tk.utf16charsBegin(); - } else if (tk.is(T_RPAREN)) { + } else if (tk.is(T_RPAREN) || tk.is(T_RBRACE)) { int matchingBrace = scanner.startOfMatchingBrace(index); if (matchingBrace == index) // If no matching brace found diff --git a/src/libs/libs.pro b/src/libs/libs.pro index 8bc99461a7..26495bbbf0 100644 --- a/src/libs/libs.pro +++ b/src/libs/libs.pro @@ -31,9 +31,27 @@ for(l, SUBDIRS) { } SUBDIRS += \ - utils/process_stub.pro \ - 3rdparty/syntax-highlighting \ - 3rdparty/syntax-highlighting/data + utils/process_stub.pro + +isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR): KSYNTAXHIGHLIGHTING_LIB_DIR=$$(KSYNTAXHIGHLIGHTING_LIB_DIR) +!isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) { + # enable short information message + KSYNTAX_WARN_ON = 1 +} + +include(../shared/syntax/syntax_shared.pri) +isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) { + SUBDIRS += \ + 3rdparty/syntax-highlighting \ + 3rdparty/syntax-highlighting/data + + equals(KSYNTAX_WARN_ON, 1) { + message("Either KSYNTAXHIGHLIGHTING_LIB_DIR does not exist or include path could not be deduced.") + unset(KSYNTAX_WARN_ON) + } +} else { + message("Using KSyntaxHighlighting provided at $${KSYNTAXHIGHLIGHTING_LIB_DIR}.") +} win32:SUBDIRS += utils/process_ctrlc_stub.pro diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index a38a2fa906..ea43a4dec8 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -748,8 +748,8 @@ void Check::endVisit(UiObjectInitializer *) { m_propertyStack.pop(); m_typeStack.pop(); - UiObjectDefinition *objectDenition = cast<UiObjectDefinition *>(parent()); - if (objectDenition && objectDenition->qualifiedTypeNameId->name == "Component") + UiObjectDefinition *objectDefinition = cast<UiObjectDefinition *>(parent()); + if (objectDefinition && objectDefinition->qualifiedTypeNameId->name == "Component") m_idStack.pop(); UiObjectBinding *objectBinding = cast<UiObjectBinding *>(parent()); if (objectBinding && objectBinding->qualifiedTypeNameId->name == "Component") diff --git a/src/libs/ssh/sshremoteprocess.cpp b/src/libs/ssh/sshremoteprocess.cpp index 48e965d6fa..a769484735 100644 --- a/src/libs/ssh/sshremoteprocess.cpp +++ b/src/libs/ssh/sshremoteprocess.cpp @@ -69,7 +69,7 @@ SshRemoteProcess::SshRemoteProcess(const QByteArray &command, const QStringList connect(this, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this] { QString error; if (exitStatus() == QProcess::CrashExit) - error = tr("The ssh binary crashed: %1").arg(errorString()); + error = tr("The ssh process crashed: %1").arg(errorString()); else if (exitCode() == 255) error = tr("Remote process crashed."); emit done(error); diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 708595aa4d..a476cd8d89 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -311,9 +311,10 @@ QString FileUtils::normalizePathName(const QString &name) if (FAILED(hr)) return name; TCHAR buffer[MAX_PATH]; - if (!SHGetPathFromIDList(file, buffer)) - return name; - return QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const ushort *>(buffer))); + const bool success = SHGetPathFromIDList(file, buffer); + ILFree(file); + return success ? QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const ushort *>(buffer))) + : name; #elif defined(Q_OS_OSX) return Internal::normalizePathName(name); #else // do not try to handle case-insensitive file systems on Linux diff --git a/src/libs/utils/jsontreeitem.cpp b/src/libs/utils/jsontreeitem.cpp index a70f5631ec..16da8e803e 100644 --- a/src/libs/utils/jsontreeitem.cpp +++ b/src/libs/utils/jsontreeitem.cpp @@ -63,9 +63,9 @@ QVariant Utils::JsonTreeItem::data(int column, int role) const if (column == 2) return typeName(m_value.type()); if (m_value.isObject()) - return QString('[' + QString::number(m_value.toObject().size()) + ' ' + tr("Items") + ']'); + return QString('[' + tr("%n Items", nullptr, m_value.toObject().size()) + ']'); if (m_value.isArray()) - return QString('[' + QString::number(m_value.toArray().size()) + ' ' + tr("Items") + ']'); + return QString('[' + tr("%n Items", nullptr, m_value.toArray().size()) + ']'); return m_value.toVariant(); } diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp index 0d8009fef8..ba10ca56ae 100644 --- a/src/libs/utils/textutils.cpp +++ b/src/libs/utils/textutils.cpp @@ -171,7 +171,8 @@ LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset) lineColumn.line = static_cast<int>( std::count(utf8Buffer.begin(), utf8Buffer.begin() + utf8Offset, '\n')) + 1; - const int startOfLineOffset = utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1; + const int startOfLineOffset = utf8Offset ? (utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1) + : 0; lineColumn.column = QString::fromUtf8( utf8Buffer.mid(startOfLineOffset, utf8Offset - startOfLineOffset)) .length() @@ -181,7 +182,9 @@ LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset) QString utf16LineTextInUtf8Buffer(const QByteArray &utf8Buffer, int currentUtf8Offset) { - const int lineStartUtf8Offset = utf8Buffer.lastIndexOf('\n', currentUtf8Offset - 1) + 1; + const int lineStartUtf8Offset = currentUtf8Offset + ? (utf8Buffer.lastIndexOf('\n', currentUtf8Offset - 1) + 1) + : 0; const int lineEndUtf8Offset = utf8Buffer.indexOf('\n', currentUtf8Offset); return QString::fromUtf8( utf8Buffer.mid(lineStartUtf8Offset, lineEndUtf8Offset - lineStartUtf8Offset)); diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 97b8e5de5b..8ba6012875 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -101,7 +101,7 @@ public: setSummaryText(displayName()); auto uninstallPreviousPackage = new QCheckBox(this); - uninstallPreviousPackage->setText(tr("Uninstall previous package")); + uninstallPreviousPackage->setText(AndroidDeployQtStep::tr("Uninstall previous package")); uninstallPreviousPackage->setChecked(step->uninstallPreviousPackage() > AndroidDeployQtStep::Keep); uninstallPreviousPackage->setEnabled(step->uninstallPreviousPackage() != AndroidDeployQtStep::ForceUnintall); diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp index 11de94c395..a4a1591cf4 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp @@ -68,13 +68,12 @@ void ClangCodeModelPlugin::generateCompilationDB() { using namespace CppTools; ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); - if (!project) + if (!project || !project->activeTarget()) return; - m_generatorWatcher.setFuture(QtConcurrent::run( - &Utils::generateCompilationDB, - project->projectDirectory(), - CppModelManager::instance()->projectInfo(project))); + m_generatorWatcher.setFuture( + QtConcurrent::run(&Utils::generateCompilationDB, + CppModelManager::instance()->projectInfo(project))); } static bool isDBGenerationEnabled(ProjectExplorer::Project *project) diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp index db34c904d4..6f1397c487 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp @@ -214,6 +214,9 @@ void ClangCompletionAssistProcessor::handleAvailableCompletions(const CodeComple setAsyncProposalAvailable(createFunctionHintProposal(completions)); return; } + + if (!m_fallbackToNormalCompletion) + return; // else: Proceed with a normal completion in case: // 1) it was not a function call, but e.g. a function declaration like "void f(" // 2) '{' meant not a constructor call. @@ -286,6 +289,14 @@ static QByteArray modifyInput(QTextDocument *doc, int endOfExpression) { return modifiedInput; } +static QChar lastPrecedingNonWhitespaceChar(const ClangCompletionAssistInterface *interface) +{ + int pos = interface->position(); + while (pos >= 0 && interface->characterAt(pos).isSpace()) + --pos; + return pos >= 0 ? interface->characterAt(pos) : QChar::Null; +} + IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper() { ClangCompletionContextAnalyzer analyzer(m_interface.data(), m_interface->languageFeatures()); @@ -323,6 +334,8 @@ IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper() } case ClangCompletionContextAnalyzer::PassThroughToLibClangAfterLeftParen: { m_sentRequestType = FunctionHintCompletion; + if (lastPrecedingNonWhitespaceChar(m_interface.data()) == ',') + m_fallbackToNormalCompletion = false; m_requestSent = sendCompletionRequest(analyzer.positionForClang(), QByteArray(), analyzer.functionNameStart()); break; diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.h b/src/plugins/clangcodemodel/clangcompletionassistprocessor.h index 03711f0fa8..5e8c772235 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.h +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.h @@ -97,6 +97,7 @@ private: CompletionRequestType m_sentRequestType = NormalCompletion; bool m_requestSent = false; bool m_addSnippets = false; // For type == Type::NormalCompletion + bool m_fallbackToNormalCompletion = true; }; } // namespace Internal diff --git a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp index ad48a60685..a2c32a537a 100644 --- a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp +++ b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp @@ -110,6 +110,8 @@ int ClangCompletionContextAnalyzer::startOfFunctionCall(int endOfOperator) const functionNameSelector.setPosition(functionNameStart); functionNameSelector.setPosition(index, QTextCursor::KeepAnchor); const QString functionName = functionNameSelector.selectedText().trimmed(); + if (functionName.isEmpty() && m_completionOperator == T_LBRACE) + return endOfOperator; return functionName.isEmpty() ? -1 : functionNameStart; } @@ -139,7 +141,10 @@ void ClangCompletionContextAnalyzer::handleCommaInFunctionCall() const int start = expressionUnderCursor.startOfFunctionCall(textCursor); m_positionEndOfExpression = start; m_positionForProposal = start + 1; // After '(' of function call - m_completionOperator = T_LPAREN; + if (m_interface->characterAt(start) == '(') + m_completionOperator = T_LPAREN; + else + m_completionOperator = T_LBRACE; } } diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index 481b0774f8..fa42dedf2d 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -34,12 +34,13 @@ #include <coreplugin/idocument.h> #include <cpptools/baseeditordocumentparser.h> #include <cpptools/compileroptionsbuilder.h> +#include <cpptools/cppcodemodelsettings.h> #include <cpptools/cppmodelmanager.h> +#include <cpptools/cpptoolsreuse.h> #include <cpptools/editordocumenthandle.h> #include <cpptools/projectpart.h> -#include <cpptools/cppcodemodelsettings.h> -#include <cpptools/cpptoolsreuse.h> #include <projectexplorer/buildconfiguration.h> +#include <projectexplorer/kitinformation.h> #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/target.h> @@ -300,12 +301,24 @@ QString diagnosticCategoryPrefixRemoved(const QString &text) return text; } -static ::Utils::FileName buildDirectory(const CppTools::ProjectPart &projectPart) +static ::Utils::FileName compilerPath(const CppTools::ProjectPart &projectPart) { ProjectExplorer::Target *target = projectPart.project->activeTarget(); if (!target) return ::Utils::FileName(); + ProjectExplorer::ToolChain *toolchain = ProjectExplorer::ToolChainKitAspect::toolChain( + target->kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID); + + return toolchain->compilerCommand(); +} + +static ::Utils::FileName buildDirectory(const ProjectExplorer::Project &project) +{ + ProjectExplorer::Target *target = project.activeTarget(); + if (!target) + return ::Utils::FileName(); + ProjectExplorer::BuildConfiguration *buildConfig = target->activeBuildConfiguration(); if (!buildConfig) return ::Utils::FileName(); @@ -313,42 +326,84 @@ static ::Utils::FileName buildDirectory(const CppTools::ProjectPart &projectPart return buildConfig->buildDirectory(); } -static QJsonObject createFileObject(CompilerOptionsBuilder &optionsBuilder, - const ProjectFile &projFile, - const ::Utils::FileName &buildDir) +static QStringList projectPartArguments(const ProjectPart &projectPart) { - const ProjectFile::Kind kind = ProjectFile::classify(projFile.path); - optionsBuilder.updateFileLanguage(kind); + QStringList args; + args << compilerPath(projectPart).toString(); + args << "-c"; + if (projectPart.toolchainType != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) { + args << "--target=" + projectPart.toolChainTargetTriple; + args << (projectPart.toolChainWordWidth == ProjectPart::WordWidth64Bit + ? QLatin1String("-m64") + : QLatin1String("-m32")); + } + args << projectPart.compilerFlags; + for (const ProjectExplorer::HeaderPath &headerPath : projectPart.headerPaths) { + if (headerPath.type == ProjectExplorer::HeaderPathType::User) { + args << "-I" + headerPath.path; + } else if (headerPath.type == ProjectExplorer::HeaderPathType::System) { + args << (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID + ? "-I" + : "-isystem") + + headerPath.path; + } + } + for (const ProjectExplorer::Macro ¯o : projectPart.projectMacros) { + args.append(QString::fromUtf8( + macro.toKeyValue(macro.type == ProjectExplorer::MacroType::Define ? "-D" : "-U"))); + } + return args; +} + +static QJsonObject createFileObject(const ::Utils::FileName &buildDir, + const QStringList &arguments, + const ProjectPart &projectPart, + const ProjectFile &projFile) +{ QJsonObject fileObject; fileObject["file"] = projFile.path; - QJsonArray args = QJsonArray::fromStringList(optionsBuilder.options()); - args.prepend(kind == ProjectFile::CXXSource ? "clang++" : "clang"); + QJsonArray args = QJsonArray::fromStringList(arguments); + + const ProjectFile::Kind kind = ProjectFile::classify(projFile.path); + if (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID + || projectPart.toolchainType == ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID) { + if (ProjectFile::isC(kind)) + args.append("/TC"); + else if (ProjectFile::isCxx(kind)) + args.append("/TP"); + } else { + QStringList langOption + = createLanguageOptionGcc(kind, + projectPart.languageExtensions + & ::Utils::LanguageExtension::ObjectiveC); + for (const QString &langOptionPart : langOption) + args.append(langOptionPart); + } args.append(QDir::toNativeSeparators(projFile.path)); fileObject["arguments"] = args; fileObject["directory"] = buildDir.toString(); return fileObject; } -void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo) +void generateCompilationDB(CppTools::ProjectInfo projectInfo) { - QFile compileCommandsFile(projectDir.toString() + "/compile_commands.json"); + const ::Utils::FileName buildDir = buildDirectory(*projectInfo.project()); + QTC_ASSERT(!buildDir.isEmpty(), return;); + QDir dir(buildDir.toString()); + if (!dir.exists()) + dir.mkpath(dir.path()); + QFile compileCommandsFile(buildDir.toString() + "/compile_commands.json"); const bool fileOpened = compileCommandsFile.open(QIODevice::WriteOnly | QIODevice::Truncate); if (!fileOpened) return; compileCommandsFile.write("["); - for (ProjectPart::Ptr projectPart : projectInfo.projectParts()) { - const ::Utils::FileName buildDir = buildDirectory(*projectPart); - - CompilerOptionsBuilder optionsBuilder(*projectPart, - UseSystemHeader::No, - UseTweakedHeaderPaths::No); - optionsBuilder.build(CppTools::ProjectFile::Unclassified, - CppTools::UsePrecompiledHeaders::No); + for (ProjectPart::Ptr projectPart : projectInfo.projectParts()) { + const QStringList args = projectPartArguments(*projectPart); for (const ProjectFile &projFile : projectPart->files) { - const QJsonObject json = createFileObject(optionsBuilder, projFile, buildDir); + const QJsonObject json = createFileObject(buildDir, args, *projectPart, projFile); if (compileCommandsFile.size() > 1) compileCommandsFile.write(","); compileCommandsFile.write('\n' + QJsonDocument(json).toJson().trimmed()); diff --git a/src/plugins/clangcodemodel/clangutils.h b/src/plugins/clangcodemodel/clangutils.h index 4db869896b..8ced14f5ad 100644 --- a/src/plugins/clangcodemodel/clangutils.h +++ b/src/plugins/clangcodemodel/clangutils.h @@ -70,7 +70,7 @@ QString diagnosticCategoryPrefixRemoved(const QString &text); ::Utils::CodeModelIcon::Type iconTypeForToken(const ClangBackEnd::TokenInfoContainer &token); -void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo); +void generateCompilationDB(CppTools::ProjectInfo projectInfo); class DiagnosticTextInfo { diff --git a/src/plugins/clangformat/ClangFormat.json.in b/src/plugins/clangformat/ClangFormat.json.in index 1c818c2f9e..f270fea580 100644 --- a/src/plugins/clangformat/ClangFormat.json.in +++ b/src/plugins/clangformat/ClangFormat.json.in @@ -2,7 +2,7 @@ \"Name\" : \"ClangFormat\", \"Version\" : \"$$QTCREATOR_VERSION\", \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\", - \"Experimental\" : true, + \"DisabledByDefault\" : true, \"Vendor\" : \"The Qt Company Ltd\", \"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\", \"License\" : [ \"Commercial Usage\", diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index a53eb50adb..dcb5edaeb1 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -29,9 +29,10 @@ #include <utils/algorithm.h> #include <utils/fileutils.h> -#include <utils/textutils.h> #include <utils/qtcassert.h> +#include <utils/textutils.h> +#include <QDebug> #include <QTextDocument> namespace ClangFormat { @@ -126,9 +127,85 @@ void trimRHSWhitespace(const QTextBlock &block) cursor.endEditBlock(); } +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; +} + +enum class CharacterContext { AfterComma, LastAfterComma, NewStatement, Continuation, Unknown }; + +QChar findFirstNonWhitespaceCharacter(const QTextBlock ¤tBlock) +{ + const QTextDocument *doc = currentBlock.document(); + int currentPos = currentBlock.position(); + while (currentPos < doc->characterCount() && doc->characterAt(currentPos).isSpace()) + ++currentPos; + return currentPos < doc->characterCount() ? doc->characterAt(currentPos) : QChar::Null; +} + +CharacterContext characterContext(const QTextBlock ¤tBlock, + const QTextBlock &previousNonEmptyBlock) +{ + const QString prevLineText = previousNonEmptyBlock.text().trimmed(); + const QChar firstNonWhitespaceChar = findFirstNonWhitespaceCharacter(currentBlock); + if (prevLineText.endsWith(',')) { + // We don't need to add comma in case it's the last argument. + if (firstNonWhitespaceChar == '}' || firstNonWhitespaceChar == ')') + return CharacterContext::LastAfterComma; + return CharacterContext::AfterComma; + } + + if (prevLineText.endsWith(';') || prevLineText.endsWith('{') || prevLineText.endsWith('}') + || firstNonWhitespaceChar == QChar::Null) { + return CharacterContext::NewStatement; + } + + return CharacterContext::Continuation; +} + +bool nextBlockExistsAndEmpty(const QTextBlock ¤tBlock) +{ + QTextBlock nextBlock = currentBlock.next(); + if (!nextBlock.isValid() || nextBlock.position() == currentBlock.position()) + return false; + + return nextBlock.text().trimmed().isEmpty(); +} + +QByteArray dummyTextForContext(CharacterContext context, bool closingBraceBlock) +{ + if (closingBraceBlock + && (context == CharacterContext::NewStatement + || context == CharacterContext::Continuation)) { + return QByteArray(); + } + + switch (context) { + case CharacterContext::Unknown: + QTC_ASSERT(false, return "";); + case CharacterContext::AfterComma: + return "a,"; + case CharacterContext::NewStatement: + return "a;"; + case CharacterContext::Continuation: + case CharacterContext::LastAfterComma: + return "& a &"; + } +} + // 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) +int forceIndentWithExtraText(QByteArray &buffer, + CharacterContext &charContext, + const QTextBlock &block, + bool secondTry) { const QString blockText = block.text(); int firstNonWhitespace = Utils::indexOf(blockText, @@ -143,26 +220,33 @@ int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool s const bool closingParenBlock = firstNonWhitespace >= 0 && blockText.at(firstNonWhitespace) == ')'; + const bool closingBraceBlock = firstNonWhitespace >= 0 + && blockText.at(firstNonWhitespace) == '}'; int extraLength = 0; - if (firstNonWhitespace < 0 || closingParenBlock) { - //This extra text works for the most cases. - QByteArray dummyText("a;a;"); - - // Search for previous character - QTextBlock prevBlock = block.previous(); - bool prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty(); - while (prevBlockIsEmpty) { - prevBlock = prevBlock.previous(); - prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty(); + QByteArray dummyText; + if (firstNonWhitespace < 0 && charContext != CharacterContext::Unknown + && nextBlockExistsAndEmpty(block)) { + // If the next line is also empty it's safer to use a comment line. + dummyText = "//"; + } else if (firstNonWhitespace < 0 || closingParenBlock || closingBraceBlock) { + if (charContext == CharacterContext::LastAfterComma) { + charContext = CharacterContext::AfterComma; + } else if (charContext == CharacterContext::Unknown || firstNonWhitespace >= 0) { + QTextBlock lastBlock = reverseFindLastEmptyBlock(block); + if (lastBlock.position() > 0) + lastBlock = lastBlock.previous(); + + // If we don't know yet the dummy text, let's guess it and use for this line and before. + charContext = characterContext(block, lastBlock); } - if (closingParenBlock || prevBlock.text().endsWith(',')) - dummyText = "&& a"; - buffer.insert(utf8Offset, dummyText); - extraLength += dummyText.length(); + dummyText = dummyTextForContext(charContext, closingBraceBlock); } + buffer.insert(utf8Offset, dummyText); + extraLength += dummyText.length(); + if (secondTry) { int nextLinePos = buffer.indexOf('\n', utf8Offset); if (nextLinePos < 0) @@ -170,7 +254,7 @@ int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool s if (nextLinePos > 0) { // If first try was not successful try to put ')' in the end of the line to close possibly - // unclosed parentheses. + // unclosed parenthesis. // TODO: Does it help to add different endings depending on the context? buffer.insert(nextLinePos, ')'); extraLength += 1; @@ -300,18 +384,6 @@ bool doNotIndentInContext(QTextDocument *doc, int pos) 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) @@ -355,23 +427,14 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer rangeStart = formattingRangeStart(startBlock, buffer, lastSaveRevision()); adjustFormatStyleForLineBreak(style, replacementsToKeep); - if (typedChar == QChar::Null) { - if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) { - if (utf8Offset > 0) { - buffer.insert(utf8Offset - 1, " //"); - utf8Offset += 3; - } + if (replacementsToKeep == ReplacementsToKeep::OnlyIndent) { + CharacterContext currentCharContext = CharacterContext::Unknown; + // Iterate backwards to reuse the same dummy text for all empty lines. + for (int index = endBlock.blockNumber(); index >= startBlock.blockNumber(); --index) { utf8Length += forceIndentWithExtraText(buffer, - cursorPositionInEditor < 0 - ? endBlock - : m_doc->findBlock(cursorPositionInEditor), + currentCharContext, + m_doc->findBlockByNumber(index), secondTry); - } else { - for (int index = startBlock.blockNumber(); index <= endBlock.blockNumber(); ++index) { - utf8Length += forceIndentWithExtraText(buffer, - m_doc->findBlockByNumber(index), - secondTry); - } } } @@ -432,9 +495,24 @@ TextEditor::Replacements ClangFormatBaseIndenter::format( static_cast<unsigned int>(utf8RangeLength)); } + clang::format::FormatStyle style = styleForFile(); + const std::string assumedFileName = m_fileName.toString().toStdString(); + clang::tooling::Replacements clangReplacements = clang::format::sortIncludes(style, + buffer.data(), + ranges, + assumedFileName); + auto changedCode = clang::tooling::applyAllReplacements(buffer.data(), clangReplacements); + QTC_ASSERT(changedCode, { + qDebug() << QString::fromStdString(llvm::toString(changedCode.takeError())); + return TextEditor::Replacements(); + }); + ranges = clang::tooling::calculateRangesAfterReplacements(clangReplacements, ranges); + clang::format::FormattingAttemptStatus status; - const clang::tooling::Replacements clangReplacements - = reformat(styleForFile(), buffer.data(), ranges, m_fileName.toString().toStdString(), &status); + const clang::tooling::Replacements formatReplacements + = reformat(style, *changedCode, ranges, m_fileName.toString().toStdString(), &status); + clangReplacements = clangReplacements.merge(formatReplacements); + const TextEditor::Replacements toReplace = utf16Replacements(m_doc, buffer, clangReplacements); applyReplacements(m_doc, toReplace); @@ -443,7 +521,6 @@ TextEditor::Replacements ClangFormatBaseIndenter::format( TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlock, const QTextBlock &endBlock, - const QByteArray &buffer, const QChar &typedChar, int cursorPositionInEditor) { @@ -461,10 +538,12 @@ TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlo cursorPositionInEditor += startBlock.position() - startBlockPosition; } + const QByteArray buffer = m_doc->toPlainText().toUtf8(); + ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent; if (formatWhileTyping() && (cursorPositionInEditor == -1 || cursorPositionInEditor >= startBlockPosition) - && (typedChar == QChar::Null || typedChar == ';' || typedChar == '}')) { + && (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. @@ -487,9 +566,7 @@ void ClangFormatBaseIndenter::indentBlocks(const QTextBlock &startBlock, const QChar &typedChar, int cursorPositionInEditor) { - const QByteArray buffer = m_doc->toPlainText().toUtf8(); - applyReplacements(m_doc, - indentsFor(startBlock, endBlock, buffer, typedChar, cursorPositionInEditor)); + applyReplacements(m_doc, indentsFor(startBlock, endBlock, typedChar, cursorPositionInEditor)); } void ClangFormatBaseIndenter::indent(const QTextCursor &cursor, @@ -533,15 +610,14 @@ int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings & /*tabSettings*/, int cursorPositionInEditor) { - const QByteArray buffer = m_doc->toPlainText().toUtf8(); TextEditor::Replacements toReplace = indentsFor(block, block, - buffer, QChar::Null, cursorPositionInEditor); if (toReplace.empty()) return -1; + const QByteArray buffer = m_doc->toPlainText().toUtf8(); return indentationForBlock(toReplace, buffer, block); } @@ -553,13 +629,12 @@ TextEditor::IndentationForBlock ClangFormatBaseIndenter::indentationForBlocks( 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); + const QByteArray buffer = m_doc->toPlainText().toUtf8(); for (const QTextBlock &block : blocks) ret.insert(block.blockNumber(), indentationForBlock(toReplace, buffer, block)); return ret; diff --git a/src/plugins/clangformat/clangformatbaseindenter.h b/src/plugins/clangformat/clangformatbaseindenter.h index b412b57d6d..87b5e0c927 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.h +++ b/src/plugins/clangformat/clangformatbaseindenter.h @@ -81,7 +81,6 @@ private: int cursorPositionInEditor); TextEditor::Replacements indentsFor(QTextBlock startBlock, const QTextBlock &endBlock, - const QByteArray &buffer, const QChar &typedChar, int cursorPositionInEditor); TextEditor::Replacements replacements(QByteArray buffer, diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp index faaf6d937f..72e1778999 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatconfigwidget.cpp @@ -59,6 +59,24 @@ ClangFormatConfigWidget::ClangFormatConfigWidget(ProjectExplorer::Project *proje { m_ui->setupUi(this); + m_preview = new TextEditor::SnippetEditorWidget(this); + m_ui->horizontalLayout_2->addWidget(m_preview); + if (m_project) { + m_ui->applyButton->show(); + hideGlobalCheckboxes(); + m_ui->overrideDefault->setChecked( + m_project->namedSettings(Constants::OVERRIDE_FILE_ID).toBool()); + } else { + m_ui->applyButton->hide(); + showGlobalCheckboxes(); + m_ui->overrideDefault->setChecked(ClangFormatSettings::instance().overrideDefaultFile()); + } + + connect(m_ui->overrideDefault, &QCheckBox::toggled, this, [this](bool checked) { + if (checked) + createStyleFileIfNeeded(!m_project); + initialize(); + }); initialize(); } @@ -81,15 +99,19 @@ void ClangFormatConfigWidget::showGlobalCheckboxes() m_ui->formatOnSave->show(); } +static bool projectConfigExists() +{ + return Utils::FileName::fromString(Core::ICore::userResourcePath()) + .appendPath("clang-format") + .appendPath(currentProjectUniqueId()) + .appendPath((Constants::SETTINGS_FILE_NAME)) + .exists(); +} + void ClangFormatConfigWidget::initialize() { - m_ui->projectHasClangFormat->show(); - m_ui->clangFormatOptionsTable->show(); - m_ui->applyButton->show(); - hideGlobalCheckboxes(); + m_ui->projectHasClangFormat->hide(); - m_preview = new TextEditor::SnippetEditorWidget(this); - m_ui->horizontalLayout_2->addWidget(m_preview); m_preview->setPlainText(QLatin1String(CppTools::Constants::DEFAULT_CODE_STYLE_SNIPPETS[0])); m_preview->textDocument()->setIndenter(new ClangFormatIndenter(m_preview->document())); m_preview->textDocument()->setFontSettings(TextEditor::TextEditorSettings::fontSettings()); @@ -103,21 +125,15 @@ void ClangFormatConfigWidget::initialize() if (lastItem->spacerItem()) m_ui->verticalLayout->removeItem(lastItem); - if (m_project - && !m_project->projectDirectory().appendPath(Constants::SETTINGS_FILE_NAME).exists()) { - m_ui->projectHasClangFormat->setText(tr("No .clang-format file for the project.")); + if (!m_ui->overrideDefault->isChecked()) { m_ui->clangFormatOptionsTable->hide(); - m_ui->applyButton->hide(); + m_preview->hide(); m_ui->verticalLayout->addStretch(1); - - connect(m_ui->createFileButton, &QPushButton::clicked, this, [this]() { - createStyleFileIfNeeded(false); - initialize(); - }); return; } - m_ui->createFileButton->hide(); + m_ui->clangFormatOptionsTable->show(); + m_preview->show(); Utils::FileName fileName; if (m_project) { @@ -126,19 +142,13 @@ void ClangFormatConfigWidget::initialize() fileName = m_project->projectFilePath().appendPath("snippet.cpp"); } else { const Project *currentProject = SessionManager::startupProject(); - if (!currentProject - || !currentProject->projectDirectory() - .appendPath(Constants::SETTINGS_FILE_NAME) - .exists()) { + if (!currentProject || !projectConfigExists()) { m_ui->projectHasClangFormat->hide(); } else { m_ui->projectHasClangFormat->setText( - tr("Current project has its own .clang-format file " + tr("Current project has its own overridden .clang-format file " "and can be configured in Projects > Code Style > C++.")); } - createStyleFileIfNeeded(true); - showGlobalCheckboxes(); - m_ui->applyButton->hide(); fileName = Utils::FileName::fromString(Core::ICore::userResourcePath()) .appendPath("snippet.cpp"); } @@ -160,7 +170,7 @@ void ClangFormatConfigWidget::fillTable() { clang::format::FormatStyle style = m_project ? currentProjectStyle() : currentGlobalStyle(); - std::string configText = clang::format::configurationAsText(style); + const std::string configText = clang::format::configurationAsText(style); m_ui->clangFormatOptionsTable->setPlainText(QString::fromStdString(configText)); } @@ -168,13 +178,19 @@ ClangFormatConfigWidget::~ClangFormatConfigWidget() = default; void ClangFormatConfigWidget::apply() { + ClangFormatSettings &settings = ClangFormatSettings::instance(); if (!m_project) { - ClangFormatSettings &settings = ClangFormatSettings::instance(); settings.setFormatCodeInsteadOfIndent(m_ui->formatAlways->isChecked()); settings.setFormatWhileTyping(m_ui->formatWhileTyping->isChecked()); settings.setFormatOnSave(m_ui->formatOnSave->isChecked()); - settings.write(); + settings.setOverrideDefaultFile(m_ui->overrideDefault->isChecked()); + } else { + m_project->setNamedSettings(Constants::OVERRIDE_FILE_ID, m_ui->overrideDefault->isChecked()); } + settings.write(); + + if (!m_ui->overrideDefault->isChecked()) + return; const QString text = m_ui->clangFormatOptionsTable->toPlainText(); clang::format::FormatStyle style; @@ -184,16 +200,18 @@ void ClangFormatConfigWidget::apply() QMessageBox::warning(this, tr("Error in ClangFormat configuration"), QString::fromStdString(error.message())); - fillTable(); - updatePreview(); + if (m_ui->overrideDefault->isChecked()) { + fillTable(); + updatePreview(); + } return; } - QString filePath; + QString filePath = Core::ICore::userResourcePath(); if (m_project) - filePath = m_project->projectDirectory().appendPath(Constants::SETTINGS_FILE_NAME).toString(); - else - filePath = Core::ICore::userResourcePath() + "/" + Constants::SETTINGS_FILE_NAME; + filePath += "/clang-format/" + currentProjectUniqueId(); + filePath += "/" + QLatin1String(Constants::SETTINGS_FILE_NAME); + QFile file(filePath); if (!file.open(QFile::WriteOnly)) return; @@ -201,7 +219,8 @@ void ClangFormatConfigWidget::apply() file.write(text.toUtf8()); file.close(); - updatePreview(); + if (m_ui->overrideDefault->isChecked()) + updatePreview(); } } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatconfigwidget.ui b/src/plugins/clangformat/clangformatconfigwidget.ui index 41e40ef1fd..c8225981f5 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.ui +++ b/src/plugins/clangformat/clangformatconfigwidget.ui @@ -55,6 +55,13 @@ </widget> </item> <item> + <widget class="QCheckBox" name="overrideDefault"> + <property name="text"> + <string>Override Clang Format configuration file</string> + </property> + </widget> + </item> + <item> <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> <widget class="QPlainTextEdit" name="clangFormatOptionsTable"/> @@ -64,13 +71,6 @@ <item> <layout class="QHBoxLayout" name="horizontalLayout"> <item> - <widget class="QPushButton" name="createFileButton"> - <property name="text"> - <string>Create Clang Format Configuration File</string> - </property> - </widget> - </item> - <item> <widget class="QPushButton" name="applyButton"> <property name="text"> <string>Apply</string> diff --git a/src/plugins/clangformat/clangformatconstants.h b/src/plugins/clangformat/clangformatconstants.h index 8b7cbcf9bd..2635dbedea 100644 --- a/src/plugins/clangformat/clangformatconstants.h +++ b/src/plugins/clangformat/clangformatconstants.h @@ -34,5 +34,7 @@ static const char SETTINGS_ID[] = "ClangFormat"; static const char FORMAT_CODE_INSTEAD_OF_INDENT_ID[] = "ClangFormat.FormatCodeInsteadOfIndent"; static const char FORMAT_WHILE_TYPING_ID[] = "ClangFormat.FormatWhileTyping"; static const char FORMAT_CODE_ON_SAVE_ID[] = "ClangFormat.FormatCodeOnSave"; +static const char OVERRIDE_FILE_ID[] = "ClangFormat.OverrideFile"; +static const char OPEN_CURRENT_CONFIG_ID[] = "ClangFormat.OpenCurrentConfig"; } // namespace Constants } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatindenter.cpp b/src/plugins/clangformat/clangformatindenter.cpp index 42cedb7b6c..381762ee7f 100644 --- a/src/plugins/clangformat/clangformatindenter.cpp +++ b/src/plugins/clangformat/clangformatindenter.cpp @@ -57,7 +57,7 @@ bool ClangFormatIndenter::formatWhileTyping() const Utils::optional<TabSettings> ClangFormatIndenter::tabSettings() const { - FormatStyle style = currentProjectStyle(); + FormatStyle style = styleForFile(); TabSettings tabSettings; switch (style.UseTab) { diff --git a/src/plugins/clangformat/clangformatplugin.cpp b/src/plugins/clangformat/clangformatplugin.cpp index 932234f982..e82802ab30 100644 --- a/src/plugins/clangformat/clangformatplugin.cpp +++ b/src/plugins/clangformat/clangformatplugin.cpp @@ -26,16 +26,23 @@ #include "clangformatplugin.h" #include "clangformatconfigwidget.h" +#include "clangformatconstants.h" #include "clangformatindenter.h" +#include "clangformatutils.h" #include <utils/qtcassert.h> -#include <coreplugin/icore.h> -#include <coreplugin/icontext.h> +#include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/actionmanager/command.h> -#include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/coreconstants.h> +#include <coreplugin/editormanager/editormanager.h> +#include <coreplugin/editormanager/ieditor.h> +#include <coreplugin/icontext.h> +#include <coreplugin/icore.h> +#include <coreplugin/idocument.h> + +#include <cppeditor/cppeditorconstants.h> #include <cpptools/cppcodestylepreferencesfactory.h> #include <cpptools/cpptoolsconstants.h> @@ -103,6 +110,48 @@ bool ClangFormatPlugin::initialize(const QStringList &arguments, QString *errorS Q_UNUSED(errorString); #ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED replaceCppCodeStyle(); + + Core::ActionContainer *contextMenu = Core::ActionManager::actionContainer( + CppEditor::Constants::M_CONTEXT); + if (contextMenu) { + auto openClangFormatConfigAction + = new QAction(tr("Open Used .clang-format Configuration File"), this); + Core::Command *command + = Core::ActionManager::registerAction(openClangFormatConfigAction, + Constants::OPEN_CURRENT_CONFIG_ID); + contextMenu->addSeparator(); + contextMenu->addAction(command); + + if (Core::EditorManager::currentEditor()) { + const Core::IDocument *doc = Core::EditorManager::currentEditor()->document(); + if (doc) + openClangFormatConfigAction->setData(doc->filePath().toString()); + } + + connect(openClangFormatConfigAction, + &QAction::triggered, + this, + [openClangFormatConfigAction]() { + const QString fileName = openClangFormatConfigAction->data().toString(); + if (!fileName.isEmpty()) { + const QString clangFormatConfigPath = configForFile( + Utils::FileName::fromString(fileName)); + Core::EditorManager::openEditor(clangFormatConfigPath); + } + }); + + connect(Core::EditorManager::instance(), + &Core::EditorManager::currentEditorChanged, + this, + [openClangFormatConfigAction](Core::IEditor *editor) { + if (!editor) + return; + + const Core::IDocument *doc = editor->document(); + if (doc) + openClangFormatConfigAction->setData(doc->filePath().toString()); + }); + } #endif return true; } diff --git a/src/plugins/clangformat/clangformatsettings.cpp b/src/plugins/clangformat/clangformatsettings.cpp index 8be2b3cefe..8f70130ae3 100644 --- a/src/plugins/clangformat/clangformatsettings.cpp +++ b/src/plugins/clangformat/clangformatsettings.cpp @@ -46,6 +46,8 @@ ClangFormatSettings::ClangFormatSettings() .toBool(); m_formatOnSave = settings->value(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), false) .toBool(); + m_overrideDefaultFile = settings->value(QLatin1String(Constants::OVERRIDE_FILE_ID), false) + .toBool(); settings->endGroup(); } @@ -57,6 +59,7 @@ void ClangFormatSettings::write() const m_formatCodeInsteadOfIndent); settings->setValue(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), m_formatWhileTyping); settings->setValue(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), m_formatOnSave); + settings->setValue(QLatin1String(Constants::OVERRIDE_FILE_ID), m_overrideDefaultFile); settings->endGroup(); } @@ -90,4 +93,14 @@ bool ClangFormatSettings::formatOnSave() const return m_formatOnSave; } +void ClangFormatSettings::setOverrideDefaultFile(bool enable) +{ + m_overrideDefaultFile = enable; +} + +bool ClangFormatSettings::overrideDefaultFile() const +{ + return m_overrideDefaultFile; +} + } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatsettings.h b/src/plugins/clangformat/clangformatsettings.h index 0ea9ed9747..9344cf34a9 100644 --- a/src/plugins/clangformat/clangformatsettings.h +++ b/src/plugins/clangformat/clangformatsettings.h @@ -25,6 +25,8 @@ #pragma once +#include <QString> + namespace ClangFormat { class ClangFormatSettings @@ -43,10 +45,14 @@ public: void setFormatOnSave(bool enable); bool formatOnSave() const; + + void setOverrideDefaultFile(bool enable); + bool overrideDefaultFile() const; private: bool m_formatCodeInsteadOfIndent = false; bool m_formatWhileTyping = false; bool m_formatOnSave = false; + bool m_overrideDefaultFile = false; }; } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index babe94da24..74c4165a34 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -26,6 +26,7 @@ #include "clangformatutils.h" #include "clangformatconstants.h" +#include "clangformatsettings.h" #include <coreplugin/icore.h> #include <cpptools/cppcodestylesettings.h> @@ -33,6 +34,8 @@ #include <projectexplorer/project.h> #include <projectexplorer/session.h> +#include <QCryptographicHash> + using namespace clang; using namespace format; using namespace llvm; @@ -42,6 +45,104 @@ using namespace TextEditor; namespace ClangFormat { +static clang::format::FormatStyle qtcStyle() +{ + clang::format::FormatStyle style = getLLVMStyle(); + style.Language = FormatStyle::LK_Cpp; + style.AccessModifierOffset = -4; + style.AlignAfterOpenBracket = FormatStyle::BAS_Align; + style.AlignConsecutiveAssignments = false; + style.AlignConsecutiveDeclarations = false; + style.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign; + style.AlignOperands = true; + style.AlignTrailingComments = true; + style.AllowAllParametersOfDeclarationOnNextLine = true; + style.AllowShortBlocksOnASingleLine = false; + style.AllowShortCaseLabelsOnASingleLine = false; + style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; + style.AllowShortIfStatementsOnASingleLine = false; + style.AllowShortLoopsOnASingleLine = false; + style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; + style.AlwaysBreakBeforeMultilineStrings = false; + style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes; + style.BinPackArguments = false; + style.BinPackParameters = false; + style.BraceWrapping.AfterClass = true; + style.BraceWrapping.AfterControlStatement = false; + style.BraceWrapping.AfterEnum = false; + style.BraceWrapping.AfterFunction = true; + style.BraceWrapping.AfterNamespace = false; + style.BraceWrapping.AfterObjCDeclaration = false; + style.BraceWrapping.AfterStruct = true; + style.BraceWrapping.AfterUnion = false; + style.BraceWrapping.BeforeCatch = false; + style.BraceWrapping.BeforeElse = false; + style.BraceWrapping.IndentBraces = false; + style.BraceWrapping.SplitEmptyFunction = false; + style.BraceWrapping.SplitEmptyRecord = false; + style.BraceWrapping.SplitEmptyNamespace = false; + style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; + style.BreakBeforeBraces = FormatStyle::BS_Custom; + style.BreakBeforeTernaryOperators = true; + style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma; + style.BreakAfterJavaFieldAnnotations = false; + style.BreakStringLiterals = true; + style.ColumnLimit = 100; + style.CommentPragmas = "^ IWYU pragma:"; + style.CompactNamespaces = false; + style.ConstructorInitializerAllOnOneLineOrOnePerLine = false; + style.ConstructorInitializerIndentWidth = 4; + style.ContinuationIndentWidth = 4; + style.Cpp11BracedListStyle = true; + style.DerivePointerAlignment = false; + style.DisableFormat = false; + style.ExperimentalAutoDetectBinPacking = false; + style.FixNamespaceComments = true; + style.ForEachMacros = {"forever", "foreach", "Q_FOREACH", "BOOST_FOREACH"}; + style.IncludeStyle.IncludeCategories = {{"^<Q.*", 200}}; + style.IncludeStyle.IncludeIsMainRegex = "(Test)?$"; + style.IndentCaseLabels = false; + style.IndentWidth = 4; + style.IndentWrappedFunctionNames = false; + style.JavaScriptQuotes = FormatStyle::JSQS_Leave; + style.JavaScriptWrapImports = true; + style.KeepEmptyLinesAtTheStartOfBlocks = false; + // Do not add QT_BEGIN_NAMESPACE/QT_END_NAMESPACE as this will indent lines in between. + style.MacroBlockBegin = ""; + style.MacroBlockEnd = ""; + style.MaxEmptyLinesToKeep = 1; + style.NamespaceIndentation = FormatStyle::NI_None; + style.ObjCBlockIndentWidth = 4; + style.ObjCSpaceAfterProperty = false; + style.ObjCSpaceBeforeProtocolList = true; + style.PenaltyBreakAssignment = 150; + style.PenaltyBreakBeforeFirstCallParameter = 300; + style.PenaltyBreakComment = 500; + style.PenaltyBreakFirstLessLess = 400; + style.PenaltyBreakString = 600; + style.PenaltyExcessCharacter = 50; + style.PenaltyReturnTypeOnItsOwnLine = 300; + style.PointerAlignment = FormatStyle::PAS_Right; + style.ReflowComments = false; + style.SortIncludes = true; + style.SortUsingDeclarations = true; + style.SpaceAfterCStyleCast = true; + style.SpaceAfterTemplateKeyword = false; + style.SpaceBeforeAssignmentOperators = true; + style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements; + style.SpaceInEmptyParentheses = false; + style.SpacesBeforeTrailingComments = 1; + style.SpacesInAngles = false; + style.SpacesInContainerLiterals = false; + style.SpacesInCStyleCastParentheses = false; + style.SpacesInParentheses = false; + style.SpacesInSquareBrackets = false; + style.Standard = FormatStyle::LS_Cpp11; + style.TabWidth = 4; + style.UseTab = FormatStyle::UT_Never; + return style; +} + static void applyTabSettings(clang::format::FormatStyle &style, const TabSettings &settings) { style.IndentWidth = static_cast<unsigned>(settings.m_indentSize); @@ -63,72 +164,86 @@ static void applyTabSettings(clang::format::FormatStyle &style, const TabSetting } } -static void applyCppCodeStyleSettings(clang::format::FormatStyle &style, - const CppCodeStyleSettings &settings) +static bool useGlobalOverriddenSettings() { - style.IndentCaseLabels = settings.indentSwitchLabels; - style.AlignOperands = settings.alignAssignments; - style.NamespaceIndentation = FormatStyle::NI_None; - if (settings.indentNamespaceBody) - style.NamespaceIndentation = FormatStyle::NI_All; + return ClangFormatSettings::instance().overrideDefaultFile(); +} - style.BraceWrapping.IndentBraces = false; - if (settings.indentBlockBraces) { - if (settings.indentClassBraces && settings.indentEnumBraces - && settings.indentNamespaceBraces && settings.indentFunctionBraces) { - style.BraceWrapping.IndentBraces = true; - } else { - style.BreakBeforeBraces = FormatStyle::BS_GNU; - } - } +QString currentProjectUniqueId() +{ + const Project *project = SessionManager::startupProject(); + if (!project) + return QString(); - if (settings.bindStarToIdentifier || settings.bindStarToRightSpecifier) - style.PointerAlignment = FormatStyle::PAS_Right; - else - style.PointerAlignment = FormatStyle::PAS_Left; + return QString::fromUtf8(QCryptographicHash::hash(project->projectFilePath().toString().toUtf8(), + QCryptographicHash::Md5) + .toHex(0)); +} + +static bool useProjectOverriddenSettings() +{ + const Project *project = SessionManager::startupProject(); + return project ? project->namedSettings(Constants::OVERRIDE_FILE_ID).toBool() : false; +} - style.AccessModifierOffset = settings.indentAccessSpecifiers - ? 0 - : - static_cast<int>(style.IndentWidth); +static Utils::FileName globalPath() +{ + return Utils::FileName::fromString(Core::ICore::userResourcePath()); } static Utils::FileName projectPath() { const Project *project = SessionManager::startupProject(); if (project) - return project->projectDirectory(); + return globalPath().appendPath("clang-format").appendPath(currentProjectUniqueId()); return Utils::FileName(); } -static Utils::FileName globalPath() +static QString findConfig(Utils::FileName fileName) { - return Utils::FileName::fromString(Core::ICore::userResourcePath()); + QDir parentDir(fileName.parentDir().toString()); + while (!parentDir.exists(Constants::SETTINGS_FILE_NAME) + && !parentDir.exists(Constants::SETTINGS_FILE_ALT_NAME)) { + if (!parentDir.cdUp()) + return QString(); + } + + if (parentDir.exists(Constants::SETTINGS_FILE_NAME)) + return parentDir.filePath(Constants::SETTINGS_FILE_NAME); + return parentDir.filePath(Constants::SETTINGS_FILE_ALT_NAME); } -static QString configForFile(Utils::FileName fileName) +static QString configForFile(Utils::FileName fileName, bool checkForSettings) { - Utils::FileName topProjectPath = projectPath(); - if (topProjectPath.isEmpty()) - return QString(); + QDir overrideDir; + if (!checkForSettings || useProjectOverriddenSettings()) { + overrideDir = projectPath().toString(); + if (!overrideDir.isEmpty() && overrideDir.exists(Constants::SETTINGS_FILE_NAME)) + return overrideDir.filePath(Constants::SETTINGS_FILE_NAME); + } - QDir projectDir(fileName.parentDir().toString()); - while (!projectDir.exists(Constants::SETTINGS_FILE_NAME) - && !projectDir.exists(Constants::SETTINGS_FILE_ALT_NAME)) { - if (projectDir.path() == topProjectPath.toString() - || !Utils::FileName::fromString(projectDir.path()).isChildOf(topProjectPath) - || !projectDir.cdUp()) { - return QString(); - } + if (!checkForSettings || useGlobalOverriddenSettings()) { + overrideDir = globalPath().toString(); + if (!overrideDir.isEmpty() && overrideDir.exists(Constants::SETTINGS_FILE_NAME)) + return overrideDir.filePath(Constants::SETTINGS_FILE_NAME); } - if (projectDir.exists(Constants::SETTINGS_FILE_NAME)) - return projectDir.filePath(Constants::SETTINGS_FILE_NAME); - return projectDir.filePath(Constants::SETTINGS_FILE_ALT_NAME); + return findConfig(fileName); +} + +QString configForFile(Utils::FileName fileName) +{ + return configForFile(fileName, true); +} + +Utils::FileName assumedPathForConfig(const QString &configFile) +{ + Utils::FileName fileName = Utils::FileName::fromString(configFile); + return fileName.parentDir().appendPath("test.cpp"); } -static clang::format::FormatStyle constructStyle(bool isGlobal, - const QByteArray &baseStyle = QByteArray()) +static clang::format::FormatStyle constructStyle(const QByteArray &baseStyle = QByteArray()) { if (!baseStyle.isEmpty()) { // Try to get the style for this base style. @@ -144,21 +259,7 @@ static clang::format::FormatStyle constructStyle(bool isGlobal, // Fallthrough to the default style. } - FormatStyle style = getLLVMStyle(); - style.BreakBeforeBraces = FormatStyle::BS_Custom; - - const CppCodeStyleSettings codeStyleSettings = isGlobal - ? CppCodeStyleSettings::currentGlobalCodeStyle() - : CppCodeStyleSettings::currentProjectCodeStyle() - .value_or(CppCodeStyleSettings::currentGlobalCodeStyle()); - const TabSettings tabSettings = isGlobal - ? CppCodeStyleSettings::currentGlobalTabSettings() - : CppCodeStyleSettings::currentProjectTabSettings(); - - applyTabSettings(style, tabSettings); - applyCppCodeStyleSettings(style, codeStyleSettings); - - return style; + return qtcStyle(); } void createStyleFileIfNeeded(bool isGlobal) @@ -169,9 +270,21 @@ void createStyleFileIfNeeded(bool isGlobal) if (QFile::exists(configFile)) return; + QDir().mkpath(path.parentDir().toString()); + if (!isGlobal) { + const Project *project = SessionManager::startupProject(); + Utils::FileName possibleProjectConfig = project->rootProjectDirectory().appendPath( + Constants::SETTINGS_FILE_NAME); + if (possibleProjectConfig.exists()) { + // Just copy th .clang-format if current project has one. + QFile::copy(possibleProjectConfig.toString(), configFile); + return; + } + } + std::fstream newStyleFile(configFile.toStdString(), std::fstream::out); if (newStyleFile.is_open()) { - newStyleFile << clang::format::configurationAsText(constructStyle(isGlobal)); + newStyleFile << clang::format::configurationAsText(constructStyle()); newStyleFile.close(); } } @@ -198,17 +311,13 @@ static QByteArray configBaseStyleName(const QString &configFile) .trimmed(); } -clang::format::FormatStyle styleForFile(Utils::FileName fileName) +static clang::format::FormatStyle styleForFile(Utils::FileName fileName, bool checkForSettings) { - bool isGlobal = false; - QString configFile = configForFile(fileName); - if (configFile.isEmpty()) { - Utils::FileName path = fileName = globalPath(); - fileName.appendPath(Constants::SAMPLE_FILE_NAME); - createStyleFileIfNeeded(true); - configFile = path.appendPath(Constants::SETTINGS_FILE_NAME).toString(); - } + QString configFile = configForFile(fileName, checkForSettings); + if (configFile.isEmpty()) + return constructStyle(); + fileName = assumedPathForConfig(configFile); Expected<FormatStyle> style = format::getStyle("file", fileName.toString().toStdString(), "none"); @@ -219,17 +328,21 @@ clang::format::FormatStyle styleForFile(Utils::FileName fileName) // do nothing }); - return constructStyle(isGlobal, configBaseStyleName(configFile)); + return constructStyle(configBaseStyleName(configFile)); } -clang::format::FormatStyle currentProjectStyle() +clang::format::FormatStyle styleForFile(Utils::FileName fileName) { - return styleForFile(projectPath().appendPath(Constants::SAMPLE_FILE_NAME)); + return styleForFile(fileName, true); } -clang::format::FormatStyle currentGlobalStyle() +clang::format::FormatStyle currentProjectStyle() { - return styleForFile(globalPath().appendPath(Constants::SAMPLE_FILE_NAME)); + return styleForFile(projectPath().appendPath(Constants::SAMPLE_FILE_NAME), false); } +clang::format::FormatStyle currentGlobalStyle() +{ + return styleForFile(globalPath().appendPath(Constants::SAMPLE_FILE_NAME), false); } +} // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatutils.h b/src/plugins/clangformat/clangformatutils.h index 41e2b5611f..bd53076943 100644 --- a/src/plugins/clangformat/clangformatutils.h +++ b/src/plugins/clangformat/clangformatutils.h @@ -25,6 +25,7 @@ #pragma once +#include <coreplugin/id.h> #include <utils/fileutils.h> #include <clang/Format/Format.h> @@ -37,10 +38,13 @@ namespace ClangFormat { // Creates the style for the current project or the global style if needed. void createStyleFileIfNeeded(bool isGlobal); +QString currentProjectUniqueId(); + clang::format::FormatStyle currentProjectStyle(); clang::format::FormatStyle currentGlobalStyle(); // Is the style from the matching .clang-format file or global one if it's not found. +QString configForFile(Utils::FileName fileName); clang::format::FormatStyle styleForFile(Utils::FileName fileName); } diff --git a/src/plugins/clangtools/clangtidyclazytool.cpp b/src/plugins/clangtools/clangtidyclazytool.cpp index 2dc381f6a3..43858cc865 100644 --- a/src/plugins/clangtools/clangtidyclazytool.cpp +++ b/src/plugins/clangtools/clangtidyclazytool.cpp @@ -452,12 +452,12 @@ void ClangTidyClazyTool::handleStateUpdate() if (issuesFound) message = tr("Running - %n diagnostics", nullptr, issuesFound); else - message = tr("Running - No diagnostics", nullptr, issuesFound); + message = tr("Running - No diagnostics"); } else { if (issuesFound) message = tr("Finished - %n diagnostics", nullptr, issuesFound); else - message = tr("Finished - No diagnostics", nullptr, issuesFound); + message = tr("Finished - No diagnostics"); } Debugger::showPermanentStatusMessage(message); diff --git a/src/plugins/coreplugin/find/searchresulttreeview.cpp b/src/plugins/coreplugin/find/searchresulttreeview.cpp index 6a9b7067bf..0ca09fcefd 100644 --- a/src/plugins/coreplugin/find/searchresulttreeview.cpp +++ b/src/plugins/coreplugin/find/searchresulttreeview.cpp @@ -78,6 +78,21 @@ void SearchResultTreeView::addResults(const QList<SearchResultItem> &items, Sear } } +void SearchResultTreeView::keyPressEvent(QKeyEvent *event) +{ + if ((event->key() == Qt::Key_Return + || event->key() == Qt::Key_Enter) + && event->modifiers() == 0 + && currentIndex().isValid() + && state() != QAbstractItemView::EditingState) { + const SearchResultItem item + = model()->data(currentIndex(), ItemDataRoles::ResultItemRole).value<SearchResultItem>(); + emit jumpToSearchResult(item); + return; + } + TreeView::keyPressEvent(event); +} + void SearchResultTreeView::emitJumpToSearchResult(const QModelIndex &index) { if (model()->data(index, ItemDataRoles::IsGeneratedRole).toBool()) diff --git a/src/plugins/coreplugin/find/searchresulttreeview.h b/src/plugins/coreplugin/find/searchresulttreeview.h index 961940fe01..eb11d29a7d 100644 --- a/src/plugins/coreplugin/find/searchresulttreeview.h +++ b/src/plugins/coreplugin/find/searchresulttreeview.h @@ -49,6 +49,8 @@ public: SearchResultTreeModel *model() const; void addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode); + void keyPressEvent(QKeyEvent *event) override; + signals: void jumpToSearchResult(const SearchResultItem &item); diff --git a/src/plugins/coreplugin/helpitem.h b/src/plugins/coreplugin/helpitem.h index 15ff585ca8..c258eed0d8 100644 --- a/src/plugins/coreplugin/helpitem.h +++ b/src/plugins/coreplugin/helpitem.h @@ -84,10 +84,9 @@ public: const Links &links() const; const Links bestLinks() const; const QString keyword() const; - -private: bool isFuzzyMatch() const; +private: QUrl m_helpUrl; QStringList m_helpIds; QString m_docMark; diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 2421bd776a..994c9e5d0e 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -252,6 +252,14 @@ void LocatorModel::addEntries(const QList<LocatorFilterEntry> &entries) CompletionList::CompletionList(QWidget *parent) : Utils::TreeView(parent) { + // on macOS and Windows the popup doesn't really get focus, so fake the selection color + // which would then just be a very light gray, but should look as if it had focus + QPalette p = palette(); + p.setBrush(QPalette::Inactive, + QPalette::Highlight, + p.brush(QPalette::Normal, QPalette::Highlight)); + setPalette(p); + setItemDelegate(new CompletionDelegate(this)); setRootIsDecorated(false); setUniformRowHeights(true); diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp index 3f19d4b9b9..eb411bdaa9 100644 --- a/src/plugins/coreplugin/outputpanemanager.cpp +++ b/src/plugins/coreplugin/outputpanemanager.cpp @@ -507,7 +507,6 @@ void OutputPaneManager::showPage(int idx, int flags) ensurePageVisible(idx); IOutputPane *out = g_outputPanes.at(idx).pane; - out->visibilityChanged(true); if (flags & IOutputPane::WithFocus) { if (out->canFocus()) out->setFocus(); @@ -538,7 +537,10 @@ void OutputPaneManager::setCurrentIndex(int idx) m_outputWidgetPane->setCurrentIndex(idx); m_opToolBarWidgets->setCurrentIndex(idx); - IOutputPane *pane = g_outputPanes.at(idx).pane; + OutputPaneData &data = g_outputPanes[idx]; + IOutputPane *pane = data.pane; + data.button->show(); + data.buttonVisible = true; pane->visibilityChanged(true); bool canNavigate = pane->canNavigate(); @@ -574,8 +576,6 @@ void OutputPaneManager::popupMenu() data.button->hide(); data.buttonVisible = false; } else { - data.button->show(); - data.buttonVisible = true; showPage(idx, IOutputPane::ModeSwitch); } } diff --git a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp index e19a94513d..4f03a681f0 100644 --- a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp +++ b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp @@ -860,11 +860,11 @@ void ClangDiagnosticConfigsWidget::syncClazyChecksGroupBox() return !m_clazySortFilterProxyModel->filterAcceptsRow(index.row(), index.parent()); }; const bool hasEnabledButHidden = m_clazyTreeModel->hasEnabledButNotVisibleChecks(isHidden); - const QString title = hasEnabledButHidden ? tr("Checks (%1 enabled, some are filtered out)") - : tr("Checks (%1 enabled)"); - - const QStringList checks = m_clazyTreeModel->enabledChecks(); - m_clazyChecks->checksGroupBox->setTitle(title.arg(checks.count())); + const int checksCount = m_clazyTreeModel->enabledChecks().count(); + const QString title = hasEnabledButHidden ? tr("Checks (%n enabled, some are filtered out)", + nullptr, checksCount) + : tr("Checks (%n enabled)", nullptr, checksCount); + m_clazyChecks->checksGroupBox->setTitle(title); } void ClangDiagnosticConfigsWidget::updateConfig(const ClangDiagnosticConfig &config) diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp index e5685dc5e0..8dfe0c7977 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.cpp +++ b/src/plugins/cpptools/compileroptionsbuilder.cpp @@ -172,7 +172,7 @@ void CompilerOptionsBuilder::addSyntaxOnly() isClStyle() ? add("/Zs") : add("-fsyntax-only"); } -static QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objcExt) +QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objcExt) { QStringList options; @@ -741,6 +741,15 @@ void CompilerOptionsBuilder::evaluateCompilerFlags() continue; } + if (option.startsWith("/Y", Qt::CaseSensitive) + || (option.startsWith("/F", Qt::CaseSensitive) && option != "/F")) { + // Precompiled header flags. + // Skip also the next option if it's not glued to the current one. + if (option.size() > 3) + skipNext = true; + continue; + } + // Check whether a language version is already used. QString theOption = option; if (theOption.startsWith("-std=")) { diff --git a/src/plugins/cpptools/compileroptionsbuilder.h b/src/plugins/cpptools/compileroptionsbuilder.h index 03564ab616..349279710a 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.h +++ b/src/plugins/cpptools/compileroptionsbuilder.h @@ -40,6 +40,7 @@ enum class UseBuildSystemWarnings : char { Yes, No }; CPPTOOLS_EXPORT QStringList XclangArgs(const QStringList &args); CPPTOOLS_EXPORT QStringList clangArgsForCl(const QStringList &args); +CPPTOOLS_EXPORT QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objcExt); class CPPTOOLS_EXPORT CompilerOptionsBuilder { diff --git a/src/plugins/cpptools/cppfilesettingspage.ui b/src/plugins/cpptools/cppfilesettingspage.ui index 9edf2cd5da..7bb13449ac 100644 --- a/src/plugins/cpptools/cppfilesettingspage.ui +++ b/src/plugins/cpptools/cppfilesettingspage.ui @@ -99,10 +99,10 @@ These prefixes are used in addition to current file name on Switch Header/Source <item row="7" column="1"> <widget class="QCheckBox" name="headerPragmaOnceCheckBox"> <property name="toolTip"> - <string>Uses #pragma once instead of #ifndef include guards.</string> + <string>Uses "#pragma once" instead of "#ifndef" include guards.</string> </property> <property name="text"> - <string>Use '#pragma once' instead of '#ifndef' guards</string> + <string>Use "#pragma once" instead of "#ifndef" guards</string> </property> </widget> </item> diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp index 8068c27d0b..d2ca6d5d0b 100644 --- a/src/plugins/cpptools/cpptoolsplugin.cpp +++ b/src/plugins/cpptools/cpptoolsplugin.cpp @@ -211,7 +211,7 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error) expander->registerVariable( "Cpp:PragmaOnce", - tr("Insert #pragma once instead of #ifndef include guards into header file"), + tr("Insert \"#pragma once\" instead of \"#ifndef\" include guards into header file"), [] { return usePragmaOnce() ? QString("true") : QString(); }); return true; diff --git a/src/plugins/debugger/console/console.h b/src/plugins/debugger/console/console.h index c46add0a86..4690283a34 100644 --- a/src/plugins/debugger/console/console.h +++ b/src/plugins/debugger/console/console.h @@ -58,7 +58,7 @@ public: QWidget *outputWidget(QWidget *) override; QList<QWidget *> toolBarWidgets() const override; - QString displayName() const override { return tr("Debugger Console"); } + QString displayName() const override { return tr("QML Debugger Console"); } int priorityInStatusBar() const override; void clearContents() override; void visibilityChanged(bool visible) override; diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index adc81bee69..4a7fb5d4a3 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -748,7 +748,8 @@ void DebuggerItemManagerPrivate::autoDetectGdbOrLldbDebuggers() dir.setPath(base.toFileInfo().absoluteFilePath()); foreach (const QString &entry, dir.entryList()) { if (entry.startsWith("lldb-platform-") - || entry.startsWith("lldb-gdbserver-")) { + || entry.startsWith("lldb-gdbserver-") + || entry.startsWith("lldb-mi-")) { continue; } suspects.append(FileName::fromString(dir.absoluteFilePath(entry))); diff --git a/src/plugins/debugger/debuggerkitinformation.cpp b/src/plugins/debugger/debuggerkitinformation.cpp index b85962bd0e..9783184346 100644 --- a/src/plugins/debugger/debuggerkitinformation.cpp +++ b/src/plugins/debugger/debuggerkitinformation.cpp @@ -152,24 +152,7 @@ DebuggerKitAspect::DebuggerKitAspect() setPriority(28000); } -QVariant DebuggerKitAspect::defaultValue(const Kit *k) const -{ - const Abi toolChainAbi = ToolChainKitAspect::targetAbi(k); - const Utils::FileNameList paths = Environment::systemEnvironment().path(); - QVariant nextBestFit; - for (const DebuggerItem &item : DebuggerItemManager::debuggers()) { - for (const Abi &targetAbi : item.abis()) { - if (targetAbi.isCompatibleWith(toolChainAbi)) { - if (paths.contains(item.command())) - return item.id(); // prefer debuggers found in PATH over those found elsewhere - if (nextBestFit.isNull()) - nextBestFit = item.id(); - } - } - } - - return nextBestFit; -} +QVariant DebuggerKitAspect::defaultValue(const Kit *) const { return QVariant(); } void DebuggerKitAspect::setup(Kit *k) { diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp index 096c03db16..0ddb983dbe 100644 --- a/src/plugins/debugger/debuggermainwindow.cpp +++ b/src/plugins/debugger/debuggermainwindow.cpp @@ -119,6 +119,7 @@ public: void resetCurrentPerspective(); int indexInChooser(Perspective *perspective) const; void fixupLayoutIfNeeded(); + void updatePerspectiveChooserWidth(); DebuggerMainWindow *q = nullptr; Perspective *m_currentPerspective = nullptr; @@ -416,10 +417,17 @@ void DebuggerMainWindowPrivate::selectPerspective(Perspective *perspective) fixupLayoutIfNeeded(); } + updatePerspectiveChooserWidth(); +} + +void DebuggerMainWindowPrivate::updatePerspectiveChooserWidth() +{ + Perspective *perspective = m_currentPerspective; int index = indexInChooser(m_currentPerspective); if (index == -1) { - if (Perspective *parent = Perspective::findPerspective(m_currentPerspective->d->m_parentPerspectiveId)) - index = indexInChooser(parent); + perspective = Perspective::findPerspective(m_currentPerspective->d->m_parentPerspectiveId); + if (perspective) + index = indexInChooser(perspective); } if (index != -1) { diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 5bb4845073..19b4011338 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -61,6 +61,7 @@ #include <utils/temporarydirectory.h> #include <utils/temporaryfile.h> #include <utils/url.h> +#include <utils/winutils.h> #include <coreplugin/icontext.h> #include <coreplugin/icore.h> @@ -565,6 +566,17 @@ void DebuggerRunTool::start() if (!fixupParameters()) return; + if (m_runParameters.cppEngineType == CdbEngineType + && Utils::is64BitWindowsBinary(m_runParameters.inferior.executable) + && !Utils::is64BitWindowsBinary(m_runParameters.debugger.executable)) { + reportFailure( + DebuggerPlugin::tr( + "%1 is a 64 bit executable which can not be debugged by a 32 bit Debugger.\n" + "Please select a 64 bit Debugger in the kit settings for this kit.") + .arg(m_runParameters.inferior.executable)); + return; + } + Utils::globalMacroExpander()->registerFileVariables( "DebuggedExecutable", tr("Debugged executable"), [this] { return m_runParameters.inferior.executable; } diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index f0c7642257..9b4f6056f3 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -395,6 +395,8 @@ void LldbEngine::handleResponse(const QString &response) handleOutputNotification(item); else if (name == "pid") notifyInferiorPid(item.toProcessHandle()); + else if (name == "breakpointmodified") + handleInterpreterBreakpointModified(item); } } @@ -607,6 +609,31 @@ void LldbEngine::handleOutputNotification(const GdbMi &output) showMessage(data, ch); } +void LldbEngine::handleInterpreterBreakpointModified(const GdbMi &bpItem) +{ + QTC_ASSERT(bpItem.childCount(), return); + QString id = bpItem.childAt(0).m_data; + + Breakpoint bp = breakHandler()->findBreakpointByResponseId(id); + if (!bp) // FIXME adapt whole bp handling and turn into soft assert + return; + + // this function got triggered by a lldb internal breakpoint event + // avoid asserts regarding unexpected state transitions + switch (bp->state()) { + case BreakpointInsertionRequested: // was a pending bp + bp->gotoState(BreakpointInsertionProceeding, BreakpointInsertionRequested); + break; + case BreakpointInserted: // was an inserted, gets updated now + bp->gotoState(BreakpointUpdateRequested, BreakpointInserted); + notifyBreakpointChangeProceeding(bp); + break; + default: + break; + } + updateBreakpointData(bp, bpItem, false); +} + void LldbEngine::loadSymbols(const QString &moduleName) { Q_UNUSED(moduleName) diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index f06798dd39..6c5b3c2c21 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -120,6 +120,7 @@ private: void handleStateNotification(const GdbMi &item); void handleLocationNotification(const GdbMi &location); void handleOutputNotification(const GdbMi &output); + void handleInterpreterBreakpointModified(const GdbMi &item); void handleResponse(const QString &data); void updateAll() override; diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index 7abdee2c7c..a887dc5371 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -657,7 +657,7 @@ void HelpPluginPrivate::showContextHelp(const HelpItem &contextHelp) .arg(contextHelp.helpIds().join(", ")) .arg(HelpPlugin::tr("No documentation available."))); } - } else if (links.size() == 1) { + } else if (links.size() == 1 && !contextHelp.isFuzzyMatch()) { showHelpUrl(links.front().second, LocalHelpManager::contextHelpOption()); } else { QMap<QString, QUrl> map; diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index efd4c8fb6f..5553e58ecc 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -208,17 +208,6 @@ void Client::openDocument(Core::IDocument *document) connect(textDocument, &QObject::destroyed, this, [this, textDocument]{ m_resetAssistProvider.remove(textDocument); }); - if (BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(textDocument)) { - if (QPointer<TextEditorWidget> widget = editor->editorWidget()) { - connect(widget, &TextEditorWidget::cursorPositionChanged, this, [this, widget](){ - // TODO This would better be a compressing timer - QTimer::singleShot(50, this, [this, widget]() { - if (widget) - cursorPositionChanged(widget); - }); - }); - } - } } m_openedDocument.append(document->filePath()); @@ -344,7 +333,7 @@ void Client::documentContentsChanged(Core::IDocument *document) if (textDocument) { using namespace TextEditor; - if (BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(textDocument)) + for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(textDocument)) if (TextEditorWidget *widget = editor->editorWidget()) widget->setRefactorMarkers(RefactorMarker::filterOutType(widget->refactorMarkers(), id())); requestDocumentSymbols(textDocument); @@ -766,6 +755,11 @@ const DynamicCapabilities &Client::dynamicCapabilities() const return m_dynamicCapabilities; } +const BaseClientInterface *Client::clientInterface() const +{ + return m_clientInterface.data(); +} + void Client::log(const ShowMessageParams &message, Core::MessageManager::PrintToOutputPaneFlag flag) { diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 2d92424f42..635512fa28 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -147,6 +147,7 @@ public: const LanguageServerProtocol::ServerCapabilities &capabilities() const; const DynamicCapabilities &dynamicCapabilities() const; + const BaseClientInterface *clientInterface() const; signals: void initialized(LanguageServerProtocol::ServerCapabilities capabilities); diff --git a/src/plugins/languageclient/languageclientinterface.cpp b/src/plugins/languageclient/languageclientinterface.cpp index b67db95dde..0598061720 100644 --- a/src/plugins/languageclient/languageclientinterface.cpp +++ b/src/plugins/languageclient/languageclientinterface.cpp @@ -110,7 +110,7 @@ StdIOClientInterface::~StdIOClientInterface() Utils::SynchronousProcess::stopProcess(m_process); } -bool StdIOClientInterface::needsRestart(const StdIOSettings *settings) +bool StdIOClientInterface::needsRestart(const StdIOSettings *settings) const { return m_executable != settings->m_executable || m_arguments != settings->m_arguments; } diff --git a/src/plugins/languageclient/languageclientinterface.h b/src/plugins/languageclient/languageclientinterface.h index 3dc2602d52..182965ab88 100644 --- a/src/plugins/languageclient/languageclientinterface.h +++ b/src/plugins/languageclient/languageclientinterface.h @@ -74,7 +74,7 @@ public: StdIOClientInterface &operator=(const StdIOClientInterface &) = delete; StdIOClientInterface &operator=(StdIOClientInterface &&) = delete; - bool needsRestart(const StdIOSettings *settings); + bool needsRestart(const StdIOSettings *settings) const; bool start() override; diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index b097f25a37..1cd162dc51 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -125,7 +125,10 @@ void LanguageClientManager::deleteClient(Client *client) QTC_ASSERT(client, return); client->disconnect(); managerInstance->m_clients.removeAll(client); - client->deleteLater(); + if (managerInstance->m_shuttingDown) + delete client; + else + client->deleteLater(); } void LanguageClientManager::shutdown() @@ -210,6 +213,18 @@ void LanguageClientManager::editorOpened(Core::IEditor *editor) (const QTextCursor &cursor){ findUsages(filePath, cursor); }); + connect(widget, &TextEditorWidget::cursorPositionChanged, this, [this, widget](){ + // TODO This would better be a compressing timer + QTimer::singleShot(50, this, + [this, widget = QPointer<TextEditorWidget>(widget)]() { + if (widget) { + for (Client *client : this->reachableClients()) { + if (client->isSupportedDocument(widget->textDocument())) + client->cursorPositionChanged(widget); + } + } + }); + }); } } } diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 276fac15fc..a337a72b7b 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -491,7 +491,9 @@ bool StdIOSettings::needsRestart() const { if (BaseSettings::needsRestart()) return true; - if (auto stdIOInterface = qobject_cast<StdIOClientInterface *>(m_client)) + if (m_client.isNull()) + return false; + if (auto stdIOInterface = qobject_cast<const StdIOClientInterface *>(m_client->clientInterface())) return stdIOInterface->needsRestart(this); return false; } diff --git a/src/plugins/languageclient/languageclientutils.cpp b/src/plugins/languageclient/languageclientutils.cpp index f81be2427c..7a28c5e3a9 100644 --- a/src/plugins/languageclient/languageclientutils.cpp +++ b/src/plugins/languageclient/languageclientutils.cpp @@ -133,12 +133,10 @@ void updateCodeActionRefactoringMarker(Client *client, TextDocument* doc = TextDocument::textDocumentForFileName(uri.toFileName()); if (!doc) return; - BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(doc); - if (!editor) + const QVector<BaseTextEditor *> editors = BaseTextEditor::textEditorsForDocument(doc); + if (editors.isEmpty()) return; - TextEditorWidget *editorWidget = editor->editorWidget(); - const QList<Diagnostic> &diagnostics = action.diagnostics().value_or(QList<Diagnostic>()); RefactorMarkers markers; @@ -181,7 +179,10 @@ void updateCodeActionRefactoringMarker(Client *client, marker.cursor = endOfLineCursor(diagnostic.range().start().toTextCursor(doc->document())); markers << marker; } - editorWidget->setRefactorMarkers(markers + editorWidget->refactorMarkers()); + for (BaseTextEditor *editor : editors) { + if (TextEditorWidget *editorWidget = editor->editorWidget()) + editorWidget->setRefactorMarkers(markers + editorWidget->refactorMarkers()); + } } } // namespace LanguageClient diff --git a/src/plugins/nim/settings/nimtoolssettingswidget.ui b/src/plugins/nim/settings/nimtoolssettingswidget.ui index 7322c6a8ec..28c0d1ac31 100644 --- a/src/plugins/nim/settings/nimtoolssettingswidget.ui +++ b/src/plugins/nim/settings/nimtoolssettingswidget.ui @@ -10,9 +10,6 @@ <height>300</height> </rect> </property> - <property name="windowTitle"> - <string>Form</string> - </property> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> <widget class="QGroupBox" name="groupBox"> diff --git a/src/plugins/perfprofiler/perftracepointdialog.cpp b/src/plugins/perfprofiler/perftracepointdialog.cpp index 07a2c90551..5dc638bbbe 100644 --- a/src/plugins/perfprofiler/perftracepointdialog.cpp +++ b/src/plugins/perfprofiler/perftracepointdialog.cpp @@ -96,7 +96,7 @@ PerfTracePointDialog::~PerfTracePointDialog() void PerfTracePointDialog::runScript() { - m_ui->label->setText(tr("Executing script ...")); + m_ui->label->setText(tr("Executing script...")); m_ui->textEdit->setReadOnly(true); m_ui->privilegesChooser->setEnabled(false); m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); diff --git a/src/plugins/perfprofiler/perftracepointdialog.h b/src/plugins/perfprofiler/perftracepointdialog.h index 83e2199dad..ca5d4e2ae5 100644 --- a/src/plugins/perfprofiler/perftracepointdialog.h +++ b/src/plugins/perfprofiler/perftracepointdialog.h @@ -41,6 +41,8 @@ namespace Ui { class PerfTracePointDialog; } class PerfTracePointDialog : public QDialog { + Q_OBJECT + public: PerfTracePointDialog(); ~PerfTracePointDialog(); diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 7b7b88967d..437f9d58ee 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -59,7 +59,6 @@ SUBDIRS = \ languageclient \ cppcheck \ compilationdatabaseprojectmanager \ - perfprofiler \ qmlpreview \ studiowelcome @@ -70,9 +69,9 @@ qtHaveModule(serialport) { } qtHaveModule(quick) { - SUBDIRS += qmlprofiler + SUBDIRS += qmlprofiler perfprofiler } else { - warning("QmlProfiler plugin has been disabled since the Qt Quick module is not available.") + warning("QmlProfiler and PerfProfiler plugins have been disabled since the Qt Quick module is not available.") } qtHaveModule(help) { diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.h b/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.h index 1ef030e67f..e69e284250 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.h +++ b/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.h @@ -32,6 +32,8 @@ namespace Internal { class DesktopDeviceFactory : public IDeviceFactory { + Q_OBJECT + public: DesktopDeviceFactory(); }; diff --git a/src/plugins/projectexplorer/kit.cpp b/src/plugins/projectexplorer/kit.cpp index e92e66c5b2..cc0ca3a39f 100644 --- a/src/plugins/projectexplorer/kit.cpp +++ b/src/plugins/projectexplorer/kit.cpp @@ -275,11 +275,9 @@ void Kit::fix() void Kit::setup() { KitGuard g(this); - // Process the KitAspects in reverse order: They may only be based on other information - // lower in the stack. const QList<KitAspect *> aspects = KitManager::kitAspects(); - for (int i = aspects.count() - 1; i >= 0; --i) - aspects.at(i)->setup(this); + for (KitAspect * const aspect : aspects) + aspect->setup(this); } void Kit::upgrade() diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp index 3d40aef1ef..07aa313fcc 100644 --- a/src/plugins/projectexplorer/kitmanager.cpp +++ b/src/plugins/projectexplorer/kitmanager.cpp @@ -71,10 +71,12 @@ class KitManagerPrivate public: Kit *m_defaultKit = nullptr; bool m_initialized = false; - std::vector<std::unique_ptr<KitAspect>> m_informationList; std::vector<std::unique_ptr<Kit>> m_kitList; std::unique_ptr<PersistentSettingsWriter> m_writer; QSet<Id> m_irrelevantAspects; + + // Sorted by priority, in descending order. + std::vector<std::unique_ptr<KitAspect>> m_informationList; }; } // namespace Internal diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 8b8c571142..9c86a70686 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -1027,6 +1027,8 @@ bool static hasFlagEffectOnMacros(const QString &flag) return false; // Skip include paths if (f.startsWith("w", Qt::CaseInsensitive)) return false; // Skip warning options + if (f.startsWith("Y") || (f.startsWith("F") && f != "F")) + return false; // Skip pch-related flags } return true; } diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index ed7c16bc1f..5d7d296e70 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2045,8 +2045,12 @@ void ProjectExplorerPluginPrivate::updateWelcomePage() void ProjectExplorerPluginPrivate::currentModeChanged(Id mode, Id oldMode) { - if (oldMode == Constants::MODE_SESSION) - ICore::saveSettings(); + if (oldMode == Constants::MODE_SESSION) { + // Saving settings directly in a mode change is not a good idea, since the mode change + // can be part of a bigger change. Save settings after that bigger change had a chance to + // complete. + QTimer::singleShot(0, ICore::instance(), &ICore::saveSettings); + } if (mode == Core::Constants::MODE_WELCOME) updateWelcomePage(); } diff --git a/src/plugins/pythoneditor/pythoneditorplugin.cpp b/src/plugins/pythoneditor/pythoneditorplugin.cpp index 68a0431789..4d71670e7d 100644 --- a/src/plugins/pythoneditor/pythoneditorplugin.cpp +++ b/src/plugins/pythoneditor/pythoneditorplugin.cpp @@ -363,7 +363,7 @@ static QStringList readLinesJson(const Utils::FileName &projectFile, // This assumes te project file is formed with only one field called // 'files' that has a list associated of the files to include in the project. if (content.isEmpty()) { - *errorMessage = PythonProject::tr("Unable read \"%1\": The file is empty.") + *errorMessage = PythonProject::tr("Unable to read \"%1\": The file is empty.") .arg(projectFile.toUserOutput()); return lines; } @@ -372,7 +372,7 @@ static QStringList readLinesJson(const Utils::FileName &projectFile, const QJsonDocument doc = QJsonDocument::fromJson(content, &error); if (doc.isNull()) { const int line = content.left(error.offset).count('\n') + 1; - *errorMessage = PythonProject::tr("Unable parse %1:%2: %3") + *errorMessage = PythonProject::tr("Unable to parse \"%1\":%2: %3") .arg(projectFile.toUserOutput()).arg(line) .arg(error.errorString()); return lines; diff --git a/src/plugins/qmldesigner/designercore/include/qmltimeline.h b/src/plugins/qmldesigner/designercore/include/qmltimeline.h index a92a292119..c04fd454c0 100644 --- a/src/plugins/qmldesigner/designercore/include/qmltimeline.h +++ b/src/plugins/qmldesigner/designercore/include/qmltimeline.h @@ -71,10 +71,10 @@ public: void toogleRecording(bool b) const; void resetGroupRecording() const; + bool hasKeyframeGroup(const ModelNode &node, const PropertyName &propertyName) const; private: void addKeyframeGroupIfNotExists(const ModelNode &node, const PropertyName &propertyName); - bool hasKeyframeGroup(const ModelNode &node, const PropertyName &propertyName) const; QList<QmlTimelineKeyframeGroup> allKeyframeGroups() const; }; diff --git a/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp index 745fdc4d00..65ed482bfb 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp @@ -63,7 +63,7 @@ void QmlObjectNode::setVariantProperty(const PropertyName &name, const QVariant timelineFrames.setValue(value, frame); return; - } else if (modelNode().hasId() && timelineIsActive()) { + } else if (modelNode().hasId() && timelineIsActive() && currentTimeline().hasKeyframeGroup(modelNode(), name)) { QmlTimelineKeyframeGroup timelineFrames(currentTimeline().keyframeGroup(modelNode(), name)); Q_ASSERT(timelineFrames.isValid()); diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h index 9b73dc1faf..bdaa22bb4b 100644 --- a/src/plugins/qmldesigner/designersettings.h +++ b/src/plugins/qmldesigner/designersettings.h @@ -65,7 +65,6 @@ const char REFORMAT_UI_QML_FILES[] = "ReformatUiQmlFiles"; /* These setti const char IGNORE_DEVICE_PIXEL_RATIO[] = "IgnoreDevicePixelRaio"; /* The settings can be used to turn off the feature, if there are serious issues */ const char STANDALONE_MODE[] = "StandAloneMode"; const char ENABLE_TIMELINEVIEW[] = "EnableTimelineView"; -const char ENABLE_TIMELINEVIEW_ENVVAR[] = "QTC_ENABLE_QTQUICKTIMELINE_EDITOR"; } class DesignerSettings : public QHash<QByteArray, QVariant> diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui index 8bc3e6c973..5d13cfa726 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui @@ -10,14 +10,11 @@ <height>176</height> </rect> </property> - <property name="windowTitle"> - <string>Form</string> - </property> <layout class="QGridLayout" name="gridLayout"> <item row="4" column="3"> <widget class="QLabel" name="label_16"> <property name="text"> - <string>Loops</string> + <string>Loops:</string> </property> </widget> </item> @@ -117,7 +114,7 @@ </size> </property> <property name="text"> - <string>Animation ID</string> + <string>Animation ID:</string> </property> </widget> </item> @@ -162,14 +159,14 @@ <item row="5" column="1"> <widget class="QLabel" name="label_23"> <property name="text"> - <string>Finished</string> + <string>Finished:</string> </property> </widget> </item> <item row="4" column="7"> <widget class="QLabel" name="label_17"> <property name="text"> - <string>Ping Pong</string> + <string>Ping pong</string> </property> </widget> </item> @@ -205,7 +202,7 @@ </size> </property> <property name="text"> - <string>Transition to state</string> + <string>Transition to state:</string> </property> </widget> </item> @@ -222,7 +219,7 @@ <bool>true</bool> </property> <property name="text"> - <string>Running in Base State</string> + <string>Running in base state</string> </property> </widget> </item> @@ -257,7 +254,7 @@ <item row="3" column="1"> <widget class="QLabel" name="label_12"> <property name="text"> - <string>Start Frame</string> + <string>Start frame:</string> </property> </widget> </item> @@ -290,14 +287,14 @@ <item row="3" column="7"> <widget class="QLabel" name="label_14"> <property name="text"> - <string>Duration</string> + <string>Duration:</string> </property> </widget> </item> <item row="3" column="3"> <widget class="QLabel" name="label_13"> <property name="text"> - <string>End Frame</string> + <string>End frame:</string> </property> </widget> </item> diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h index 40e4900442..6c012beec1 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -46,13 +46,13 @@ const int priorityTimelineCategory = 110; const char timelineCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Timeline"); const char timelineCopyKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Copy All Keyframes from item"); + "Copy All Keyframes"); const char timelinePasteKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Paste Keyframes to item"); + "Paste Keyframes"); const char timelineInsertKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Insert Keyframes for item"); + "Add Keyframes at Current Frame"); const char timelineDeleteKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Delete All Keyframes for item"); + "Delete All Keyframes"); const char timelineStatusBarFrameNumber[] = QT_TRANSLATE_NOOP("QmlDesignerTimeline", "Frame %1"); diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui index 5eea257be1..b8b47e4c70 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui @@ -10,9 +10,6 @@ <height>170</height> </rect> </property> - <property name="windowTitle"> - <string>Form</string> - </property> <layout class="QGridLayout" name="gridLayout"> <item row="1" column="8" colspan="2"> <spacer name="horizontalSpacer_11"> @@ -84,7 +81,7 @@ <item row="4" column="0"> <widget class="QLabel" name="label_8"> <property name="text"> - <string>Expression Binding</string> + <string>Expression binding:</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> @@ -107,7 +104,7 @@ <item row="2" column="4"> <widget class="QLabel" name="label_7"> <property name="text"> - <string>End Frame</string> + <string>End frame:</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> @@ -200,7 +197,7 @@ <bool>false</bool> </property> <property name="text"> - <string>Expression Binding</string> + <string>Expression binding</string> </property> </widget> </item> @@ -214,7 +211,7 @@ <item row="1" column="0"> <widget class="QLabel" name="label_5"> <property name="text"> - <string>Timeline ID</string> + <string>Timeline ID:</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> @@ -243,7 +240,7 @@ <item row="2" column="1"> <widget class="QLabel" name="label_6"> <property name="text"> - <string>Start Frame</string> + <string>Start frame:</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinepropertyitem.h b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinepropertyitem.h index 5cd241b7a3..2b8c00c59b 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinepropertyitem.h +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinepropertyitem.h @@ -44,6 +44,8 @@ class TimelineToolButton; class TimelineKeyframeItem : public TimelineMovableAbstractItem { + Q_DECLARE_TR_FUNCTIONS(TimelineKeyframeItem) + public: explicit TimelineKeyframeItem(TimelinePropertyItem *parent, const ModelNode &frame); ~TimelineKeyframeItem() override; @@ -84,6 +86,8 @@ private: class TimelinePropertyItem : public TimelineItem { + Q_OBJECT + public: enum { Type = TimelineConstants::timelinePropertyItemUserType }; diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesectionitem.h b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesectionitem.h index 3c34ba3929..26db04f757 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesectionitem.h +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesectionitem.h @@ -40,6 +40,8 @@ class TimelineSectionItem; class TimelineBarItem : public TimelineMovableAbstractItem { + Q_DECLARE_TR_FUNCTIONS(TimelineBarItem) + enum class Location { Undefined, Center, Left, Right }; public: diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsmodel.cpp b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsmodel.cpp index 6ce3731222..47426d9755 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsmodel.cpp +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsmodel.cpp @@ -103,7 +103,7 @@ QWidget *TimelineEditorDelegate::createEditor(QWidget *parent, switch (index.column()) { case TimelineSettingsModel::TimelineRow: { QTC_ASSERT(comboBox, return widget); - comboBox->addItem(tr("None")); + comboBox->addItem(TimelineSettingsModel::tr("None")); for (const auto &timeline : timelineSettingsModel->timelineView()->getTimelines()) { if (!timeline.modelNode().id().isEmpty()) comboBox->addItem(timeline.modelNode().id()); @@ -111,7 +111,7 @@ QWidget *TimelineEditorDelegate::createEditor(QWidget *parent, } break; case TimelineSettingsModel::AnimationRow: { QTC_ASSERT(comboBox, return widget); - comboBox->addItem(tr("None")); + comboBox->addItem(TimelineSettingsModel::tr("None")); for (const auto &animation : timelineSettingsModel->timelineView()->getAnimations(qmlTimeline)) { if (!animation.id().isEmpty()) diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 09e10c3b0c..84b95cccc3 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -194,8 +194,7 @@ bool QmlDesignerPlugin::delayedInitialize() d->settings.fromSettings(Core::ICore::settings()); d->viewManager.registerViewTakingOwnership(new QmlDesigner::Internal::ConnectionView); - if (DesignerSettings::getValue(DesignerSettingsKey::ENABLE_TIMELINEVIEW).toBool() - || qEnvironmentVariableIsSet(DesignerSettingsKey::ENABLE_TIMELINEVIEW_ENVVAR)) + if (DesignerSettings::getValue(DesignerSettingsKey::ENABLE_TIMELINEVIEW).toBool()) d->viewManager.registerViewTakingOwnership(new QmlDesigner::TimelineView); d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::SourceTool); d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::ColorTool); diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp index e9bd2d1cb4..a7d6bc2bb0 100644 --- a/src/plugins/qmldesigner/settingspage.cpp +++ b/src/plugins/qmldesigner/settingspage.cpp @@ -159,6 +159,8 @@ DesignerSettings SettingsPageWidget::settings() const m_ui.showPropertyEditorWarningsCheckBox->isChecked()); settings.insert(DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT, m_ui.showWarnExceptionsCheckBox->isChecked()); + settings.insert(DesignerSettingsKey::ENABLE_TIMELINEVIEW, + m_ui.featureTimelineEditorCheckBox->isChecked()); return settings; } @@ -224,9 +226,13 @@ void SettingsPageWidget::setSettings(const DesignerSettings &settings) m_ui.controls2StyleComboBox->setCurrentText(m_ui.styleLineEdit->text()); + m_ui.featureTimelineEditorCheckBox->setChecked(settings.value( + DesignerSettingsKey::ENABLE_TIMELINEVIEW).toBool()); + if (settings.value(DesignerSettingsKey::STANDALONE_MODE).toBool()) { m_ui.emulationGroupBox->hide(); m_ui.debugGroupBox->hide(); + m_ui.featuresGroupBox->hide(); } } @@ -262,7 +268,8 @@ void SettingsPage::apply() << DesignerSettingsKey::PUPPET_KILL_TIMEOUT << DesignerSettingsKey::FORWARD_PUPPET_OUTPUT << DesignerSettingsKey::DEBUG_PUPPET - << DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT; + << DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT + << DesignerSettingsKey::ENABLE_TIMELINEVIEW; foreach (const QByteArray &key, restartNecessaryKeys) { if (currentSettings.value(key) != newSettings.value(key)) { diff --git a/src/plugins/qmldesigner/settingspage.ui b/src/plugins/qmldesigner/settingspage.ui index 567f0f7d80..7da62b300a 100644 --- a/src/plugins/qmldesigner/settingspage.ui +++ b/src/plugins/qmldesigner/settingspage.ui @@ -411,6 +411,22 @@ </layout> </item> <item> + <widget class="QGroupBox" name="featuresGroupBox"> + <property name="title"> + <string>Features</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QCheckBox" name="featureTimelineEditorCheckBox"> + <property name="text"> + <string>Enable Timeline editor</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> <widget class="QGroupBox" name="debugGroupBox"> <property name="title"> <string>Debugging</string> diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index 1df46d885b..a6e5850076 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -287,10 +287,10 @@ void QmlProfilerTool::updateRunActions() d->m_startAction->setToolTip(tr("A QML Profiler analysis is still in progress.")); d->m_stopAction->setEnabled(true); } else { - QString whyNot = tr("Start QML Profiler analysis."); + QString tooltip = tr("Start QML Profiler analysis."); bool canRun = ProjectExplorerPlugin::canRunStartupProject - (ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, &whyNot); - d->m_startAction->setToolTip(whyNot); + (ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, &tooltip); + d->m_startAction->setToolTip(tooltip); d->m_startAction->setEnabled(canRun); d->m_stopAction->setEnabled(false); } diff --git a/src/plugins/qtsupport/qtoutputformatter.cpp b/src/plugins/qtsupport/qtoutputformatter.cpp index 778d309600..2b7933ea8a 100644 --- a/src/plugins/qtsupport/qtoutputformatter.cpp +++ b/src/plugins/qtsupport/qtoutputformatter.cpp @@ -31,6 +31,7 @@ #include <utils/algorithm.h> #include <utils/ansiescapecodehandler.h> #include <utils/fileinprojectfinder.h> +#include <utils/hostosinfo.h> #include <utils/theme/theme.h> #include <QPlainTextEdit> @@ -412,16 +413,16 @@ void QtSupportPlugin::testQtOutputFormatter_data() << " Loc: [../TestProject/test.cpp(123)]" << 9 << 37 << "../TestProject/test.cpp(123)" << "../TestProject/test.cpp" << 123 << -1; - - QTest::newRow("Windows failed QTest link") - << "..\\TestProject\\test.cpp(123) : failure location" - << 0 << 28 << "..\\TestProject\\test.cpp(123)" - << "..\\TestProject\\test.cpp" << 123 << -1; - - QTest::newRow("Windows failed QTest link with carriage return") - << "..\\TestProject\\test.cpp(123) : failure location\r" - << 0 << 28 << "..\\TestProject\\test.cpp(123)" - << "..\\TestProject\\test.cpp" << 123 << -1; + if (HostOsInfo::isWindowsHost()) { + QTest::newRow("Windows failed QTest link") + << "..\\TestProject\\test.cpp(123) : failure location" + << 0 << 28 << "..\\TestProject\\test.cpp(123)" + << "../TestProject/test.cpp" << 123 << -1; + QTest::newRow("Windows failed QTest link with carriage return") + << "..\\TestProject\\test.cpp(123) : failure location\r" + << 0 << 28 << "..\\TestProject\\test.cpp(123)" + << "../TestProject/test.cpp" << 123 << -1; + } } void QtSupportPlugin::testQtOutputFormatter() diff --git a/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp b/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp index 728aea666d..f525f777d0 100644 --- a/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp +++ b/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp @@ -203,7 +203,7 @@ void AbstractRemoteLinuxDeployService::handleDeviceSetupDone(bool success) } else { connect(d->connection, &SshConnection::connected, this, &AbstractRemoteLinuxDeployService::handleConnected); - emit progressMessage(tr("Connecting to device '%1' (%2)") + emit progressMessage(tr("Connecting to device \"%1\" (%2).") .arg(deviceConfiguration()->displayName()) .arg(deviceConfiguration()->sshParameters().host())); if (d->connection->state() == SshConnection::Unconnected) diff --git a/src/plugins/texteditor/basehoverhandler.cpp b/src/plugins/texteditor/basehoverhandler.cpp index 72e35ba5bb..92dae73d59 100644 --- a/src/plugins/texteditor/basehoverhandler.cpp +++ b/src/plugins/texteditor/basehoverhandler.cpp @@ -145,7 +145,7 @@ void BaseHoverHandler::decorateToolTip() if (Qt::mightBeRichText(toolTip())) setToolTip(toolTip().toHtmlEscaped()); - if (lastHelpItemIdentified().isValid()) { + if (lastHelpItemIdentified().isValid() && !lastHelpItemIdentified().isFuzzyMatch()) { const QString &helpContents = lastHelpItemIdentified().extractContent(false); if (!helpContents.isEmpty()) { m_toolTip = toolTip().toHtmlEscaped(); diff --git a/src/plugins/texteditor/highlighter.cpp b/src/plugins/texteditor/highlighter.cpp index 4178dc7195..5b60b885ab 100644 --- a/src/plugins/texteditor/highlighter.cpp +++ b/src/plugins/texteditor/highlighter.cpp @@ -258,6 +258,16 @@ void Highlighter::handleShutdown() delete highlightRepository(); } +static bool isOpeningParenthesis(QChar c) +{ + return c == QLatin1Char('{') || c == QLatin1Char('[') || c == QLatin1Char('('); +} + +static bool isClosingParenthesis(QChar c) +{ + return c == QLatin1Char('}') || c == QLatin1Char(']') || c == QLatin1Char(')'); +} + void Highlighter::highlightBlock(const QString &text) { if (!definition().isValid()) @@ -266,8 +276,21 @@ void Highlighter::highlightBlock(const QString &text) KSyntaxHighlighting::State state = TextDocumentLayout::userData(block)->syntaxState(); state = highlightLine(text, state); block = block.next(); + + Parentheses parentheses; + int pos = 0; + for (const QChar &c : text) { + if (isOpeningParenthesis(c)) + parentheses.push_back(Parenthesis(Parenthesis::Opened, c, pos)); + else if (isClosingParenthesis(c)) + parentheses.push_back(Parenthesis(Parenthesis::Closed, c, pos)); + pos++; + } + TextDocumentLayout::setParentheses(currentBlock(), parentheses); + if (block.isValid()) TextDocumentLayout::userData(block)->setSyntaxState(state); + formatSpaces(text); } void Highlighter::applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format) diff --git a/src/plugins/texteditor/highlightersettingspage.ui b/src/plugins/texteditor/highlightersettingspage.ui index fcd4919b12..7b1e6c9e0d 100644 --- a/src/plugins/texteditor/highlightersettingspage.ui +++ b/src/plugins/texteditor/highlightersettingspage.ui @@ -127,6 +127,9 @@ </item> <item> <widget class="QPushButton" name="resetCache"> + <property name="toolTip"> + <string>Reset definitions remembered for files that can be associated with more than one highlighter definition.</string> + </property> <property name="text"> <string>Reset Remembered Definitions</string> </property> diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 36abfc01e2..3c4c8cd516 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -8508,13 +8508,14 @@ BaseTextEditor *BaseTextEditor::currentTextEditor() return qobject_cast<BaseTextEditor *>(EditorManager::currentEditor()); } -BaseTextEditor *BaseTextEditor::textEditorForDocument(TextDocument *textDocument) +QVector<BaseTextEditor *> BaseTextEditor::textEditorsForDocument(TextDocument *textDocument) { + QVector<BaseTextEditor *> ret; for (IEditor *editor : Core::DocumentModel::editorsForDocument(textDocument)) { if (auto textEditor = qobject_cast<BaseTextEditor *>(editor)) - return textEditor; + ret << textEditor; } - return nullptr; + return ret; } TextEditorWidget *BaseTextEditor::editorWidget() const diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index d792a1b12c..3d079bf77f 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -111,7 +111,7 @@ public: virtual void finalizeInitialization() {} static BaseTextEditor *currentTextEditor(); - static BaseTextEditor *textEditorForDocument(TextDocument *textDocument); + static QVector<BaseTextEditor *> textEditorsForDocument(TextDocument *textDocument); TextEditorWidget *editorWidget() const; TextDocument *textDocument() const; diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro index d5bf895ee4..29231afb82 100644 --- a/src/plugins/texteditor/texteditor.pro +++ b/src/plugins/texteditor/texteditor.pro @@ -2,7 +2,19 @@ DEFINES += TEXTEDITOR_LIBRARY QT += gui-private network printsupport xml CONFIG += exceptions CONFIG += include_source_dir # For the highlighter autotest. + +include(../../shared/syntax/syntax_shared.pri) +isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) | isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { + QTC_LIB_DEPENDS += syntax-highlighting +} else { + unix:!disable_external_rpath { + !macos: QMAKE_LFLAGS += -Wl,-z,origin + QMAKE_LFLAGS += -Wl,-rpath,$$shell_quote($${KSYNTAXHIGHLIGHTING_LIB_DIR}) + } +} + include(../../qtcreatorplugin.pri) + SOURCES += texteditorplugin.cpp \ plaintexteditorfactory.cpp \ textdocument.cpp \ diff --git a/src/plugins/texteditor/texteditor_dependencies.pri b/src/plugins/texteditor/texteditor_dependencies.pri index c624e4cfb2..85ccb3ded7 100644 --- a/src/plugins/texteditor/texteditor_dependencies.pri +++ b/src/plugins/texteditor/texteditor_dependencies.pri @@ -2,7 +2,21 @@ QTC_PLUGIN_NAME = TextEditor QTC_LIB_DEPENDS += \ aggregation \ extensionsystem \ - utils \ - syntax-highlighting + utils + QTC_PLUGIN_DEPENDS += \ coreplugin + +# needed for plugins that depend on TextEditor plugin +include(../../shared/syntax/syntax_shared.pri) +!isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR):!isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { + INCLUDEPATH *= $${KSYNTAXHIGHLIGHTING_INCLUDE_DIR} + LIBS *= -L$$KSYNTAXHIGHLIGHTING_LIB_DIR -lKF5SyntaxHighlighting + + linux { + QMAKE_LFLAGS += -Wl,-z,origin + QMAKE_LFLAGS += -Wl,-rpath,$$shell_quote($${KSYNTAXHIGHLIGHTING_LIB_DIR}) + } +} else { + QTC_LIB_DEPENDS += syntax-highlighting +} diff --git a/src/shared/clang/clang_installation.pri b/src/shared/clang/clang_installation.pri index 6c820dc36d..8c75b6cc82 100644 --- a/src/shared/clang/clang_installation.pri +++ b/src/shared/clang/clang_installation.pri @@ -96,7 +96,16 @@ defineReplace(splitFlags) { flag ~= s,-I\S*,, flag ~= s,/D\S*,, flag ~= s,/Z\S*,, - result += $$split(flag, " ") + separate_flags = $$split(flag, " ") + for (separate_flag, separate_flags) { + starting_substr = $$str_member($$separate_flag, 0, 0) + win32:equals(starting_substr, "/") { + result += $$separate_flag + } + equals(starting_substr, "-") { + result += $$separate_flag + } + } } else { inside_quotes = 0 starting_substr = $$str_member($$flag, 0, 0) diff --git a/src/shared/syntax/syntax_shared.pri b/src/shared/syntax/syntax_shared.pri new file mode 100644 index 0000000000..a10ae45b5c --- /dev/null +++ b/src/shared/syntax/syntax_shared.pri @@ -0,0 +1,21 @@ +# KSyntaxHighlighting uses a special folder structure (may contain target arch triple for the lib), +# so expect lib folder to be specified by the user - generate include path based on this +isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR): KSYNTAXHIGHLIGHTING_LIB_DIR=$$(KSYNTAXHIGHLIGHTING_LIB_DIR) +isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR): KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) + +!isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) { + !exists($$KSYNTAXHIGHLIGHTING_LIB_DIR) { + unset(KSYNTAXHIGHLIGHTING_LIB_DIR) + unset(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) + } else { + isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { + !linux: KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$absolute_path('../include/KF5/KSyntaxHighlighting/', $$KSYNTAXHIGHLIGHTING_LIB_DIR) + else: KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$absolute_path('../../include/KF5/KSyntaxHighlighting/', $$KSYNTAXHIGHLIGHTING_LIB_DIR) + } + + !exists($$KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { + unset(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) + unset(KSYNTAXHIGHLIGHTING_LIB_DIR) + } + } +} diff --git a/src/tools/clangbackend/source/fulltokeninfo.cpp b/src/tools/clangbackend/source/fulltokeninfo.cpp index eb57abbbe6..fd59d25766 100644 --- a/src/tools/clangbackend/source/fulltokeninfo.cpp +++ b/src/tools/clangbackend/source/fulltokeninfo.cpp @@ -181,6 +181,7 @@ void FullTokenInfo::variableKind(const Cursor &cursor) { TokenInfo::variableKind(cursor); + m_extraInfo.accessSpecifier = cursor.accessSpecifier(); m_extraInfo.storageClass = cursor.storageClass(); } diff --git a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp index 89567b8d38..3237aab2fb 100644 --- a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp +++ b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp @@ -41,7 +41,7 @@ #include <precompiledheaderstorage.h> #include <processormanager.h> #include <progresscounter.h> -#include <projectparts.h> +#include <projectpartsmanager.h> #include <filepathcaching.h> #include <refactoringdatabaseinitializer.h> #include <sqlitedatabase.h> @@ -68,7 +68,7 @@ using ClangBackEnd::PchCreator; using ClangBackEnd::PchManagerClientProxy; using ClangBackEnd::PchManagerServer; using ClangBackEnd::PrecompiledHeaderStorage; -using ClangBackEnd::ProjectParts; +using ClangBackEnd::ProjectPartsManager; using ClangBackEnd::FilePathCache; using ClangBackEnd::FilePathView; using ClangBackEnd::TimeStamp; @@ -138,12 +138,14 @@ public: ClangBackEnd::Environment &environment, Sqlite::Database &database, PchManagerServer &pchManagerServer, - ClangBackEnd::ClangPathWatcherInterface &pathWatcher) - : ProcessorManager(generatedFiles), - m_environment(environment), - m_database(database), - m_pchManagerServer(pchManagerServer), - m_pathWatcher(pathWatcher) + ClangBackEnd::ClangPathWatcherInterface &pathWatcher, + ClangBackEnd::BuildDependenciesStorageInterface &buildDependenciesStorage) + : ProcessorManager(generatedFiles) + , m_environment(environment) + , m_database(database) + , m_pchManagerServer(pchManagerServer) + , m_pathWatcher(pathWatcher) + , m_buildDependenciesStorage(buildDependenciesStorage) {} protected: @@ -152,7 +154,8 @@ protected: return std::make_unique<PchCreator>(m_environment, m_database, *m_pchManagerServer.client(), - m_pathWatcher); + m_pathWatcher, + m_buildDependenciesStorage); } private: @@ -160,6 +163,7 @@ private: Sqlite::Database &m_database; ClangBackEnd::PchManagerServer &m_pchManagerServer; ClangBackEnd::ClangPathWatcherInterface &m_pathWatcher; + ClangBackEnd::BuildDependenciesStorageInterface &m_buildDependenciesStorage; }; struct Data // because we have a cycle dependency @@ -175,13 +179,14 @@ struct Data // because we have a cycle dependency ClangBackEnd::FilePathCaching filePathCache{database}; ClangPathWatcher<QFileSystemWatcher, QTimer> includeWatcher{filePathCache}; ApplicationEnvironment environment; - ProjectParts projectParts; + ProjectPartsManager projectParts; GeneratedFiles generatedFiles; PchCreatorManager pchCreatorManager{generatedFiles, environment, database, clangPchManagerServer, - includeWatcher}; + includeWatcher, + buildDependencyStorage}; PrecompiledHeaderStorage<> preCompiledHeaderStorage{database}; ClangBackEnd::ProgressCounter pchCreationProgressCounter{[&](int progress, int total) { executeInLoop([&] { diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp index d58da0f27c..a2a7a813ac 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp @@ -55,19 +55,19 @@ OutputContainer setUnion(InputContainer1 &&input1, BuildDependency BuildDependenciesProvider::create(const ProjectPartContainer &projectPart) { - SourceEntries includes = createSourceEntriesFromStorage(projectPart.sourcePathIds, - projectPart.projectPartId); + auto sourcesAndProjectPart = createSourceEntriesFromStorage( + projectPart.sourcePathIds, projectPart.projectPartId); - if (!m_modifiedTimeChecker.isUpToDate(includes)) { + if (!m_modifiedTimeChecker.isUpToDate(sourcesAndProjectPart.first)) { BuildDependency buildDependency = m_generator.create(projectPart); - storeBuildDependency(buildDependency); + storeBuildDependency(buildDependency, sourcesAndProjectPart.second); return buildDependency; } - return createBuildDependencyFromStorage(std::move(includes)); - + return createBuildDependencyFromStorage( + std::move(sourcesAndProjectPart.first)); } BuildDependency BuildDependenciesProvider::createBuildDependencyFromStorage( @@ -76,7 +76,7 @@ BuildDependency BuildDependenciesProvider::createBuildDependencyFromStorage( BuildDependency buildDependency; buildDependency.usedMacros = createUsedMacrosFromStorage(includes); - buildDependency.includes = std::move(includes); + buildDependency.sources = std::move(includes); return buildDependency; } @@ -101,16 +101,19 @@ UsedMacros BuildDependenciesProvider::createUsedMacrosFromStorage(const SourceEn return usedMacros; } -SourceEntries BuildDependenciesProvider::createSourceEntriesFromStorage( - const FilePathIds &sourcePathIds, Utils::SmallStringView projectPartId) const -{ +std::pair<SourceEntries, int> +BuildDependenciesProvider::createSourceEntriesFromStorage( + const FilePathIds &sourcePathIds, + Utils::SmallStringView projectPartName) const { SourceEntries includes; Sqlite::DeferredTransaction transaction(m_transactionBackend); + int projectPartId = m_storage.fetchProjectPartId(projectPartName); + for (FilePathId sourcePathId : sourcePathIds) { - SourceEntries entries = m_storage.fetchDependSources(sourcePathId, - projectPartId); + SourceEntries entries = + m_storage.fetchDependSources(sourcePathId, projectPartId); SourceEntries mergedEntries = setUnion<SourceEntries>(includes, entries); includes = std::move(mergedEntries); @@ -118,15 +121,14 @@ SourceEntries BuildDependenciesProvider::createSourceEntriesFromStorage( transaction.commit(); - return includes; + return {includes, projectPartId}; } -void BuildDependenciesProvider::storeBuildDependency(const BuildDependency &buildDependency) -{ +void BuildDependenciesProvider::storeBuildDependency( + const BuildDependency &buildDependency, int projectPartId) { Sqlite::ImmediateTransaction transaction(m_transactionBackend); - - m_storage.updateSources(buildDependency.includes); - m_storage.insertFileStatuses(buildDependency.fileStatuses); + m_storage.insertOrUpdateSources(buildDependency.sources, projectPartId); + m_storage.insertOrUpdateFileStatuses(buildDependency.fileStatuses); m_storage.insertOrUpdateSourceDependencies(buildDependency.sourceDependencies); m_storage.insertOrUpdateUsedMacros(buildDependency.usedMacros); diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h index 4a89ace732..2eb5210518 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h @@ -55,9 +55,9 @@ public: private: BuildDependency createBuildDependencyFromStorage(SourceEntries &&includes) const; UsedMacros createUsedMacrosFromStorage(const SourceEntries &includes) const; - SourceEntries createSourceEntriesFromStorage(const FilePathIds &sourcePathIds, - Utils::SmallStringView projectPartId) const; - void storeBuildDependency(const BuildDependency &buildDependency); + std::pair<SourceEntries, int> createSourceEntriesFromStorage( + const FilePathIds &sourcePathIds, Utils::SmallStringView projectPartName) const; + void storeBuildDependency(const BuildDependency &buildDependency, int projectPartId); private: BuildDependenciesStorageInterface &m_storage; diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h b/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h index 324552bf99..3e6d00da3f 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h @@ -53,25 +53,28 @@ public: transaction.commit(); } - void updateSources(const SourceEntries &sourceEntries) override + void insertOrUpdateSources(const SourceEntries &sourceEntries, int projectPartId) override { + deleteAllProjectPartsSourcesWithProjectPartNameStatement.write( + projectPartId); + for (const SourceEntry &entry : sourceEntries) { - updateBuildDependencyTimeStampStatement.write(static_cast<long long>(entry.lastModified), - entry.sourceId.filePathId); - updateSourceTypeStatement.write(static_cast<uchar>(entry.sourceType), - entry.sourceId.filePathId); + insertOrUpdateProjectPartsSourcesStatement.write( + entry.sourceId.filePathId, + projectPartId, + static_cast<uchar>(entry.sourceType), + static_cast<uchar>(entry.hasMissingIncludes)); } } - void insertFileStatuses(const FileStatuses &fileStatuses) override + void insertOrUpdateFileStatuses(const FileStatuses &fileStatuses) override { - WriteStatement &statement = insertFileStatusesStatement; + WriteStatement &statement = insertOrUpdateFileStatusesStatement; for (const FileStatus &fileStatus : fileStatuses) statement.write(fileStatus.filePathId.filePathId, fileStatus.size, - fileStatus.lastModified, - fileStatus.isInPrecompiledHeader); + fileStatus.lastModified); } long long fetchLowestLastModifiedTime(FilePathId sourceId) const override @@ -85,7 +88,8 @@ public: { WriteStatement &insertStatement = insertIntoNewUsedMacrosStatement; for (const UsedMacro &usedMacro : usedMacros) - insertStatement.write(usedMacro.filePathId.filePathId, usedMacro.macroName); + insertStatement.write(usedMacro.filePathId.filePathId, + usedMacro.macroName); syncNewUsedMacrosStatement.execute(); deleteOutdatedUsedMacrosStatement.execute(); @@ -104,18 +108,22 @@ public: deleteNewSourceDependenciesStatement.execute(); } - SourceEntries fetchDependSources(FilePathId sourceId, - Utils::SmallStringView projectPartName) const override + int fetchProjectPartId(Utils::SmallStringView projectPartName) override { auto projectPartId = fetchProjectPartIdStatement.template value<int>(projectPartName); - if (projectPartId) { - return fetchSourceDependenciesStatement.template values<SourceEntry, 3>( - 300, - sourceId.filePathId, - projectPartId.value()); - } - return {}; + if (projectPartId) + return projectPartId.value(); + + insertProjectPartNameStatement.write(projectPartName); + + return static_cast<int>(database.lastInsertedRowId()); + } + + SourceEntries fetchDependSources(FilePathId sourceId, int projectPartId) const override + { + return fetchSourceDependenciesStatement.template values<SourceEntry, 4>( + 300, sourceId.filePathId, projectPartId); } UsedMacros fetchUsedMacros(FilePathId sourceId) const override @@ -123,6 +131,17 @@ public: return fetchUsedMacrosStatement.template values<UsedMacro, 2>(128, sourceId.filePathId); } + void updatePchCreationTimeStamp( + long long pchCreationTimeStamp, + Utils::SmallStringView projectPartName) override { + Sqlite::ImmediateTransaction transaction{database}; + + updatePchCreationTimeStampStatement.write(pchCreationTimeStamp, + projectPartName); + + transaction.commit(); + } + static Utils::SmallString toJson(const Utils::SmallStringVector &strings) { QJsonDocument document; @@ -207,10 +226,11 @@ public: "INSERT INTO newSourceDependencies(sourceId, dependencySourceId) VALUES (?,?)", database }; - WriteStatement insertFileStatusesStatement{ - "INSERT OR REPLACE INTO fileStatuses(sourceId, size, lastModified, isInPrecompiledHeader) VALUES (?,?,?,?)", - database - }; + WriteStatement insertOrUpdateFileStatusesStatement{ + "INSERT INTO fileStatuses(sourceId, size, lastModified) VALUES " + "(?001,?002,?003) ON " + "CONFLICT(sourceId) DO UPDATE SET size = ?002, lastModified = ?003", + database}; WriteStatement syncNewSourceDependenciesStatement{ "INSERT INTO sourceDependencies(sourceId, dependencySourceId) SELECT sourceId, dependencySourceId FROM newSourceDependencies WHERE NOT EXISTS (SELECT sourceId FROM sourceDependencies WHERE sourceDependencies.sourceId == newSourceDependencies.sourceId AND sourceDependencies.dependencySourceId == newSourceDependencies.dependencySourceId)", database @@ -223,25 +243,37 @@ public: "DELETE FROM newSourceDependencies", database }; - WriteStatement updateBuildDependencyTimeStampStatement{ - "UPDATE fileStatuses SET buildDependencyTimeStamp = ? WHERE sourceId == ?", - database - }; - WriteStatement updateSourceTypeStatement{ - "UPDATE projectPartsSources SET sourceType = ? WHERE sourceId == ?", - database - }; + WriteStatement insertOrUpdateProjectPartsSourcesStatement{ + "INSERT INTO projectPartsSources(sourceId, projectPartId, " + "sourceType, hasMissingIncludes) VALUES (?001, ?002, ?003, ?004) ON " + "CONFLICT(sourceId, projectPartId) DO UPDATE SET sourceType = ?003, " + "hasMissingIncludes = ?004", + database}; mutable ReadStatement fetchSourceDependenciesStatement{ - "WITH RECURSIVE collectedDependencies(sourceId) AS (VALUES(?) UNION SELECT dependencySourceId FROM sourceDependencies, collectedDependencies WHERE sourceDependencies.sourceId == collectedDependencies.sourceId) SELECT sourceId, buildDependencyTimeStamp, sourceType FROM collectedDependencies NATURAL JOIN projectPartsSources NATURAL JOIN fileStatuses WHERE projectPartId = ? ORDER BY sourceId", - database - }; + "WITH RECURSIVE collectedDependencies(sourceId) AS (VALUES(?) UNION " + "SELECT dependencySourceId FROM sourceDependencies, " + "collectedDependencies WHERE sourceDependencies.sourceId == " + "collectedDependencies.sourceId) SELECT sourceId, " + "pchCreationTimeStamp, sourceType, hasMissingIncludes FROM " + "collectedDependencies NATURAL JOIN projectPartsSources WHERE " + "projectPartId = ? ORDER BY sourceId", + database}; mutable ReadStatement fetchProjectPartIdStatement{ "SELECT projectPartId FROM projectParts WHERE projectPartName = ?", database }; + WriteStatement insertProjectPartNameStatement{ + "INSERT INTO projectParts(projectPartName) VALUES (?)", database}; mutable ReadStatement fetchUsedMacrosStatement{ "SELECT macroName, sourceId FROM usedMacros WHERE sourceId = ? ORDER BY sourceId, macroName", database }; + WriteStatement updatePchCreationTimeStampStatement{ + "UPDATE projectPartsSources SET pchCreationTimeStamp = ?001 WHERE " + "projectPartId = (SELECT " + "projectPartId FROM projectParts WHERE projectPartName = ?002)", + database}; + WriteStatement deleteAllProjectPartsSourcesWithProjectPartNameStatement{ + "DELETE FROM projectPartsSources WHERE projectPartId = ?", database}; }; } diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h b/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h index 445afa052f..4edc47fce1 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h @@ -33,6 +33,8 @@ #include <sourcedependency.h> #include <usedmacro.h> +#include <utils/optional.h> + namespace ClangBackEnd { class BuildDependenciesStorageInterface @@ -42,13 +44,20 @@ public: BuildDependenciesStorageInterface(const BuildDependenciesStorageInterface &) = delete; BuildDependenciesStorageInterface &operator=(const BuildDependenciesStorageInterface &) = delete; - virtual void updateSources(const SourceEntries &sourceIds) = 0; + virtual void insertOrUpdateSources(const SourceEntries &sourceIds, + int projectPartId) = 0; virtual void insertOrUpdateUsedMacros(const UsedMacros &usedMacros) = 0; - virtual void insertFileStatuses(const FileStatuses &fileStatuses) = 0; + virtual void + insertOrUpdateFileStatuses(const FileStatuses &fileStatuses) = 0; virtual void insertOrUpdateSourceDependencies(const SourceDependencies &sourceDependencies) = 0; virtual long long fetchLowestLastModifiedTime(FilePathId sourceId) const = 0; - virtual SourceEntries fetchDependSources(FilePathId sourceId, Utils::SmallStringView projectPartId) const = 0; + virtual SourceEntries fetchDependSources(FilePathId sourceId, + int projectPartId) const = 0; virtual UsedMacros fetchUsedMacros(FilePathId sourceId) const = 0; + virtual int fetchProjectPartId(Utils::SmallStringView projectPartName) = 0; + virtual void updatePchCreationTimeStamp(long long pchCreationTimeStamp, + Utils::SmallStringView projectPartName) + = 0; protected: ~BuildDependenciesStorageInterface() = default; diff --git a/src/tools/clangpchmanagerbackend/source/builddependency.h b/src/tools/clangpchmanagerbackend/source/builddependency.h index 1b649e3118..6725254e30 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependency.h +++ b/src/tools/clangpchmanagerbackend/source/builddependency.h @@ -37,7 +37,7 @@ class BuildDependency public: void clear() { - includes.clear(); + sources.clear(); usedMacros.clear(); sourceFiles.clear(); fileStatuses.clear(); @@ -46,14 +46,15 @@ public: friend bool operator==(const BuildDependency &first, const BuildDependency &second) { - return first.includes == second.includes && first.usedMacros == second.usedMacros - && first.sourceFiles == second.sourceFiles - && first.sourceDependencies == second.sourceDependencies - && first.fileStatuses == second.fileStatuses; + return first.sources == second.sources && + first.usedMacros == second.usedMacros && + first.sourceFiles == second.sourceFiles && + first.sourceDependencies == second.sourceDependencies && + first.fileStatuses == second.fileStatuses; } public: - SourceEntries includes; + SourceEntries sources; UsedMacros usedMacros; FilePathIds sourceFiles; SourceDependencies sourceDependencies; diff --git a/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp b/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp index b3ebbc75ad..1d08442c51 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp +++ b/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp @@ -45,8 +45,27 @@ FilePathIds operator+(const FilePathIds &first, const FilePathIds &second) return result; } + +FilePaths operator+(FilePaths &&first, FilePaths &&second) { + FilePaths result = std::move(first); + + std::copy(second.begin(), second.end(), std::back_inserter(result)); + + return result; } +FilePaths generatedFilePaths(const V2::FileContainers &containers) { + FilePaths paths; + paths.reserve(containers.size()); + std::transform(containers.begin(), + containers.end(), + std::back_inserter(paths), + [](const auto &container) { return container.filePath; }); + return paths; +} + +} // namespace + BuildDependency BuildDependencyCollector::create(const ProjectPartContainer &projectPart) { CommandLineBuilder<ProjectPartContainer, Utils::SmallStringVector> @@ -54,8 +73,9 @@ BuildDependency BuildDependencyCollector::create(const ProjectPartContainer &pro addFiles(projectPart.sourcePathIds, std::move(builder.commandLine)); - setExcludedFilePaths( - m_filePathCache.filePaths(projectPart.headerPathIds + projectPart.sourcePathIds)); + setExcludedFilePaths(m_filePathCache.filePaths(projectPart.headerPathIds + + projectPart.sourcePathIds) + + generatedFilePaths(m_generatedFiles.fileContainers())); addUnsavedFiles(m_generatedFiles.fileContainers()); diff --git a/src/tools/clangpchmanagerbackend/source/builddependencycollector.h b/src/tools/clangpchmanagerbackend/source/builddependencycollector.h index c5e41e9190..f8aaa8f07c 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependencycollector.h +++ b/src/tools/clangpchmanagerbackend/source/builddependencycollector.h @@ -83,11 +83,11 @@ public: return m_buildDependency.sourceDependencies; } - const SourceEntries &includeIds() - { - std::sort(m_buildDependency.includes.begin(), m_buildDependency.includes.end()); + const SourceEntries &sourceEntries() { + std::sort(m_buildDependency.sources.begin(), + m_buildDependency.sources.end()); - return std::move(m_buildDependency.includes); + return std::move(m_buildDependency.sources); } private: diff --git a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri index 94d9540bea..61bcedc262 100644 --- a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri +++ b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri @@ -3,20 +3,19 @@ INCLUDEPATH += $$PWD SOURCES += \ $$PWD/builddependenciesprovider.cpp \ $$PWD/pchmanagerserver.cpp \ - $$PWD/projectparts.cpp \ $$PWD/pchtaskgenerator.cpp \ $$PWD/pchtasksmerger.cpp \ - $$PWD/pchtaskqueue.cpp + $$PWD/pchtaskqueue.cpp \ + $$PWD/projectpartsmanager.cpp HEADERS += \ - $$PWD/pchcreatorincludes.h \ $$PWD/pchmanagerserver.h \ $$PWD/clangpchmanagerbackend_global.h \ $$PWD/pchnotcreatederror.h \ $$PWD/environment.h \ - $$PWD/projectparts.h \ $$PWD/pchcreatorinterface.h \ - $$PWD/projectpartsinterface.h \ + $$PWD/projectpartsmanager.h \ + $$PWD/projectpartsmanagerinterface.h \ $$PWD/queueinterface.h \ $$PWD/processormanagerinterface.h \ $$PWD/processorinterface.h \ diff --git a/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h b/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h index 980d065fdb..f3b365d8d5 100644 --- a/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h +++ b/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h @@ -109,36 +109,46 @@ public: clang::SrcMgr::CharacteristicKind fileType) override { clang::FileID currentFileId = m_sourceManager->getFileID(hashLocation); - if (file && currentFileId != m_mainFileId) { - addSourceDependency(file, hashLocation); - auto fileUID = file->getUID(); - auto sourceFileUID = m_sourceManager - ->getFileEntryForID(m_sourceManager->getFileID(hashLocation)) - ->getUID(); - auto notAlreadyIncluded = isNotAlreadyIncluded(fileUID); - if (notAlreadyIncluded.first) { - m_alreadyIncludedFileUIDs.insert(notAlreadyIncluded.second, fileUID); - FilePath filePath = filePathFromFile(file); - if (!filePath.empty()) { - FilePathId includeId = m_filePathCache.filePathId(filePath); - - time_t lastModified = file->getModificationTime(); - - SourceType sourceType = SourceType::UserInclude; - if (isSystem(fileType)) { - if (isInSystemHeader(hashLocation)) - sourceType = SourceType::SystemInclude; - else - sourceType = SourceType::TopSystemInclude; - } else if (isNotInExcludedIncludeUID(fileUID)) { - if (isInExcludedIncludeUID(sourceFileUID)) - sourceType = SourceType::TopProjectInclude; - else - sourceType = SourceType::ProjectInclude; + if (file) { + if (currentFileId != m_mainFileId) { + addSourceDependency(file, hashLocation); + auto fileUID = file->getUID(); + auto sourceFileUID = + m_sourceManager + ->getFileEntryForID( + m_sourceManager->getFileID(hashLocation)) + ->getUID(); + auto notAlreadyIncluded = isNotAlreadyIncluded(fileUID); + if (notAlreadyIncluded.first) { + m_alreadyIncludedFileUIDs.insert(notAlreadyIncluded.second, + fileUID); + FilePath filePath = filePathFromFile(file); + if (!filePath.empty()) { + FilePathId includeId = + m_filePathCache.filePathId(filePath); + + time_t lastModified = file->getModificationTime(); + + SourceType sourceType = SourceType::UserInclude; + if (isSystem(fileType)) { + if (isInSystemHeader(hashLocation)) + sourceType = SourceType::SystemInclude; + else + sourceType = SourceType::TopSystemInclude; + } else if (isNotInExcludedIncludeUID(fileUID)) { + if (isInExcludedIncludeUID(sourceFileUID)) + sourceType = SourceType::TopProjectInclude; + else + sourceType = SourceType::ProjectInclude; + } + + addSource({includeId, sourceType, lastModified}); } - - addInclude({includeId, sourceType, lastModified}); } + } else { + addSource({m_filePathCache.filePathId(filePathFromFile(file)), + SourceType::Source, + file->getModificationTime()}); } } else { auto sourceFileId = filePathId(hashLocation); @@ -194,10 +204,10 @@ public: void appendContainsMissingIncludes(const FilePathIds &dependentSourceFilesWithMissingIncludes) { - auto split = m_containsMissingIncludes - .insert(m_containsMissingIncludes.end(), - dependentSourceFilesWithMissingIncludes.begin(), - dependentSourceFilesWithMissingIncludes.end()); + auto split = m_containsMissingIncludes.insert( + m_containsMissingIncludes.end(), + dependentSourceFilesWithMissingIncludes.begin(), + dependentSourceFilesWithMissingIncludes.end()); std::inplace_merge(m_containsMissingIncludes.begin(), split, m_containsMissingIncludes.end()); @@ -207,11 +217,13 @@ public: { FilePathIds filteredDependentSourceFilesWithMissingIncludes; filteredDependentSourceFilesWithMissingIncludes.reserve(dependentSourceFilesWithMissingIncludes.size()); - std::set_difference(dependentSourceFilesWithMissingIncludes.begin(), - dependentSourceFilesWithMissingIncludes.end(), - m_containsMissingIncludes.begin(), - m_containsMissingIncludes.end(), - std::back_inserter(filteredDependentSourceFilesWithMissingIncludes)); + std::set_difference( + dependentSourceFilesWithMissingIncludes.begin(), + dependentSourceFilesWithMissingIncludes.end(), + m_containsMissingIncludes.begin(), + m_containsMissingIncludes.end(), + std::back_inserter( + filteredDependentSourceFilesWithMissingIncludes)); dependentSourceFilesWithMissingIncludes = filteredDependentSourceFilesWithMissingIncludes; } @@ -255,8 +267,7 @@ public: sourceDependencies); } - void removeSourceWithMissingIncludesFromIncludes() - { + void removeSourceWithMissingIncludesFromSources() { class Compare { public: @@ -270,17 +281,16 @@ public: } }; - auto &includes = m_buildDependency.includes; - SourceEntries newIncludes; - newIncludes.reserve(includes.size()); - std::set_difference(includes.begin(), - includes.end(), - m_containsMissingIncludes.begin(), - m_containsMissingIncludes.end(), - std::back_inserter(newIncludes), - Compare{}); - - m_buildDependency.includes = newIncludes; + SourceEntryReferences sourcesWithMissingIncludes; + sourcesWithMissingIncludes.reserve(m_containsMissingIncludes.size()); + std::set_intersection(m_buildDependency.sources.begin(), + m_buildDependency.sources.end(), + m_containsMissingIncludes.begin(), + m_containsMissingIncludes.end(), + std::back_inserter(sourcesWithMissingIncludes), + Compare{}); + for (SourceEntryReference entry : sourcesWithMissingIncludes) + entry.get().hasMissingIncludes = HasMissingIncludes::Yes; } SourceDependencies sourceDependenciesSortedByDependendFilePathId() const @@ -296,12 +306,12 @@ public: void filterOutIncludesWithMissingIncludes() { - sortAndMakeUnique(m_containsMissingIncludes);; + sortAndMakeUnique(m_containsMissingIncludes); collectSourceWithMissingIncludes(m_containsMissingIncludes, sourceDependenciesSortedByDependendFilePathId()); - removeSourceWithMissingIncludesFromIncludes(); + removeSourceWithMissingIncludesFromSources(); } void ensureDirectory(const QString &directory, const QString &fileName) @@ -339,16 +349,16 @@ public: return FilePath::fromNativeFilePath(absolutePath(file->getName())); } - void addInclude(SourceEntry sourceEntry) - { - auto &includes = m_buildDependency.includes; - auto found = std::lower_bound(includes.begin(), - includes.end(), - sourceEntry, - [](auto first, auto second) { return first < second; }); - - if (found == includes.end() || *found != sourceEntry) - includes.emplace(found, sourceEntry); + void addSource(SourceEntry sourceEntry) { + auto &sources = m_buildDependency.sources; + auto found = std::lower_bound( + sources.begin(), + sources.end(), + sourceEntry, + [](auto first, auto second) { return first < second; }); + + if (found == sources.end() || *found != sourceEntry) + sources.emplace(found, sourceEntry); } private: diff --git a/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h b/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h index 90108bd76b..b8ea406df0 100644 --- a/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h +++ b/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h @@ -92,8 +92,7 @@ public: m_fileStatuses.emplace(found, id, fileEntry->getSize(), - fileEntry->getModificationTime(), - fileEntry->isInPCH()); + fileEntry->getModificationTime()); } } diff --git a/src/tools/clangpchmanagerbackend/source/modifiedtimechecker.h b/src/tools/clangpchmanagerbackend/source/modifiedtimechecker.h index 88d5f140d5..d641de054c 100644 --- a/src/tools/clangpchmanagerbackend/source/modifiedtimechecker.h +++ b/src/tools/clangpchmanagerbackend/source/modifiedtimechecker.h @@ -75,21 +75,68 @@ public: private: bool compareEntries(const SourceEntries &sourceEntries) const { + class CompareSourceId + { + public: + bool operator()(SourceTimeStamp first, SourceTimeStamp second) { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceEntry first, SourceEntry second) + { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceTimeStamp first, SourceEntry second) + { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceEntry first, SourceTimeStamp second) + { + return first.sourceId < second.sourceId; + } + }; + SourceTimeStamps currentSourceTimeStamp; currentSourceTimeStamp.reserve(sourceEntries.size()); std::set_intersection(m_currentSourceTimeStamps.begin(), m_currentSourceTimeStamps.end(), sourceEntries.begin(), sourceEntries.end(), - std::back_inserter(currentSourceTimeStamp)); - - return std::equal(currentSourceTimeStamp.begin(), - currentSourceTimeStamp.end(), - sourceEntries.begin(), - sourceEntries.end(), - [](SourceTimeStamp first, SourceTimeStamp second) { - return first.lastModified <= second.lastModified; - }); + std::back_inserter(currentSourceTimeStamp), + CompareSourceId{}); + + class CompareTime + { + public: + bool operator()(SourceTimeStamp first, SourceTimeStamp second) + { + return first.lastModified <= second.lastModified; + } + + bool operator()(SourceEntry first, SourceEntry second) + { + return first.pchCreationTimeStamp <= + second.pchCreationTimeStamp; + } + + bool operator()(SourceTimeStamp first, SourceEntry second) + { + return first.lastModified <= second.pchCreationTimeStamp; + } + + bool operator()(SourceEntry first, SourceTimeStamp second) + { + return first.pchCreationTimeStamp <= second.lastModified; + } + }; + + return std::lexicographical_compare(currentSourceTimeStamp.begin(), + currentSourceTimeStamp.end(), + sourceEntries.begin(), + sourceEntries.end(), + CompareTime{}); } void updateCurrentSourceTimeStamps(const SourceEntries &sourceEntries) const @@ -102,8 +149,8 @@ private: } auto split = sourceTimeStamps.insert(sourceTimeStamps.end(), - m_currentSourceTimeStamps.begin(), - m_currentSourceTimeStamps.end()); + m_currentSourceTimeStamps.begin(), + m_currentSourceTimeStamps.end()); std::inplace_merge(sourceTimeStamps.begin(), split, sourceTimeStamps.end()); m_currentSourceTimeStamps = sourceTimeStamps; @@ -111,14 +158,49 @@ private: SourceTimeStamps newSourceTimeStamps(const SourceEntries &sourceEntries) const { - SourceTimeStamps newTimeStamps; - newTimeStamps.reserve(sourceEntries.size() + m_currentSourceTimeStamps.size()); + SourceEntries newSourceEntries; + newSourceEntries.reserve(sourceEntries.size()); + + class CompareSourceId + { + public: + bool operator()(SourceTimeStamp first, SourceTimeStamp second) + { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceEntry first, SourceEntry second) + { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceTimeStamp first, SourceEntry second) + { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceEntry first, SourceTimeStamp second) + { + return first.sourceId < second.sourceId; + } + }; std::set_difference(sourceEntries.begin(), sourceEntries.end(), m_currentSourceTimeStamps.begin(), m_currentSourceTimeStamps.end(), - std::back_inserter(newTimeStamps)); + std::back_inserter(newSourceEntries), + CompareSourceId{}); + + SourceTimeStamps newTimeStamps; + newTimeStamps.reserve(newSourceEntries.size()); + + std::transform(newSourceEntries.begin(), + newSourceEntries.end(), + std::back_inserter(newTimeStamps), + [](SourceEntry entry) { + return SourceTimeStamp{entry.sourceId, {}}; + }); return newTimeStamps; } diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp index b8227ce964..3f858b50ee 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp @@ -31,6 +31,7 @@ #include "generatepchactionfactory.h" #include "pchnotcreatederror.h" +#include <builddependenciesstorageinterface.h> #include <clangpathwatcherinterface.h> #include <filepathcachinginterface.h> #include <generatedfiles.h> @@ -110,7 +111,7 @@ Utils::SmallStringVector PchCreator::generateClangCompilerArguments(const PchTas void PchCreator::generatePch(PchTask &&pchTask) { - long long lastModified = QDateTime::currentSecsSinceEpoch(); + m_projectPartPch.lastModified = QDateTime::currentSecsSinceEpoch(); auto content = generatePchIncludeFileContent(pchTask.includes); auto pchOutputPath = generatePchFilePath(); @@ -123,9 +124,8 @@ void PchCreator::generatePch(PchTask &&pchTask) m_projectPartPch.projectPartId = pchTask.projectPartId(); if (success) { - m_allInclues = pchTask.allIncludes; + m_sources = pchTask.sources; m_projectPartPch.pchPath = std::move(pchOutputPath); - m_projectPartPch.lastModified = lastModified; } } @@ -163,18 +163,21 @@ void PchCreator::clear() { m_clangTool = ClangTool{}; m_projectPartPch = {}; + m_sources.clear(); } void PchCreator::doInMainThreadAfterFinished() { - FilePathIds existingIncludes; - existingIncludes.reserve(m_allInclues.size()); - std::set_difference(m_allInclues.begin(), - m_allInclues.end(), + FilePathIds existingSources; + existingSources.reserve(m_sources.size()); + std::set_difference(m_sources.begin(), + m_sources.end(), m_generatedFilePathIds.begin(), m_generatedFilePathIds.end(), - std::back_inserter(existingIncludes)); - m_clangPathwatcher.updateIdPaths({{m_projectPartPch.projectPartId, existingIncludes}}); + std::back_inserter(existingSources)); + m_buildDependenciesStorage.updatePchCreationTimeStamp(m_projectPartPch.lastModified, + m_projectPartPch.projectPartId); + m_clangPathwatcher.updateIdPaths({{m_projectPartPch.projectPartId, existingSources}}); m_pchManagerClient.precompiledHeadersUpdated(ProjectPartPchs{m_projectPartPch}); } diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.h b/src/tools/clangpchmanagerbackend/source/pchcreator.h index 73f185176d..f1fadcd33a 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.h +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.h @@ -27,7 +27,6 @@ #include "pchcreatorinterface.h" -#include "pchcreatorincludes.h" #include "idpaths.h" #include "sourceentry.h" #include "clangtool.h" @@ -49,6 +48,7 @@ class Environment; class GeneratedFiles; class PchManagerClientInterface; class ClangPathWatcherInterface; +class BuildDependenciesStorageInterface; class PchCreator final : public PchCreatorInterface { @@ -56,12 +56,12 @@ public: PchCreator(Environment &environment, Sqlite::Database &database, PchManagerClientInterface &pchManagerClient, - ClangPathWatcherInterface &clangPathwatcher) - : m_filePathCache(database) - , m_environment(environment) - , m_pchManagerClient(pchManagerClient) - , m_clangPathwatcher(clangPathwatcher) - {} + ClangPathWatcherInterface &clangPathwatcher, + BuildDependenciesStorageInterface &buildDependenciesStorage) + : m_filePathCache(database), m_environment(environment), + m_pchManagerClient(pchManagerClient), + m_clangPathwatcher(clangPathwatcher), + m_buildDependenciesStorage(buildDependenciesStorage) {} void generatePch(PchTask &&pchTask) override; const ProjectPartPch &projectPartPch() override; @@ -85,16 +85,19 @@ public: return m_clangTool; } + const FilePathIds &sources() const { return m_sources; } + private: mutable std::mt19937_64 randomNumberGenator{std::random_device{}()}; ClangTool m_clangTool; ProjectPartPch m_projectPartPch; FilePathCaching m_filePathCache; - FilePathIds m_allInclues; + FilePathIds m_sources; FilePathIds m_generatedFilePathIds; Environment &m_environment; PchManagerClientInterface &m_pchManagerClient; ClangPathWatcherInterface &m_clangPathwatcher; + BuildDependenciesStorageInterface &m_buildDependenciesStorage; bool m_isUsed = false; }; diff --git a/src/tools/clangpchmanagerbackend/source/pchcreatorincludes.h b/src/tools/clangpchmanagerbackend/source/pchcreatorincludes.h deleted file mode 100644 index 6854c59907..0000000000 --- a/src/tools/clangpchmanagerbackend/source/pchcreatorincludes.h +++ /dev/null @@ -1,40 +0,0 @@ -/**************************************************************************** -** -** 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 <filepathid.h> - -namespace ClangBackEnd { - -class PchCreatorIncludes -{ -public: - FilePathIds includeIds; - FilePathIds topIncludeIds; - FilePathIds topSystemIncludeIds; -}; - -} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp index 999da26448..89ad912640 100644 --- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp @@ -42,12 +42,12 @@ namespace ClangBackEnd { PchManagerServer::PchManagerServer(ClangPathWatcherInterface &fileSystemWatcher, PchTaskGeneratorInterface &pchTaskGenerator, - ProjectPartsInterface &projectParts, + ProjectPartsManagerInterface &projectParts, GeneratedFilesInterface &generatedFiles) - : m_fileSystemWatcher(fileSystemWatcher), - m_pchTaskGenerator(pchTaskGenerator), - m_projectParts(projectParts), - m_generatedFiles(generatedFiles) + : m_fileSystemWatcher(fileSystemWatcher) + , m_pchTaskGenerator(pchTaskGenerator) + , m_projectPartsManager(projectParts) + , m_generatedFiles(generatedFiles) { m_fileSystemWatcher.setNotifier(this); } @@ -61,13 +61,13 @@ void PchManagerServer::updateProjectParts(UpdateProjectPartsMessage &&message) { m_toolChainsArgumentsCache.update(message.projectsParts, message.toolChainArguments); - ProjectPartContainers newProjectParts = m_projectParts.update(message.takeProjectsParts()); + ProjectPartContainers newProjectParts = m_projectPartsManager.update(message.takeProjectsParts()); if (m_generatedFiles.isValid()) { m_pchTaskGenerator.addProjectParts(std::move(newProjectParts), std::move(message.toolChainArguments)); } else { - m_projectParts.updateDeferred(newProjectParts); + m_projectPartsManager.updateDeferred(newProjectParts); } } @@ -75,7 +75,7 @@ void PchManagerServer::removeProjectParts(RemoveProjectPartsMessage &&message) { m_fileSystemWatcher.removeIds(message.projectsPartIds); - m_projectParts.remove(message.projectsPartIds); + m_projectPartsManager.remove(message.projectsPartIds); m_pchTaskGenerator.removeProjectParts(message.projectsPartIds); @@ -102,7 +102,7 @@ void PchManagerServer::updateGeneratedFiles(UpdateGeneratedFilesMessage &&messag m_generatedFiles.update(message.takeGeneratedFiles()); if (m_generatedFiles.isValid()) { - ProjectPartContainers deferredProjectParts = m_projectParts.deferredUpdates(); + ProjectPartContainers deferredProjectParts = m_projectPartsManager.deferredUpdates(); ArgumentsEntries entries = m_toolChainsArgumentsCache.arguments( projectPartIds(deferredProjectParts)); @@ -123,8 +123,8 @@ void PchManagerServer::pathsWithIdsChanged(const Utils::SmallStringVector &ids) ArgumentsEntries entries = m_toolChainsArgumentsCache.arguments(ids); for (ArgumentsEntry &entry : entries) { - m_pchTaskGenerator.addProjectParts( - m_projectParts.projects(entry.ids), std::move(entry.arguments)); + m_pchTaskGenerator.addProjectParts(m_projectPartsManager.projects(entry.ids), + std::move(entry.arguments)); } } diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h index bf6b5bd7e7..9cf8aa8321 100644 --- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h +++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h @@ -29,7 +29,7 @@ #include "clangpathwatchernotifier.h" #include "pchcreatorinterface.h" #include "pchmanagerserverinterface.h" -#include "projectpartsinterface.h" +#include "projectpartsmanagerinterface.h" #include "toolchainargumentscache.h" #include <generatedfilesinterface.h> @@ -48,7 +48,7 @@ class PchManagerServer : public PchManagerServerInterface, public: PchManagerServer(ClangPathWatcherInterface &fileSystemWatcher, PchTaskGeneratorInterface &pchTaskGenerator, - ProjectPartsInterface &projectParts, + ProjectPartsManagerInterface &projectParts, GeneratedFilesInterface &generatedFiles); void end() override; @@ -66,7 +66,7 @@ public: private: ClangPathWatcherInterface &m_fileSystemWatcher; PchTaskGeneratorInterface &m_pchTaskGenerator; - ProjectPartsInterface &m_projectParts; + ProjectPartsManagerInterface &m_projectPartsManager; GeneratedFilesInterface &m_generatedFiles; ToolChainsArgumentsCache m_toolChainsArgumentsCache; }; diff --git a/src/tools/clangpchmanagerbackend/source/pchtask.h b/src/tools/clangpchmanagerbackend/source/pchtask.h index c94d7ac816..528d6e63f1 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtask.h +++ b/src/tools/clangpchmanagerbackend/source/pchtask.h @@ -41,7 +41,7 @@ class PchTask public: PchTask(Utils::SmallString &&projectPartId, FilePathIds &&includes, - FilePathIds &&allIncludes, + FilePathIds &&sources, CompilerMacros &&compilerMacros, Utils::SmallStringVector &&usedMacros, Utils::SmallStringVector toolChainArguments, @@ -52,7 +52,7 @@ public: Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None) : projectPartIds({projectPartId}) , includes(includes) - , allIncludes(allIncludes) + , sources(sources) , compilerMacros(compilerMacros) , systemIncludeSearchPaths(std::move(systemIncludeSearchPaths)) , projectIncludeSearchPaths(std::move(projectIncludeSearchPaths)) @@ -64,7 +64,7 @@ public: PchTask(Utils::SmallStringVector &&projectPartIds, FilePathIds &&includes, - FilePathIds &&allIncludes, + FilePathIds &&sources, CompilerMacros &&compilerMacros, Utils::SmallStringVector &&usedMacros, Utils::SmallStringVector toolChainArguments, @@ -75,7 +75,7 @@ public: Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None) : projectPartIds(std::move(projectPartIds)) , includes(includes) - , allIncludes(allIncludes) + , sources(sources) , compilerMacros(compilerMacros) , systemIncludeSearchPaths(std::move(systemIncludeSearchPaths)) , projectIncludeSearchPaths(std::move(projectIncludeSearchPaths)) @@ -104,7 +104,7 @@ public: FilePath systemPchPath; Utils::SmallStringVector projectPartIds; FilePathIds includes; - FilePathIds allIncludes; + FilePathIds sources; CompilerMacros compilerMacros; IncludeSearchPaths systemIncludeSearchPaths; IncludeSearchPaths projectIncludeSearchPaths; diff --git a/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp b/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp index aab3bfe7d4..a44fc91b16 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp @@ -45,7 +45,7 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts, for (auto &projectPart : projectParts) { BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart); - UsedMacroFilter filter{buildDependency.includes, + UsedMacroFilter filter{buildDependency.sources, buildDependency.usedMacros, projectPart.compilerMacros}; @@ -62,7 +62,7 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts, projectPart.languageExtension}, PchTask{std::move(projectPart.projectPartId), std::move(filter.topProjectIncludes), - std::move(filter.allIncludes), + std::move(filter.sources), std::move(filter.projectCompilerMacros), std::move(filter.projectUsedMacros), projectPart.toolChainArguments, diff --git a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp index 50851a838a..65d1a3e9fe 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp @@ -96,8 +96,8 @@ bool PchTasksMerger::mergePchTasks(PchTask &firstTask, PchTask &secondTask) firstTask.projectPartIds = merge(std::move(firstTask.projectPartIds), std::move(secondTask.projectPartIds)); firstTask.includes = merge(std::move(firstTask.includes), std::move(secondTask.includes)); - firstTask.allIncludes = merge(std::move(firstTask.allIncludes), - std::move(secondTask.allIncludes)); + firstTask.sources = merge(std::move(firstTask.sources), + std::move(secondTask.sources)); firstTask.compilerMacros = std::move(macros); firstTask.systemIncludeSearchPaths = mergeIncludeSearchPaths( std::move(firstTask.systemIncludeSearchPaths), diff --git a/src/tools/clangpchmanagerbackend/source/projectparts.cpp b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.cpp index e8df25e104..8333ed9674 100644 --- a/src/tools/clangpchmanagerbackend/source/projectparts.cpp +++ b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.cpp @@ -23,7 +23,7 @@ ** ****************************************************************************/ -#include "projectparts.h" +#include "projectpartsmanager.h" #include <projectpartcontainer.h> @@ -33,7 +33,7 @@ namespace ClangBackEnd { inline namespace Pch { -ProjectPartContainers ProjectParts::update(ProjectPartContainers &&projectsParts) +ProjectPartContainers ProjectPartsManager::update(ProjectPartContainers &&projectsParts) { auto updatedProjectPartContainers = newProjectParts(std::move(projectsParts)); @@ -42,7 +42,7 @@ ProjectPartContainers ProjectParts::update(ProjectPartContainers &&projectsParts return updatedProjectPartContainers; } -void ProjectParts::remove(const Utils::SmallStringVector &ids) +void ProjectPartsManager::remove(const Utils::SmallStringVector &ids) { auto shouldRemove = [&] (const ProjectPartContainer &projectPart) { return std::find(ids.begin(), ids.end(), projectPart.projectPartId) != ids.end(); @@ -52,7 +52,7 @@ void ProjectParts::remove(const Utils::SmallStringVector &ids) m_projectParts.erase(newEnd, m_projectParts.end()); } -ProjectPartContainers ProjectParts::projects(const Utils::SmallStringVector &projectPartIds) const +ProjectPartContainers ProjectPartsManager::projects(const Utils::SmallStringVector &projectPartIds) const { ProjectPartContainers projectPartsWithIds; @@ -66,7 +66,7 @@ ProjectPartContainers ProjectParts::projects(const Utils::SmallStringVector &pro return projectPartsWithIds; } -void ProjectParts::updateDeferred(const ProjectPartContainers &deferredProjectsParts) +void ProjectPartsManager::updateDeferred(const ProjectPartContainers &deferredProjectsParts) { using ProjectPartContainerReferences = std::vector<std::reference_wrapper<ProjectPartContainer>>; @@ -86,7 +86,7 @@ void ProjectParts::updateDeferred(const ProjectPartContainers &deferredProjectsP projectPart.updateIsDeferred = true; } -ProjectPartContainers ProjectParts::deferredUpdates() +ProjectPartContainers ProjectPartsManager::deferredUpdates() { ProjectPartContainers deferredProjectParts; deferredProjectParts.reserve(m_projectParts.size()); @@ -102,7 +102,7 @@ ProjectPartContainers ProjectParts::deferredUpdates() return deferredProjectParts; } -ProjectPartContainers ProjectParts::newProjectParts(ProjectPartContainers &&projectsParts) const +ProjectPartContainers ProjectPartsManager::newProjectParts(ProjectPartContainers &&projectsParts) const { ProjectPartContainers updatedProjectPartContainers; updatedProjectPartContainers.reserve(projectsParts.size()); @@ -116,7 +116,7 @@ ProjectPartContainers ProjectParts::newProjectParts(ProjectPartContainers &&proj return updatedProjectPartContainers; } -void ProjectParts::mergeProjectParts(const ProjectPartContainers &projectsParts) +void ProjectPartsManager::mergeProjectParts(const ProjectPartContainers &projectsParts) { ProjectPartContainers newProjectParts; newProjectParts.reserve(m_projectParts.size() + projectsParts.size()); @@ -135,7 +135,7 @@ void ProjectParts::mergeProjectParts(const ProjectPartContainers &projectsParts) m_projectParts = newProjectParts; } -const ProjectPartContainers &ProjectParts::projectParts() const +const ProjectPartContainers &ProjectPartsManager::projectParts() const { return m_projectParts; } diff --git a/src/tools/clangpchmanagerbackend/source/projectparts.h b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h index 4df413ce6f..2b3c43ebc8 100644 --- a/src/tools/clangpchmanagerbackend/source/projectparts.h +++ b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h @@ -27,15 +27,14 @@ #include "clangpchmanagerbackend_global.h" -#include <projectpartsinterface.h> +#include <projectpartsmanagerinterface.h> #include <utils/smallstringvector.h> namespace ClangBackEnd { inline namespace Pch { - -class ProjectParts final : public ProjectPartsInterface +class ProjectPartsManager final : public ProjectPartsManagerInterface { public: ProjectPartContainers update(ProjectPartContainers &&projectsParts) override; diff --git a/src/tools/clangpchmanagerbackend/source/projectpartsinterface.h b/src/tools/clangpchmanagerbackend/source/projectpartsmanagerinterface.h index d37673af10..f99674ddda 100644 --- a/src/tools/clangpchmanagerbackend/source/projectpartsinterface.h +++ b/src/tools/clangpchmanagerbackend/source/projectpartsmanagerinterface.h @@ -29,12 +29,12 @@ namespace ClangBackEnd { -class ProjectPartsInterface +class ProjectPartsManagerInterface { public: - ProjectPartsInterface() = default; - ProjectPartsInterface(const ProjectPartsInterface &) = delete; - ProjectPartsInterface &operator=(const ProjectPartsInterface &) = delete; + ProjectPartsManagerInterface() = default; + ProjectPartsManagerInterface(const ProjectPartsManagerInterface &) = delete; + ProjectPartsManagerInterface &operator=(const ProjectPartsManagerInterface &) = delete; virtual ProjectPartContainers update(ProjectPartContainers &&projectsParts) = 0; virtual void remove(const Utils::SmallStringVector &projectPartIds) = 0; @@ -42,7 +42,7 @@ public: virtual void updateDeferred(const ProjectPartContainers &projectsParts) = 0; virtual ProjectPartContainers deferredUpdates() = 0; protected: - ~ProjectPartsInterface() = default; + ~ProjectPartsManagerInterface() = default; }; } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/sourceentry.h b/src/tools/clangpchmanagerbackend/source/sourceentry.h index e903baf3f6..5c45db6bde 100644 --- a/src/tools/clangpchmanagerbackend/source/sourceentry.h +++ b/src/tools/clangpchmanagerbackend/source/sourceentry.h @@ -31,19 +31,22 @@ namespace ClangBackEnd { -enum class SourceType : unsigned char -{ +enum class SourceType : unsigned char { TopProjectInclude, TopSystemInclude, UserInclude, ProjectInclude, - SystemInclude + SystemInclude, + Source }; +enum class HasMissingIncludes : unsigned char { No, Yes }; + class TimeStamp { using int64 = long long; public: + TimeStamp() = default; TimeStamp(int64 value) : value(value) {} @@ -58,7 +61,6 @@ public: class SourceTimeStamp { -protected: using int64 = long long; public: SourceTimeStamp(int sourceId, int64 lastModified) @@ -103,37 +105,47 @@ public: using SourceTimeStamps = std::vector<SourceTimeStamp>; -class SourceEntry : public SourceTimeStamp +class SourceEntry { + using int64 = long long; public: - SourceEntry(int sourceId, int64 lastModified, int sourceType) - : SourceTimeStamp(sourceId, lastModified) - , sourceType(static_cast<SourceType>(sourceType)) - {} - - SourceEntry(FilePathId sourceId, SourceType sourceType, TimeStamp lastModified) - : SourceTimeStamp(sourceId, lastModified) - , sourceType(sourceType) - {} - - friend bool operator<(SourceEntry first, SourceEntry second) - { + SourceEntry(int sourceId, + int64 pchCreationTimeStamp, + int sourceType, + int hasMissingIncludes) + : pchCreationTimeStamp(pchCreationTimeStamp), sourceId(sourceId), + sourceType(static_cast<SourceType>(sourceType)), + hasMissingIncludes( + static_cast<HasMissingIncludes>(hasMissingIncludes)) {} + + SourceEntry(FilePathId sourceId, + SourceType sourceType, + TimeStamp pchCreationTimeStamp, + HasMissingIncludes hasMissingIncludes = HasMissingIncludes::No) + : pchCreationTimeStamp(pchCreationTimeStamp), sourceId(sourceId), + sourceType(sourceType), hasMissingIncludes(hasMissingIncludes) {} + + friend bool operator<(SourceEntry first, SourceEntry second) { return first.sourceId < second.sourceId; } friend bool operator==(SourceEntry first, SourceEntry second) { return first.sourceId == second.sourceId && first.sourceType == second.sourceType - && first.lastModified == second.lastModified; + && first.pchCreationTimeStamp == second.pchCreationTimeStamp; } friend bool operator!=(SourceEntry first, SourceEntry second) { return !(first == second); } public: + TimeStamp pchCreationTimeStamp; + FilePathId sourceId; SourceType sourceType = SourceType::UserInclude; + HasMissingIncludes hasMissingIncludes = HasMissingIncludes::No; }; using SourceEntries = std::vector<SourceEntry>; - -} +using SourceEntryReference = std::reference_wrapper<SourceEntry>; +using SourceEntryReferences = std::vector<SourceEntryReference>; +} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h index 6042895325..9db3c683b9 100644 --- a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h +++ b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h @@ -87,23 +87,22 @@ public: UsedMacroFilter(const SourceEntries &includes, const UsedMacros &usedMacros, - const CompilerMacros &compilerMacros) - { - filterIncludes(includes); + const CompilerMacros &compilerMacros) { + filterSources(includes); systemUsedMacros = filterUsedMarcos(usedMacros, systemIncludes); projectUsedMacros = filterUsedMarcos(usedMacros, projectIncludes); filter(compilerMacros); } - void filterIncludes(const SourceEntries &includes) - { - systemIncludes.reserve(includes.size()); - projectIncludes.reserve(includes.size()); - topSystemIncludes.reserve(includes.size() / 10); - topProjectIncludes.reserve(includes.size() / 10); + void filterSources(const SourceEntries &sources) { + systemIncludes.reserve(sources.size()); + projectIncludes.reserve(sources.size()); + topSystemIncludes.reserve(sources.size() / 10); + topProjectIncludes.reserve(sources.size() / 10); + this->sources.reserve(sources.size()); - for (SourceEntry include : includes) - filterInclude(include); + for (SourceEntry source : sources) + filterSource(source); } void filter(const CompilerMacros &compilerMacros) @@ -121,28 +120,31 @@ public: } private: - void filterInclude(SourceEntry include) - { - switch (include.sourceType) { - case SourceType::TopSystemInclude: - topSystemIncludes.emplace_back(include.sourceId); - systemIncludes.emplace_back(include.sourceId); - break; - case SourceType::SystemInclude: - systemIncludes.emplace_back(include.sourceId); - break; - case SourceType::TopProjectInclude: - topProjectIncludes.emplace_back(include.sourceId); - projectIncludes.emplace_back(include.sourceId); - break; - case SourceType::ProjectInclude: - projectIncludes.emplace_back(include.sourceId); - break; - case SourceType::UserInclude: - break; + void filterSource(SourceEntry source) { + if (source.hasMissingIncludes == HasMissingIncludes::Yes) + return; + + switch (source.sourceType) { + case SourceType::TopSystemInclude: + topSystemIncludes.emplace_back(source.sourceId); + systemIncludes.emplace_back(source.sourceId); + break; + case SourceType::SystemInclude: + systemIncludes.emplace_back(source.sourceId); + break; + case SourceType::TopProjectInclude: + topProjectIncludes.emplace_back(source.sourceId); + projectIncludes.emplace_back(source.sourceId); + break; + case SourceType::ProjectInclude: + projectIncludes.emplace_back(source.sourceId); + break; + case SourceType::UserInclude: + case SourceType::Source: + break; } - allIncludes.emplace_back(include.sourceId); + sources.emplace_back(source.sourceId); } static Utils::SmallStringVector filterUsedMarcos(const UsedMacros &usedMacros, @@ -209,7 +211,7 @@ private: } public: - FilePathIds allIncludes; + FilePathIds sources; FilePathIds projectIncludes; FilePathIds systemIncludes; FilePathIds topProjectIncludes; diff --git a/src/tools/clangrefactoringbackend/source/filestatus.h b/src/tools/clangrefactoringbackend/source/filestatus.h index 9ade546294..da2be4a304 100644 --- a/src/tools/clangrefactoringbackend/source/filestatus.h +++ b/src/tools/clangrefactoringbackend/source/filestatus.h @@ -36,15 +36,8 @@ namespace ClangBackEnd { class FileStatus { public: - FileStatus(FilePathId filePathId, - off_t size, - std::time_t lastModified, - bool isInPrecompiledHeader) - : filePathId(filePathId), - size(size), - lastModified(lastModified), - isInPrecompiledHeader(isInPrecompiledHeader) - {} + FileStatus(FilePathId filePathId, off_t size, std::time_t lastModified) + : filePathId(filePathId), size(size), lastModified(lastModified) {} friend bool operator==(const FileStatus &first, const FileStatus &second) @@ -64,7 +57,6 @@ public: FilePathId filePathId; off_t size; std::time_t lastModified; - bool isInPrecompiledHeader; }; using FileStatuses = std::vector<FileStatus>; diff --git a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp index 6928e49712..aee8344fc9 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp @@ -120,8 +120,7 @@ void SymbolIndexer::updateProjectPart(ProjectPartContainer &&projectPart) std::vector<SymbolIndexerTask> symbolIndexerTask; symbolIndexerTask.reserve(projectPart.sourcePathIds.size()); for (FilePathId sourcePathId : projectPart.sourcePathIds) { - auto indexing = [projectPartId, - arguments = commandLineBuilder.commandLine, + auto indexing = [arguments = commandLineBuilder.commandLine, sourcePathId, this](SymbolsCollectorInterface &symbolsCollector) { symbolsCollector.setFile(sourcePathId, arguments); @@ -134,12 +133,9 @@ void SymbolIndexer::updateProjectPart(ProjectPartContainer &&projectPart) m_symbolStorage.addSymbolsAndSourceLocations(symbolsCollector.symbols(), symbolsCollector.sourceLocations()); - m_symbolStorage.updateProjectPartSources(projectPartId, - symbolsCollector.sourceFiles()); - m_buildDependencyStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); - m_buildDependencyStorage.insertFileStatuses(symbolsCollector.fileStatuses()); + m_buildDependencyStorage.insertOrUpdateFileStatuses(symbolsCollector.fileStatuses()); m_buildDependencyStorage.insertOrUpdateSourceDependencies( symbolsCollector.sourceDependencies()); @@ -193,10 +189,8 @@ void SymbolIndexer::updateChangedPath(FilePathId filePathId, CommandLineBuilder<ProjectPartArtefact, Utils::SmallStringVector> builder{artefact, artefact.toolChainArguments, InputFileType::Source, {}, {}, pchPath}; - auto indexing = [projectPartId = artefact.projectPartId, - arguments = builder.commandLine, - filePathId, - this](SymbolsCollectorInterface &symbolsCollector) { + auto indexing = [arguments = builder.commandLine, filePathId, this]( + SymbolsCollectorInterface &symbolsCollector) { symbolsCollector.setFile(filePathId, arguments); bool success = symbolsCollector.collectSymbols(); @@ -207,11 +201,9 @@ void SymbolIndexer::updateChangedPath(FilePathId filePathId, m_symbolStorage.addSymbolsAndSourceLocations(symbolsCollector.symbols(), symbolsCollector.sourceLocations()); - m_symbolStorage.updateProjectPartSources(projectPartId, symbolsCollector.sourceFiles()); - m_buildDependencyStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); - m_buildDependencyStorage.insertFileStatuses(symbolsCollector.fileStatuses()); + m_buildDependencyStorage.insertOrUpdateFileStatuses(symbolsCollector.fileStatuses()); m_buildDependencyStorage.insertOrUpdateSourceDependencies( symbolsCollector.sourceDependencies()); diff --git a/src/tools/clangrefactoringbackend/source/symbolstorage.h b/src/tools/clangrefactoringbackend/source/symbolstorage.h index 3b7141c783..798fa26dd0 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorage.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorage.h @@ -112,17 +112,6 @@ public: return statement.template value<ProjectPartArtefact, 8>(projectPartName); } - void updateProjectPartSources(int projectPartId, - const FilePathIds &sourceFilePathIds) override - { - WriteStatement &deleteStatement = m_deleteAllProjectPartsSourcesWithProjectPartIdStatement; - deleteStatement.write(projectPartId); - - WriteStatement &insertStatement = m_insertProjectPartSourcesStatement; - for (const FilePathId &sourceFilePathId : sourceFilePathIds) - insertStatement.write(projectPartId, sourceFilePathId.filePathId); - } - static Utils::SmallString toJson(const Utils::SmallStringVector &strings) { QJsonDocument document; @@ -322,14 +311,7 @@ public: "SELECT projectPartId FROM projectParts WHERE projectPartName = ?", m_database }; - WriteStatement m_deleteAllProjectPartsSourcesWithProjectPartIdStatement{ - "DELETE FROM projectPartsSources WHERE projectPartId = ?", - m_database - }; - WriteStatement m_insertProjectPartSourcesStatement{ - "INSERT INTO projectPartsSources(projectPartId, sourceId) VALUES (?,?)", - m_database - }; + mutable ReadStatement m_getCompileArgumentsForFileIdStatement{ "SELECT toolChainArguments FROM projectParts WHERE projectPartId = (SELECT projectPartId " "FROM projectPartsSources WHERE sourceId = ?)", diff --git a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h index 5f2e6c30e6..210f66f7da 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h @@ -61,7 +61,6 @@ public: Utils::LanguageVersion languageVersion, Utils::LanguageExtension languageExtension) = 0; - virtual void updateProjectPartSources(int projectPartId, const FilePathIds &sourceFilePathIds) = 0; virtual Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact( FilePathId sourceId) const = 0; virtual Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact( diff --git a/tests/unit/unittest/builddependenciesprovider-test.cpp b/tests/unit/unittest/builddependenciesprovider-test.cpp index 2a5372c55d..b69965cc56 100644 --- a/tests/unit/unittest/builddependenciesprovider-test.cpp +++ b/tests/unit/unittest/builddependenciesprovider-test.cpp @@ -99,9 +99,7 @@ protected: UsedMacros thirdUsedMacros{{"SAN", 10}}; FilePathIds sourceFiles{1, 3, 8}; ClangBackEnd::SourceDependencies sourceDependencies{{1, 3}, {1, 8}}; - ClangBackEnd::FileStatuses fileStatuses{{1, 21, 12, false}, - {3, 21, 12, false}, - {8, 21, 12, false}}; + ClangBackEnd::FileStatuses fileStatuses{{1, 21, 12}, {3, 21, 12}, {8, 21, 12}}; BuildDependency buildDependency{ secondSources, secondUsedMacros, @@ -117,7 +115,9 @@ TEST_F(BuildDependenciesProvider, CreateCallsFetchDependSourcesFromStorageIfTime EXPECT_CALL(mockSqliteTransactionBackend, deferredBegin()); EXPECT_CALL(mockBuildDependenciesStorage, - fetchDependSources({2}, TypedEq<Utils::SmallStringView>("ProjectPart1"))) + fetchProjectPartId(TypedEq<Utils::SmallStringView>("ProjectPart1"))) + .WillOnce(Return(11)); + EXPECT_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, 11)) .WillRepeatedly(Return(firstSources)); EXPECT_CALL(mockSqliteTransactionBackend, commit()); EXPECT_CALL(mockModifiedTimeChecker, isUpToDate(firstSources)).WillRepeatedly(Return(true)); @@ -132,15 +132,24 @@ TEST_F(BuildDependenciesProvider, CreateCallsFetchDependSourcesFromStorageIfTime TEST_F(BuildDependenciesProvider, FetchDependSourcesFromStorage) { - ON_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, TypedEq<Utils::SmallStringView>("ProjectPart2"))).WillByDefault(Return(firstSources)); - ON_CALL(mockBuildDependenciesStorage, fetchDependSources({3}, TypedEq<Utils::SmallStringView>("ProjectPart2"))).WillByDefault(Return(secondSources)); - ON_CALL(mockBuildDependenciesStorage, fetchDependSources({4}, TypedEq<Utils::SmallStringView>("ProjectPart2"))).WillByDefault(Return(thirdSources)); + ON_CALL(mockBuildDependenciesStorage, + fetchProjectPartId(TypedEq<Utils::SmallStringView>("ProjectPart2"))) + .WillByDefault(Return(11)); + ON_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, 11)).WillByDefault(Return(firstSources)); + ON_CALL(mockBuildDependenciesStorage, fetchDependSources({3}, 11)).WillByDefault(Return(secondSources)); + ON_CALL(mockBuildDependenciesStorage, fetchDependSources({4}, 11)).WillByDefault(Return(thirdSources)); ON_CALL(mockModifiedTimeChecker, isUpToDate(_)).WillByDefault(Return(true)); auto buildDependency = provider.create(projectPart2); - ASSERT_THAT(buildDependency.includes, ElementsAre(HasSourceId(1), HasSourceId(2), HasSourceId(3), HasSourceId(4), HasSourceId(8), HasSourceId(10))); + ASSERT_THAT(buildDependency.sources, + ElementsAre(HasSourceId(1), + HasSourceId(2), + HasSourceId(3), + HasSourceId(4), + HasSourceId(8), + HasSourceId(10))); } TEST_F(BuildDependenciesProvider, CreateCallsFetchDependSourcesFromGeneratorIfTimeStampsAreNotUpToDate) @@ -149,15 +158,17 @@ TEST_F(BuildDependenciesProvider, CreateCallsFetchDependSourcesFromGeneratorIfTi EXPECT_CALL(mockSqliteTransactionBackend, deferredBegin()); EXPECT_CALL(mockBuildDependenciesStorage, - fetchDependSources({2}, TypedEq<Utils::SmallStringView>("ProjectPart1"))) + fetchProjectPartId(TypedEq<Utils::SmallStringView>("ProjectPart1"))) + .WillOnce(Return(11)); + EXPECT_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, TypedEq<int>(11))) .WillRepeatedly(Return(firstSources)); EXPECT_CALL(mockSqliteTransactionBackend, commit()); EXPECT_CALL(mockModifiedTimeChecker, isUpToDate(firstSources)).WillRepeatedly(Return(false)); EXPECT_CALL(mockBuildDependenciesGenerator, create(projectPart1)) .WillOnce(Return(buildDependency)); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); - EXPECT_CALL(mockBuildDependenciesStorage, updateSources(Eq(secondSources))); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(Eq(fileStatuses))); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSources(Eq(secondSources), 11)); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(Eq(fileStatuses))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(Eq(sourceDependencies))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(Eq(secondUsedMacros))); EXPECT_CALL(mockSqliteTransactionBackend, commit()); @@ -167,13 +178,16 @@ TEST_F(BuildDependenciesProvider, CreateCallsFetchDependSourcesFromGeneratorIfTi TEST_F(BuildDependenciesProvider, FetchDependSourcesFromGenerator) { - ON_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, TypedEq<Utils::SmallStringView>("ProjectPart1"))).WillByDefault(Return(firstSources)); + ON_CALL(mockBuildDependenciesStorage, + fetchProjectPartId(TypedEq<Utils::SmallStringView>("ProjectPart1"))) + .WillByDefault(Return(11)); + ON_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, 11)).WillByDefault(Return(firstSources)); ON_CALL(mockModifiedTimeChecker, isUpToDate(_)).WillByDefault(Return(false)); ON_CALL(mockBuildDependenciesGenerator, create(projectPart1)).WillByDefault(Return(buildDependency)); auto buildDependency = provider.create(projectPart1); - ASSERT_THAT(buildDependency.includes, ElementsAre(HasSourceId(1), HasSourceId(3), HasSourceId(8))); + ASSERT_THAT(buildDependency.sources, ElementsAre(HasSourceId(1), HasSourceId(3), HasSourceId(8))); } TEST_F(BuildDependenciesProvider, CreateCallsFetchUsedMacrosFromStorageIfTimeStampsAreUpToDate) @@ -181,7 +195,11 @@ TEST_F(BuildDependenciesProvider, CreateCallsFetchUsedMacrosFromStorageIfTimeSta InSequence s; EXPECT_CALL(mockSqliteTransactionBackend, deferredBegin()); - EXPECT_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, TypedEq<Utils::SmallStringView>("ProjectPart1"))).WillRepeatedly(Return(firstSources)); + EXPECT_CALL(mockBuildDependenciesStorage, + fetchProjectPartId(TypedEq<Utils::SmallStringView>("ProjectPart1"))) + .WillOnce(Return(11)); + EXPECT_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, 11)) + .WillRepeatedly(Return(firstSources)); EXPECT_CALL(mockSqliteTransactionBackend, commit()); EXPECT_CALL(mockModifiedTimeChecker, isUpToDate(firstSources)).WillRepeatedly(Return(true)); EXPECT_CALL(mockSqliteTransactionBackend, deferredBegin()); @@ -195,7 +213,10 @@ TEST_F(BuildDependenciesProvider, CreateCallsFetchUsedMacrosFromStorageIfTimeSta TEST_F(BuildDependenciesProvider, FetchUsedMacrosFromStorageIfDependSourcesAreUpToDate) { - ON_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, TypedEq<Utils::SmallStringView>("ProjectPart1"))).WillByDefault(Return(firstSources)); + ON_CALL(mockBuildDependenciesStorage, + fetchProjectPartId(TypedEq<Utils::SmallStringView>("ProjectPart1"))) + .WillByDefault(Return(11)); + ON_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, 11)).WillByDefault(Return(firstSources)); ON_CALL(mockModifiedTimeChecker, isUpToDate(firstSources)).WillByDefault(Return(true)); ON_CALL(mockBuildDependenciesStorage, fetchUsedMacros({1})).WillByDefault(Return(firstUsedMacros)); ON_CALL(mockBuildDependenciesStorage, fetchUsedMacros({2})).WillByDefault(Return(secondUsedMacros)); diff --git a/tests/unit/unittest/builddependenciesstorage-test.cpp b/tests/unit/unittest/builddependenciesstorage-test.cpp index d69f8b868a..30db7ea408 100644 --- a/tests/unit/unittest/builddependenciesstorage-test.cpp +++ b/tests/unit/unittest/builddependenciesstorage-test.cpp @@ -55,17 +55,20 @@ protected: MockSqliteWriteStatement &syncNewUsedMacrosStatement =storage.syncNewUsedMacrosStatement; MockSqliteWriteStatement &deleteOutdatedUsedMacrosStatement = storage.deleteOutdatedUsedMacrosStatement; MockSqliteWriteStatement &deleteNewUsedMacrosTableStatement = storage.deleteNewUsedMacrosTableStatement; - MockSqliteWriteStatement &insertFileStatuses = storage.insertFileStatusesStatement; + MockSqliteWriteStatement &insertOrUpdateFileStatusesStatement = storage.insertOrUpdateFileStatusesStatement; MockSqliteWriteStatement &insertIntoNewSourceDependenciesStatement = storage.insertIntoNewSourceDependenciesStatement; MockSqliteWriteStatement &syncNewSourceDependenciesStatement = storage.syncNewSourceDependenciesStatement; MockSqliteWriteStatement &deleteOutdatedSourceDependenciesStatement = storage.deleteOutdatedSourceDependenciesStatement; MockSqliteWriteStatement &deleteNewSourceDependenciesStatement = storage.deleteNewSourceDependenciesStatement; MockSqliteReadStatement &getLowestLastModifiedTimeOfDependencies = storage.getLowestLastModifiedTimeOfDependencies; - MockSqliteWriteStatement &updateBuildDependencyTimeStampStatement = storage.updateBuildDependencyTimeStampStatement; - MockSqliteWriteStatement &updateSourceTypeStatement = storage.updateSourceTypeStatement; + MockSqliteWriteStatement &insertOrUpdateProjectPartsSourcesStatement = storage.insertOrUpdateProjectPartsSourcesStatement; MockSqliteReadStatement &fetchSourceDependenciesStatement = storage.fetchSourceDependenciesStatement; MockSqliteReadStatement &fetchProjectPartIdStatement = storage.fetchProjectPartIdStatement; MockSqliteReadStatement &fetchUsedMacrosStatement = storage.fetchUsedMacrosStatement; + MockSqliteWriteStatement &insertProjectPartNameStatement = storage.insertProjectPartNameStatement; + MockSqliteWriteStatement &updatePchCreationTimeStampStatement = storage.updatePchCreationTimeStampStatement; + MockSqliteWriteStatement &deleteAllProjectPartsSourcesWithProjectPartNameStatement + = storage.deleteAllProjectPartsSourcesWithProjectPartNameStatement; }; TEST_F(BuildDependenciesStorage, ConvertStringsToJson) @@ -81,8 +84,10 @@ TEST_F(BuildDependenciesStorage, InsertOrUpdateUsedMacros) { InSequence sequence; - EXPECT_CALL(insertIntoNewUsedMacrosStatement, write(TypedEq<uint>(42u), TypedEq<Utils::SmallStringView>("FOO"))); - EXPECT_CALL(insertIntoNewUsedMacrosStatement, write(TypedEq<uint>(43u), TypedEq<Utils::SmallStringView>("BAR"))); + EXPECT_CALL(insertIntoNewUsedMacrosStatement, + write(TypedEq<int>(42), TypedEq<Utils::SmallStringView>("FOO"))); + EXPECT_CALL(insertIntoNewUsedMacrosStatement, + write(TypedEq<int>(43), TypedEq<Utils::SmallStringView>("BAR"))); EXPECT_CALL(syncNewUsedMacrosStatement, execute()); EXPECT_CALL(deleteOutdatedUsedMacrosStatement, execute()); EXPECT_CALL(deleteNewUsedMacrosTableStatement, execute()); @@ -90,12 +95,14 @@ TEST_F(BuildDependenciesStorage, InsertOrUpdateUsedMacros) storage.insertOrUpdateUsedMacros({{"FOO", 42}, {"BAR", 43}}); } -TEST_F(BuildDependenciesStorage, InsertFileStatuses) +TEST_F(BuildDependenciesStorage, InsertOrUpdateFileStatuses) { - EXPECT_CALL(insertFileStatuses, write(TypedEq<int>(42), TypedEq<off_t>(1), TypedEq<time_t>(2), TypedEq<bool>(false))); - EXPECT_CALL(insertFileStatuses, write(TypedEq<int>(43), TypedEq<off_t>(4), TypedEq<time_t>(5), TypedEq<bool>(true))); + EXPECT_CALL(insertOrUpdateFileStatusesStatement, + write(TypedEq<int>(42), TypedEq<off_t>(1), TypedEq<time_t>(2))); + EXPECT_CALL(insertOrUpdateFileStatusesStatement, + write(TypedEq<int>(43), TypedEq<off_t>(4), TypedEq<time_t>(5))); - storage.insertFileStatuses({{42, 1, 2, false}, {43, 4, 5, true}}); + storage.insertOrUpdateFileStatuses({{42, 1, 2}, {43, 4, 5}}); } TEST_F(BuildDependenciesStorage, InsertOrUpdateSourceDependencies) @@ -125,7 +132,6 @@ TEST_F(BuildDependenciesStorage, AddTablesInConstructor) Storage storage{mockDatabase}; } - TEST_F(BuildDependenciesStorage, FetchLowestLastModifiedTimeIfNoModificationTimeExists) { EXPECT_CALL(getLowestLastModifiedTimeOfDependencies, valueReturnInt64(Eq(1))); @@ -168,48 +174,82 @@ TEST_F(BuildDependenciesStorage, AddNewSourceDependenciesTable) TEST_F(BuildDependenciesStorage, UpdateSources) { InSequence s; - SourceEntries entries{{1, SourceType::TopProjectInclude, 10}, {2, SourceType::TopSystemInclude, 20}}; + SourceEntries entries{{1, SourceType::TopProjectInclude, 10, ClangBackEnd::HasMissingIncludes::Yes}, + {2, SourceType::TopSystemInclude, 20}}; + + EXPECT_CALL(deleteAllProjectPartsSourcesWithProjectPartNameStatement, write(TypedEq<int>(22))); + EXPECT_CALL(insertOrUpdateProjectPartsSourcesStatement, + write(TypedEq<int>(1), TypedEq<int>(22), TypedEq<uchar>(0), TypedEq<uchar>(1))); + EXPECT_CALL(insertOrUpdateProjectPartsSourcesStatement, + write(TypedEq<int>(2), TypedEq<int>(22), TypedEq<uchar>(1), TypedEq<uchar>(0))); + + storage.insertOrUpdateSources(entries, 22); +} + +TEST_F(BuildDependenciesStorage, UpdatePchCreationTimeStamp) +{ + InSequence s; - EXPECT_CALL(updateBuildDependencyTimeStampStatement, write(TypedEq<long long>(10), TypedEq<int>(1))); - EXPECT_CALL(updateSourceTypeStatement, write(TypedEq<uchar>(0), TypedEq<int>(1))); - EXPECT_CALL(updateBuildDependencyTimeStampStatement, write(TypedEq<long long>(20), TypedEq<int>(2))); - EXPECT_CALL(updateSourceTypeStatement, write(TypedEq<uchar>(1), TypedEq<int>(2))); + EXPECT_CALL(mockDatabase, immediateBegin()); + EXPECT_CALL(updatePchCreationTimeStampStatement, + write(TypedEq<long long>(101), TypedEq<Utils::SmallStringView>("project1"))); + EXPECT_CALL(mockDatabase, commit()); - storage.updateSources(entries); + storage.updatePchCreationTimeStamp(101, "project1"); } -TEST_F(BuildDependenciesStorage, CallsFetchDependSourcesWithNonExistingProjectPartDontFetchesSourceDependencies) +TEST_F(BuildDependenciesStorage, CallsFetchProjectIdWithNonExistingProjectPartName) { - EXPECT_CALL(fetchProjectPartIdStatement, valueReturnInt32(TypedEq<Utils::SmallStringView>("test"))).WillOnce(Return(Utils::optional<int>{})); - EXPECT_CALL(fetchSourceDependenciesStatement, valuesReturnSourceEntries(_, _, _)).Times(0); + EXPECT_CALL(fetchProjectPartIdStatement, + valueReturnInt32(TypedEq<Utils::SmallStringView>("test"))); + EXPECT_CALL(insertProjectPartNameStatement, write(TypedEq<Utils::SmallStringView>("test"))); - storage.fetchDependSources(22, "test"); + storage.fetchProjectPartId("test"); } -TEST_F(BuildDependenciesStorage, CallsFetchDependSourcesWithExistingProjectPartFetchesSourceDependencies) +TEST_F(BuildDependenciesStorage, CallsFetchProjectIdWithExistingProjectPart) { - EXPECT_CALL(fetchProjectPartIdStatement, valueReturnInt32(TypedEq<Utils::SmallStringView>("test"))).WillOnce(Return(Utils::optional<int>{20})); - EXPECT_CALL(fetchSourceDependenciesStatement, valuesReturnSourceEntries(_, 22, 20)); + EXPECT_CALL(fetchProjectPartIdStatement, valueReturnInt32(TypedEq<Utils::SmallStringView>("test"))) + .WillOnce(Return(Utils::optional<int>{20})); + EXPECT_CALL(insertProjectPartNameStatement, write(TypedEq<Utils::SmallStringView>("test"))).Times(0); - storage.fetchDependSources(22, "test"); + storage.fetchProjectPartId("test"); } -TEST_F(BuildDependenciesStorage, FetchDependSourcesWithNonExistingProjectPartReturnsEmptySourceEntries) +TEST_F(BuildDependenciesStorage, FetchProjectIdWithNonExistingProjectPartName) { - EXPECT_CALL(fetchProjectPartIdStatement, valueReturnInt32(TypedEq<Utils::SmallStringView>("test"))).WillOnce(Return(Utils::optional<int>{})); + ON_CALL(fetchProjectPartIdStatement, valueReturnInt32(TypedEq<Utils::SmallStringView>("test"))) + .WillByDefault(Return(Utils::optional<int>{})); + ON_CALL(mockDatabase, lastInsertedRowId()).WillByDefault(Return(21)); - auto entries = storage.fetchDependSources(22, "test"); + int id = storage.fetchProjectPartId("test"); + + ASSERT_THAT(id, 21); +} + +TEST_F(BuildDependenciesStorage, FetchProjectIdWithExistingProjectPartName) +{ + ON_CALL(fetchProjectPartIdStatement, valueReturnInt32(TypedEq<Utils::SmallStringView>("test"))) + .WillByDefault(Return(Utils::optional<int>{20})); + + int id = storage.fetchProjectPartId("test"); + + ASSERT_THAT(id, 20); +} + +TEST_F(BuildDependenciesStorage, CallsFetchDependSources) +{ + EXPECT_CALL(fetchSourceDependenciesStatement, valuesReturnSourceEntries(_, 22, 20)); - ASSERT_THAT(entries, IsEmpty()); + storage.fetchDependSources(22, 20); } -TEST_F(BuildDependenciesStorage, FetchDependSourcesWithExistingProjectPartReturnsSourceEntries) +TEST_F(BuildDependenciesStorage, FetchDependSources) { SourceEntries sourceEntries{{1, SourceType::TopProjectInclude, 10}, {2, SourceType::TopSystemInclude, 20}}; - EXPECT_CALL(fetchProjectPartIdStatement, valueReturnInt32(TypedEq<Utils::SmallStringView>("test"))).WillOnce(Return(Utils::optional<int>{20})); EXPECT_CALL(fetchSourceDependenciesStatement, valuesReturnSourceEntries(_, 22, 20)).WillOnce(Return(sourceEntries)); - auto entries = storage.fetchDependSources(22, "test"); + auto entries = storage.fetchDependSources(22, 20); ASSERT_THAT(entries, sourceEntries); } diff --git a/tests/unit/unittest/builddependencycollector-test.cpp b/tests/unit/unittest/builddependencycollector-test.cpp index aa46fc77bb..5850666232 100644 --- a/tests/unit/unittest/builddependencycollector-test.cpp +++ b/tests/unit/unittest/builddependencycollector-test.cpp @@ -47,19 +47,37 @@ using ClangBackEnd::BuildDependency; using ClangBackEnd::FilePathId; using ClangBackEnd::FilePathIds; using ClangBackEnd::FilePathView; +using ClangBackEnd::HasMissingIncludes; using ClangBackEnd::SourceDependency; using ClangBackEnd::SourceType; using ClangBackEnd::UsedMacro; namespace { -MATCHER_P2(HasInclude, sourceId, sourceType, +MATCHER_P2(HasSource, + sourceId, + sourceType, std::string(negation ? "hasn't " : "has ") - + PrintToString(ClangBackEnd::SourceEntry(sourceId, sourceType, -1))) + + PrintToString(ClangBackEnd::SourceEntry( + sourceId, sourceType, -1, ClangBackEnd::HasMissingIncludes::No))) { const ClangBackEnd::SourceEntry &entry = arg; - return entry.sourceId == sourceId && entry.sourceType == sourceType; + return entry.sourceId == sourceId && entry.sourceType == sourceType + && entry.hasMissingIncludes == ClangBackEnd::HasMissingIncludes::No; +} + +MATCHER_P3(HasSource, + sourceId, + sourceType, + hasMissingIncludes, + std::string(negation ? "hasn't " : "has ") + + PrintToString(ClangBackEnd::SourceEntry(sourceId, sourceType, -1, hasMissingIncludes))) +{ + const ClangBackEnd::SourceEntry &entry = arg; + + return entry.sourceId == sourceId && entry.sourceType == sourceType + && entry.hasMissingIncludes == hasMissingIncludes; } class BuildDependencyCollector : public ::testing::Test @@ -107,50 +125,50 @@ protected: ClangBackEnd::FileStatus fileStatus(Utils::SmallStringView filePath) const { - return {id(filePath), fileSize(filePath), lastModified(filePath), false}; + return {id(filePath), fileSize(filePath), lastModified(filePath)}; } - static FilePathIds filteredIncludes(const ClangBackEnd::SourceEntries &includes, - ClangBackEnd::SourceType includeType) + static FilePathIds filteredSources(const ClangBackEnd::SourceEntries &sources, + ClangBackEnd::SourceType sourceType) { - FilePathIds filteredIncludes; + FilePathIds filteredSources; - for (const ClangBackEnd::SourceEntry &include : includes) { - if (include.sourceType == includeType) - filteredIncludes.push_back(include.sourceId); + for (const ClangBackEnd::SourceEntry &source : sources) { + if (source.sourceType == sourceType) + filteredSources.push_back(source.sourceId); } - return filteredIncludes; + return filteredSources; } - static FilePathIds topIncludes(const ClangBackEnd::SourceEntries &includes) + static FilePathIds topSources(const ClangBackEnd::SourceEntries &sources) { - return filteredIncludes(includes, ClangBackEnd::SourceType::TopProjectInclude); + return filteredSources(sources, ClangBackEnd::SourceType::TopProjectInclude); } - static FilePathIds systemTopIncludes(const ClangBackEnd::SourceEntries &includes) + static FilePathIds systemTopSources(const ClangBackEnd::SourceEntries &sources) { - return filteredIncludes(includes, ClangBackEnd::SourceType::TopSystemInclude); + return filteredSources(sources, ClangBackEnd::SourceType::TopSystemInclude); } - static FilePathIds userIncludes(const ClangBackEnd::SourceEntries &includes) + static FilePathIds userSources(const ClangBackEnd::SourceEntries &sources) { - return filteredIncludes(includes, ClangBackEnd::SourceType::UserInclude); + return filteredSources(sources, ClangBackEnd::SourceType::UserInclude); } - static FilePathIds projectPartIncludes(const ClangBackEnd::SourceEntries &includes) + static FilePathIds projectPartSources(const ClangBackEnd::SourceEntries &sources) { - return filteredIncludes(includes, ClangBackEnd::SourceType::ProjectInclude); + return filteredSources(sources, ClangBackEnd::SourceType::ProjectInclude); } - static FilePathIds allIncludes(const ClangBackEnd::SourceEntries &includes) + static FilePathIds sources(const ClangBackEnd::SourceEntries &sources) { - FilePathIds filteredIncludes; + FilePathIds filteredSources; - for (const ClangBackEnd::SourceEntry &include : includes) - filteredIncludes.push_back(include.sourceId); + for (const ClangBackEnd::SourceEntry &source : sources) + filteredSources.push_back(source.sourceId); - return filteredIncludes; + return filteredSources; } protected: @@ -173,26 +191,31 @@ TEST_F(BuildDependencyCollector, IncludesExternalHeader) { collector.collect(); - ASSERT_THAT(allIncludes(collector.includeIds()), + ASSERT_THAT(sources(collector.sourceEntries()), AllOf(Contains(id(TESTDATA_DIR "/builddependencycollector/external/external1.h")), Contains(id(TESTDATA_DIR "/builddependencycollector/external/external2.h")), - Contains(id(TESTDATA_DIR "/builddependencycollector/external/indirect_external.h")), - Contains(id(TESTDATA_DIR "/builddependencycollector/external/indirect_external2.h")))); + Contains(id(TESTDATA_DIR + "/builddependencycollector/external/indirect_external.h")), + Contains(id(TESTDATA_DIR + "/builddependencycollector/external/indirect_external2.h")))); } TEST_F(BuildDependencyCollector, InternalHeaderAreUserIncludes) { collector.collect(); - ASSERT_THAT(userIncludes(collector.includeIds()), Contains(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"))); + ASSERT_THAT(userSources(collector.sourceEntries()), + Contains(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"))); } TEST_F(BuildDependencyCollector, NoDuplicate) { collector.collect(); - ASSERT_THAT(allIncludes(collector.includeIds()), + ASSERT_THAT(sources(collector.sourceEntries()), UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/project/main.cpp"), + id(TESTDATA_DIR "/builddependencycollector/project/main2.cpp"), id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), @@ -206,15 +229,18 @@ TEST_F(BuildDependencyCollector, IncludesAreSorted) { collector.collect(); - ASSERT_THAT(allIncludes(collector.includeIds()), - ElementsAre( - id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), - id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external3.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - id(TESTDATA_DIR "/builddependencycollector/external/indirect_external.h"), - id(TESTDATA_DIR "/builddependencycollector/external/indirect_external2.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external2.h"))); + ASSERT_THAT(sources(collector.sourceEntries()), + ElementsAre(id(TESTDATA_DIR "/builddependencycollector/project/main.cpp"), + id(TESTDATA_DIR "/builddependencycollector/project/main2.cpp"), + id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), + id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external3.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), + id(TESTDATA_DIR + "/builddependencycollector/external/indirect_external.h"), + id(TESTDATA_DIR + "/builddependencycollector/external/indirect_external2.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external2.h"))); } TEST_F(BuildDependencyCollector, If) @@ -223,8 +249,9 @@ TEST_F(BuildDependencyCollector, If) emptyCollector.collect(); - ASSERT_THAT(allIncludes(emptyCollector.includeIds()), - ElementsAre(id(TESTDATA_DIR "/builddependencycollector/project/true.h"))); + ASSERT_THAT(sources(emptyCollector.sourceEntries()), + ElementsAre(id(TESTDATA_DIR "/builddependencycollector/project/if.cpp"), + id(TESTDATA_DIR "/builddependencycollector/project/true.h"))); } TEST_F(BuildDependencyCollector, LocalPath) @@ -233,8 +260,9 @@ TEST_F(BuildDependencyCollector, LocalPath) emptyCollector.collect(); - ASSERT_THAT(allIncludes(emptyCollector.includeIds()), + ASSERT_THAT(sources(emptyCollector.sourceEntries()), UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/project/main.cpp"), id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), @@ -250,20 +278,23 @@ TEST_F(BuildDependencyCollector, IgnoreMissingFile) emptyCollector.collect(); - ASSERT_THAT(allIncludes(emptyCollector.includeIds()), - UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - id(TESTDATA_DIR "/builddependencycollector/external/indirect_external.h"), - id(TESTDATA_DIR "/builddependencycollector/external/indirect_external2.h"))); + ASSERT_THAT(sources(emptyCollector.sourceEntries()), + UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/project/missingfile.cpp"), + id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), + id(TESTDATA_DIR "/builddependencycollector/external/indirect_external.h"), + id(TESTDATA_DIR "/builddependencycollector/external/indirect_external2.h"))); } TEST_F(BuildDependencyCollector, IncludesOnlyTopExternalHeader) { collector.collect(); - ASSERT_THAT(topIncludes(collector.includeIds()), - UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external2.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external3.h"))); + ASSERT_THAT( + topSources(collector.sourceEntries()), + UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external2.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external3.h"))); } TEST_F(BuildDependencyCollector, TopIncludeInIfMacro) @@ -273,7 +304,7 @@ TEST_F(BuildDependencyCollector, TopIncludeInIfMacro) emptyCollector.collect(); - ASSERT_THAT(topIncludes(emptyCollector.includeIds()), + ASSERT_THAT(topSources(emptyCollector.sourceEntries()), ElementsAre(id(TESTDATA_DIR "/builddependencycollector/project/true.h"))); } @@ -283,10 +314,11 @@ TEST_F(BuildDependencyCollector, TopIncludeWithLocalPath) emptyCollector.collect(); - ASSERT_THAT(topIncludes(emptyCollector.includeIds()), - UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external2.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external3.h"))); + ASSERT_THAT( + topSources(emptyCollector.sourceEntries()), + UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external2.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external3.h"))); } TEST_F(BuildDependencyCollector, TopIncludesIgnoreMissingFile) @@ -296,8 +328,9 @@ TEST_F(BuildDependencyCollector, TopIncludesIgnoreMissingFile) emptyCollector.collect(); - ASSERT_THAT(topIncludes(emptyCollector.includeIds()), - UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"))); + ASSERT_THAT(topSources(emptyCollector.sourceEntries()), + UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/external/external1.h"))); } TEST_F(BuildDependencyCollector, SourceFiles) @@ -620,10 +653,37 @@ TEST_F(BuildDependencyCollector, MissingInclude) emptyCollector.collect(); - ASSERT_THAT(emptyCollector.includeIds(), - ElementsAre( - HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), - SourceType::UserInclude))); + ASSERT_THAT( + emptyCollector.sourceEntries(), + UnorderedElementsAre( + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/main5.cpp"), + SourceType::Source, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/missinginclude2.h"), + SourceType::ProjectInclude, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR + "/builddependencycollector/project/indirect_missinginclude.h"), + SourceType::ProjectInclude, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR + "/builddependencycollector/project/indirect_missinginclude3.h"), + SourceType::ProjectInclude, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR + "/builddependencycollector/project/indirect_missinginclude4.h"), + SourceType::ProjectInclude, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/missinginclude3.h"), + SourceType::ProjectInclude, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR + "/builddependencycollector/project/indirect_missinginclude2.h"), + SourceType::ProjectInclude, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), + SourceType::UserInclude, + HasMissingIncludes::No))); } @@ -643,10 +703,12 @@ TEST_F(BuildDependencyCollector, GeneratedFile) emptyCollector.collect(); - ASSERT_THAT(emptyCollector.includeIds(), - ElementsAre( - HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/generated_file.h"), - SourceType::UserInclude))); + ASSERT_THAT( + emptyCollector.sourceEntries(), + ElementsAre(HasSource(id(TESTDATA_DIR "/builddependencycollector/project/main6.cpp"), + SourceType::Source), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/generated_file.h"), + SourceType::UserInclude))); } TEST_F(BuildDependencyCollector, CreateFakeFileContent) @@ -715,41 +777,43 @@ TEST_F(BuildDependencyCollector, Create) fileStatus(TESTDATA_DIR "/builddependencycollector/project/missingfile.h"), fileStatus(TESTDATA_DIR "/builddependencycollector/project/macros.h"), ClangBackEnd::FileStatus( - id(TESTDATA_DIR "/builddependencycollector/project/generated_file.h"), - 12, - 0, - false))), - Field(&BuildDependency::includes, - UnorderedElementsAre( - HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), - SourceType::UserInclude), - HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), - SourceType::UserInclude), - HasInclude(id(TESTDATA_DIR "/builddependencycollector/external/external3.h"), - SourceType::TopProjectInclude), - HasInclude(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - SourceType::TopProjectInclude), - HasInclude(id(TESTDATA_DIR - "/builddependencycollector/external/indirect_external.h"), - SourceType::ProjectInclude), - HasInclude(id(TESTDATA_DIR - "/builddependencycollector/external/indirect_external2.h"), - SourceType::ProjectInclude), - HasInclude(id(TESTDATA_DIR "/builddependencycollector/external/external2.h"), - SourceType::TopProjectInclude), - HasInclude(id(TESTDATA_DIR "/builddependencycollector/system/system1.h"), - SourceType::TopSystemInclude), - HasInclude(id(TESTDATA_DIR - "/builddependencycollector/system/indirect_system.h"), - SourceType::SystemInclude), - HasInclude(id(TESTDATA_DIR - "/builddependencycollector/system/indirect_system2.h"), - SourceType::SystemInclude), - HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/macros.h"), - SourceType::UserInclude), - HasInclude(id(TESTDATA_DIR - "/builddependencycollector/project/generated_file.h"), - SourceType::TopProjectInclude))), + id(TESTDATA_DIR "/builddependencycollector/project/generated_file.h"), 12, 0))), + Field( + &BuildDependency::sources, + UnorderedElementsAre( + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/main4.cpp"), + SourceType::Source, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/missingfile.h"), + SourceType::UserInclude, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), + SourceType::UserInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), + SourceType::UserInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/external/external3.h"), + SourceType::TopProjectInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), + SourceType::TopProjectInclude), + HasSource(id(TESTDATA_DIR + "/builddependencycollector/external/indirect_external.h"), + SourceType::ProjectInclude), + HasSource(id(TESTDATA_DIR + "/builddependencycollector/external/indirect_external2.h"), + SourceType::ProjectInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/external/external2.h"), + SourceType::TopProjectInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/system/system1.h"), + SourceType::TopSystemInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/system/indirect_system.h"), + SourceType::SystemInclude), + HasSource(id(TESTDATA_DIR + "/builddependencycollector/system/indirect_system2.h"), + SourceType::SystemInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/macros.h"), + SourceType::UserInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/generated_file.h"), + SourceType::UserInclude))), Field(&BuildDependency::usedMacros, UnorderedElementsAre( UsedMacro{"IFDEF", id(TESTDATA_DIR "/builddependencycollector/project/macros.h")}, @@ -843,6 +907,6 @@ TEST_F(BuildDependencyCollector, Clear) auto buildDependency = collector.create(projectPart); - ASSERT_THAT(buildDependency.includes, IsEmpty()); + ASSERT_THAT(buildDependency.sources, IsEmpty()); } } // namespace diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp index 115ecaf763..ad2c8bf3e3 100644 --- a/tests/unit/unittest/clangformat-test.cpp +++ b/tests/unit/unittest/clangformat-test.cpp @@ -32,9 +32,8 @@ namespace TextEditor { class TabSettings -{ -}; -} +{}; +} // namespace TextEditor namespace { @@ -58,10 +57,7 @@ public: : ClangFormatIndenter(doc) {} - bool formatWhileTyping() const override - { - return true; - } + bool formatWhileTyping() const override { return true; } }; class ClangFormat : public ::testing::Test @@ -76,6 +72,7 @@ protected: void insertLines(const std::vector<QString> &lines) { + doc.clear(); cursor.setPosition(0); for (size_t lineNumber = 1; lineNumber <= lines.size(); ++lineNumber) { if (lineNumber > 1) @@ -104,6 +101,7 @@ protected: QTextCursor cursor{&doc}; }; +// clang-format off TEST_F(ClangFormat, IndentBasicFile) { insertLines({"int main()", @@ -121,14 +119,14 @@ TEST_F(ClangFormat, IndentBasicFile) TEST_F(ClangFormat, IndentEmptyLine) { - insertLines({"int main", + insertLines({"int main()", "{", "", "}"}); indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - ASSERT_THAT(documentLines(), ElementsAre("int main", + ASSERT_THAT(documentLines(), ElementsAre("int main()", "{", " ", "}")); @@ -365,7 +363,148 @@ TEST_F(ClangFormat, IndentEmptyLineAndKeepPreviousEmptyLines) "}")); } -TEST_F(ClangFormat, IndentFunctionBodyAndFormatBeforeIt) +TEST_F(ClangFormat, IndentOnElectricCharacterButNotRemoveEmptyLinesBefore) +{ + insertLines({"{", + " ", + " ", + "if ()", + "}"}); + + indenter.indentBlock(doc.findBlockByNumber(3), '(', TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("{", + " ", + " ", + " if ()", + "}")); +} + +TEST_F(ClangFormat, IndentAfterExtraSpaceInpreviousLine) +{ + insertLines({"if (a ", + "&& b)"}); + + indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (a", + " && b)")); +} + +TEST_F(ClangFormat, IndentEmptyLineInsideParantheses) +{ + insertLines({"if (a ", + "", + " && b)"}); + + indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (a", + " ", + " && b)")); +} + +TEST_F(ClangFormat, EmptyLineInInitializerList) +{ + insertLines({"Bar foo{a,", + "", + "};"}); + + indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("Bar foo{a,", + " ", + "};")); +} + +TEST_F(ClangFormat, IndentClosingBraceAfterComma) +{ + insertLines({"Bar foo{a,", + "}"}); + + indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("Bar foo{a,", + " }")); +} + +TEST_F(ClangFormat, DoNotIndentClosingBraceAfterSemicolon) +{ + insertLines({"{", + " a;" + "}"}); + + indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("{", + " a;" + "}")); +} + +TEST_F(ClangFormat, SameIndentAfterSecondNewLineAfterIf) +{ + insertLines({"if (a)", + " ", + ""}); + + indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (a)", + " ", + " ")); +} + +TEST_F(ClangFormat, IndentAfterNewLineInsideIfWithFunctionCall) +{ + insertLines({"if (foo()", + ")"}); + + indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (foo()", + " )")); +} + +TEST_F(ClangFormat, SameIndentAfterSecondNewLineInsideIfWithFunctionCall) +{ + insertLines({"if (foo()", + " ", + ")"}); + + indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (foo()", + " ", + " )")); +} + +TEST_F(ClangFormat, SameIndentAfterSecondNonEmptyNewLineInsideIfWithFunctionCall) +{ + insertLines({"if (foo()", + " ", + "bar)"}); + + indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (foo()", + " ", + " bar)")); +} + +TEST_F(ClangFormat, SameIndentsOnNewLinesAfterComments) +{ + insertLines({"namespace {} //comment", + "", + ""}); + + indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("namespace {} //comment", + "", + "")); +} + +TEST_F(ClangFormat, IndentFunctionBodyButNotFormatBeforeIt) { insertLines({"int foo(int a, int b,", " int c, int d", @@ -375,8 +514,9 @@ TEST_F(ClangFormat, IndentFunctionBodyAndFormatBeforeIt) extendedIndenter.indentBlock(doc.findBlockByNumber(3), QChar::Null, TextEditor::TabSettings()); - ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b, int c, int d)", - "{", + ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b,", + " int c, int d", + " ) {", " ", "}")); } @@ -404,13 +544,11 @@ TEST_F(ClangFormat, ReformatToEmptyFunction) insertLines({"int foo(int a, int b, int c, int d)", "{", " ", - "}", - ""}); + "}"}); - extendedIndenter.indentBlock(doc.findBlockByNumber(4), QChar::Null, TextEditor::TabSettings()); + extendedIndenter.indentBlock(doc.findBlockByNumber(3), '}', TextEditor::TabSettings()); - ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b, int c, int d) {}", - "")); + ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b, int c, int d) {}")); } TEST_F(ClangFormat, ReformatToNonEmptyFunction) @@ -421,13 +559,12 @@ TEST_F(ClangFormat, ReformatToNonEmptyFunction) extendedIndenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); - ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b)", - "{", + ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b) {", " ", "}")); } -TEST_F(ClangFormat, IndentIfBodyAndFormatBeforeIt) +TEST_F(ClangFormat, IndentClosingScopeAndFormatBeforeIt) { insertLines({"if(a && b", " &&c && d", @@ -435,10 +572,9 @@ TEST_F(ClangFormat, IndentIfBodyAndFormatBeforeIt) "", "}"}); - extendedIndenter.indentBlock(doc.findBlockByNumber(3), QChar::Null, TextEditor::TabSettings()); + extendedIndenter.indentBlock(doc.findBlockByNumber(4), '}', TextEditor::TabSettings()); ASSERT_THAT(documentLines(), ElementsAre("if (a && b && c && d) {", - " ", "}")); } @@ -496,7 +632,7 @@ TEST_F(ClangFormat, IndentAndFormatCompleteStatementOnClosingScope) "}")); } -TEST_F(ClangFormat, IndentAndFormatWithEmptyLines) +TEST_F(ClangFormat, OnlyIndentClosingParenthesis) { insertLines({"foo(a,", " ", @@ -505,7 +641,25 @@ TEST_F(ClangFormat, IndentAndFormatWithEmptyLines) extendedIndenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); ASSERT_THAT(documentLines(), ElementsAre("foo(a,", - "", + " ", + " )")); +} + +TEST_F(ClangFormat, EquallyIndentInsideParenthesis) +{ + insertLines({"if (a", + ")"}); + extendedIndenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + auto linesAfterFirstLineBreak = documentLines(); + insertLines({"if (a", + " ", + ")"}); + extendedIndenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(linesAfterFirstLineBreak, ElementsAre("if (a", + " )")); + ASSERT_THAT(documentLines(), ElementsAre("if (a", + " ", " )")); } @@ -623,4 +777,22 @@ TEST_F(ClangFormat, FormatTemplateparameters) ASSERT_THAT(documentLines(), ElementsAre("using Alias = Template<A, B, C>")); } +TEST_F(ClangFormat, SortIncludes) +{ + insertLines({"#include \"b.h\"", + "#include \"a.h\"", + "", + "#include <bb.h>", + "#include <aa.h>"}); + + indenter.format({{1, 5}}); + + ASSERT_THAT(documentLines(), ElementsAre("#include \"a.h\"", + "#include \"b.h\"", + "", + "#include <aa.h>", + "#include <bb.h>")); } +// clang-format on + +} // namespace diff --git a/tests/unit/unittest/commandlinebuilder-test.cpp b/tests/unit/unittest/commandlinebuilder-test.cpp index a75c8d8a35..328b832b9c 100644 --- a/tests/unit/unittest/commandlinebuilder-test.cpp +++ b/tests/unit/unittest/commandlinebuilder-test.cpp @@ -139,6 +139,7 @@ TYPED_TEST(CommandLineBuilder, CHeader) ASSERT_THAT(builder.commandLine, ElementsAre("clang", + "-w", "-DNOMINMAX", "-x", "c-header", @@ -156,6 +157,7 @@ TYPED_TEST(CommandLineBuilder, CSource) ASSERT_THAT(builder.commandLine, ElementsAre("clang", + "-w", "-DNOMINMAX", "-x", "c", @@ -174,6 +176,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCHeader) ASSERT_THAT(builder.commandLine, ElementsAre("clang", + "-w", "-DNOMINMAX", "-x", "objective-c-header", @@ -192,6 +195,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCSource) ASSERT_THAT(builder.commandLine, ElementsAre("clang", + "-w", "-DNOMINMAX", "-x", "objective-c", @@ -209,6 +213,7 @@ TYPED_TEST(CommandLineBuilder, CppHeader) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -227,6 +232,7 @@ TYPED_TEST(CommandLineBuilder, CppSource) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++", @@ -246,6 +252,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCppHeader) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "objective-c++-header", @@ -265,6 +272,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCppSource) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "objective-c++", @@ -498,6 +506,7 @@ TYPED_TEST(CommandLineBuilder, IncludesOrder) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -525,6 +534,7 @@ TYPED_TEST(CommandLineBuilder, EmptySourceFile) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -539,6 +549,7 @@ TYPED_TEST(CommandLineBuilder, SourceFile) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -555,6 +566,7 @@ TYPED_TEST(CommandLineBuilder, EmptyOutputFile) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -574,6 +586,7 @@ TYPED_TEST(CommandLineBuilder, OutputFile) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -596,6 +609,7 @@ TYPED_TEST(CommandLineBuilder, IncludePchPath) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -619,6 +633,7 @@ TYPED_TEST(CommandLineBuilder, CompilerMacros) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", diff --git a/tests/unit/unittest/data/highlightingmarks.cpp b/tests/unit/unittest/data/highlightingmarks.cpp index e1a48903ca..a703e89a11 100644 --- a/tests/unit/unittest/data/highlightingmarks.cpp +++ b/tests/unit/unittest/data/highlightingmarks.cpp @@ -686,3 +686,12 @@ class NonConstParameterConstructor NonConstParameterConstructor bar(foo); } }; + +class StaticMembersAccess +{ +protected: + static int protectedValue; + +private: + static int privateValue; +}; diff --git a/tests/unit/unittest/filepathstorage-test.cpp b/tests/unit/unittest/filepathstorage-test.cpp index be689b44f3..c08c84e913 100644 --- a/tests/unit/unittest/filepathstorage-test.cpp +++ b/tests/unit/unittest/filepathstorage-test.cpp @@ -189,7 +189,8 @@ TEST_F(FilePathStorage, CallWriteForWriteDirectory) TEST_F(FilePathStorage, CallWriteForWriteSource) { - EXPECT_CALL(insertIntoSources, write(5, TypedEq<Utils::SmallStringView>("unknownfile.h"))); + EXPECT_CALL(insertIntoSources, + write(TypedEq<int>(5), TypedEq<Utils::SmallStringView>("unknownfile.h"))); storage.writeSourceId(5, "unknownfile.h"); } @@ -280,7 +281,8 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingSourceIdForUnknownEntry) EXPECT_CALL(mockDatabase, deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("unknownfile.h"))); - EXPECT_CALL(insertIntoSources, write(5, TypedEq<Utils::SmallStringView>("unknownfile.h"))); + EXPECT_CALL(insertIntoSources, + write(TypedEq<int>(5), TypedEq<Utils::SmallStringView>("unknownfile.h"))); EXPECT_CALL(mockDatabase, commit()); storage.fetchSourceId(5, "unknownfile.h"); @@ -347,7 +349,8 @@ TEST_F(FilePathStorage, RestartFetchSourceIdIfTheDatabaseIsBusyInBeginBecauseThe EXPECT_CALL(mockDatabase, deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("otherunknownfile.h"))); - EXPECT_CALL(insertIntoSources, write(5, TypedEq<Utils::SmallStringView>("otherunknownfile.h"))); + EXPECT_CALL(insertIntoSources, + write(TypedEq<int>(5), TypedEq<Utils::SmallStringView>("otherunknownfile.h"))); EXPECT_CALL(mockDatabase, commit()); storage.fetchSourceId(5, "otherunknownfile.h"); @@ -360,13 +363,16 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingSourceTwoTimesIfTheDatabase EXPECT_CALL(mockDatabase, deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("otherunknownfile.h"))); - EXPECT_CALL(insertIntoSources, write(5, TypedEq<Utils::SmallStringView>("otherunknownfile.h"))) - .WillOnce(Throw(Sqlite::StatementIsBusy("busy")));; + EXPECT_CALL(insertIntoSources, + write(TypedEq<int>(5), TypedEq<Utils::SmallStringView>("otherunknownfile.h"))) + .WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + ; EXPECT_CALL(mockDatabase, rollback()); EXPECT_CALL(mockDatabase, deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("otherunknownfile.h"))); - EXPECT_CALL(insertIntoSources, write(5, TypedEq<Utils::SmallStringView>("otherunknownfile.h"))); + EXPECT_CALL(insertIntoSources, + write(TypedEq<int>(5), TypedEq<Utils::SmallStringView>("otherunknownfile.h"))); EXPECT_CALL(mockDatabase, commit()); storage.fetchSourceId(5, "otherunknownfile.h"); @@ -379,12 +385,14 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingSourceTwoTimesIfTheIndexIsC EXPECT_CALL(mockDatabase,deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("otherunknownfile.h"))); - EXPECT_CALL(insertIntoSources, write(5, TypedEq<Utils::SmallStringView>("otherunknownfile.h"))) - .WillOnce(Throw(Sqlite::ConstraintPreventsModification("busy")));; + EXPECT_CALL(insertIntoSources, + write(TypedEq<int>(5), TypedEq<Utils::SmallStringView>("otherunknownfile.h"))) + .WillOnce(Throw(Sqlite::ConstraintPreventsModification("busy"))); EXPECT_CALL(mockDatabase, rollback()); EXPECT_CALL(mockDatabase,deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, - valueReturnInt32(5, Eq("otherunknownfile.h"))); + valueReturnInt32(5, Eq("otherunknownfile.h"))) + .WillOnce(Return(Utils::optional<int>(42))); EXPECT_CALL(mockDatabase, commit()); storage.fetchSourceId(5, "otherunknownfile.h"); diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 8427e79af8..2befb52417 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -45,7 +45,6 @@ #include <fulltokeninfo.h> #include <includesearchpath.h> #include <nativefilepath.h> -#include <pchcreatorincludes.h> #include <pchtask.h> #include <precompiledheadersupdatedmessage.h> #include <projectpartartefact.h> @@ -1138,6 +1137,7 @@ const char* progressTypeToString(ClangBackEnd::ProgressType type) case ProgressType::Invalid: return "Invalid"; case ProgressType::PrecompiledHeader: return "PrecompiledHeader"; case ProgressType::Indexing: return "Indexing"; + case ProgressType::DependencyCreation: return "DependencyCreation"; } return nullptr; @@ -1150,11 +1150,6 @@ std::ostream &operator<<(std::ostream &out, const ProgressMessage &message) << message.total << ")"; } -std::ostream &operator<<(std::ostream &out, const PchCreatorIncludes &includes) -{ - return out << "(" << includes.includeIds << ", " << includes.topIncludeIds << ", " - << includes.topSystemIncludeIds << ")"; -} std::ostream &operator<<(std::ostream &out, const PchTask &task) { return out << "(" << task.projectPartIds << ", " << task.includes << ", " << task.compilerMacros @@ -1171,11 +1166,11 @@ std::ostream &operator<<(std::ostream &out, const PchTaskSet &taskSet) std::ostream &operator<<(std::ostream &out, const BuildDependency &dependency) { return out << "(\n" - << "includes: " << dependency.includes << ",\n" - << "usedMacros: " << dependency.usedMacros << ",\n" - << "fileStatuses: " << dependency.fileStatuses << ",\n" - << "sourceFiles: " << dependency.sourceFiles << ",\n" - << "sourceDependencies: " << dependency.sourceDependencies << ",\n" + << "includes: " << dependency.sources << ",\n" + << "usedMacros: " << dependency.usedMacros << ",\n" + << "fileStatuses: " << dependency.fileStatuses << ",\n" + << "sourceFiles: " << dependency.sourceFiles << ",\n" + << "sourceDependencies: " << dependency.sourceDependencies << ",\n" << ")"; } @@ -1184,7 +1179,7 @@ std::ostream &operator<<(std::ostream &out, const SlotUsage &slotUsage) return out << "(" << slotUsage.free << ", " << slotUsage.used << ")"; } -const char *sourceTypeString(SourceType sourceType) +const char *typeToString(SourceType sourceType) { using ClangBackEnd::SymbolTag; @@ -1199,6 +1194,22 @@ const char *sourceTypeString(SourceType sourceType) return "ProjectInclude"; case SourceType::UserInclude: return "UserInclude"; + case SourceType::Source: + return "Source"; + } + + return ""; +} + +const char *typeToString(HasMissingIncludes hasMissingIncludes) +{ + using ClangBackEnd::SymbolTag; + + switch (hasMissingIncludes) { + case HasMissingIncludes::No: + return "HasMissingIncludes::No"; + case HasMissingIncludes::Yes: + return "HasMissingIncludes::Yes"; } return ""; @@ -1206,7 +1217,8 @@ const char *sourceTypeString(SourceType sourceType) std::ostream &operator<<(std::ostream &out, const SourceEntry &entry) { - return out << "(" << entry.sourceId << ", " << sourceTypeString(entry.sourceType) << ")"; + return out << "(" << entry.sourceId << ", " << typeToString(entry.sourceType) << ", " + << typeToString(entry.hasMissingIncludes) << ")"; } const char *typeToString(IncludeSearchPathType type) diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index cb63fd56bb..75eae281ae 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -186,7 +186,6 @@ class SuspendResumeJobsEntry; class ReferencesResult; class SymbolIndexerTask; class ProgressMessage; -class PchCreatorIncludes; class PchTask; class PchTaskSet; class BuildDependency; @@ -277,7 +276,6 @@ std::ostream &operator<<(std::ostream &os, const SuspendResumeJobsEntry &entry); std::ostream &operator<<(std::ostream &os, const ReferencesResult &value); std::ostream &operator<<(std::ostream &out, const SymbolIndexerTask &task); std::ostream &operator<<(std::ostream &out, const ProgressMessage &message); -std::ostream &operator<<(std::ostream &out, const PchCreatorIncludes &includes); std::ostream &operator<<(std::ostream &out, const PchTask &task); std::ostream &operator<<(std::ostream &out, const PchTaskSet &taskSet); std::ostream &operator<<(std::ostream &out, const BuildDependency &dependency); diff --git a/tests/unit/unittest/mockbuilddependenciesstorage.h b/tests/unit/unittest/mockbuilddependenciesstorage.h index a654579a83..739c13cf8d 100644 --- a/tests/unit/unittest/mockbuilddependenciesstorage.h +++ b/tests/unit/unittest/mockbuilddependenciesstorage.h @@ -32,19 +32,22 @@ class MockBuildDependenciesStorage : public ClangBackEnd::BuildDependenciesStorageInterface { public: - MOCK_METHOD1(updateSources, - void (const ClangBackEnd::SourceEntries &sources)); + MOCK_METHOD2(insertOrUpdateSources, + void(const ClangBackEnd::SourceEntries &sources, int projectPartId)); MOCK_METHOD1(insertOrUpdateUsedMacros, void (const ClangBackEnd::UsedMacros &usedMacros)); - MOCK_METHOD1(insertFileStatuses, - void (const ClangBackEnd::FileStatuses &fileStatuses)); + MOCK_METHOD1(insertOrUpdateFileStatuses, void(const ClangBackEnd::FileStatuses &fileStatuses)); MOCK_METHOD1(insertOrUpdateSourceDependencies, void (const ClangBackEnd::SourceDependencies &sourceDependencies)); MOCK_CONST_METHOD1(fetchLowestLastModifiedTime, long long (ClangBackEnd::FilePathId sourceId)); MOCK_CONST_METHOD2(fetchDependSources, - ClangBackEnd::SourceEntries (ClangBackEnd::FilePathId sourceId, Utils::SmallStringView)); + ClangBackEnd::SourceEntries(ClangBackEnd::FilePathId sourceId, + int projectPartId)); MOCK_CONST_METHOD1(fetchUsedMacros, ClangBackEnd::UsedMacros (ClangBackEnd::FilePathId sourceId)); + MOCK_METHOD1(fetchProjectPartId, int(Utils::SmallStringView projectPartName)); + MOCK_METHOD2(updatePchCreationTimeStamp, + void(long long pchCreationTimeStamp, Utils::SmallStringView projectPartName)); }; diff --git a/tests/unit/unittest/mockprojectparts.h b/tests/unit/unittest/mockprojectparts.h index 7c7a2daf4a..15ec023846 100644 --- a/tests/unit/unittest/mockprojectparts.h +++ b/tests/unit/unittest/mockprojectparts.h @@ -27,9 +27,9 @@ #include "googletest.h" -#include <projectpartsinterface.h> +#include <projectpartsmanagerinterface.h> -class MockProjectParts : public ClangBackEnd::ProjectPartsInterface +class MockProjectPartsManager : public ClangBackEnd::ProjectPartsManagerInterface { public: MOCK_METHOD1(update, diff --git a/tests/unit/unittest/mocksqlitedatabase.h b/tests/unit/unittest/mocksqlitedatabase.h index 0b890e01f0..5bef2ba8c5 100644 --- a/tests/unit/unittest/mocksqlitedatabase.h +++ b/tests/unit/unittest/mocksqlitedatabase.h @@ -39,8 +39,8 @@ class MockSqliteDatabase : public MockSqliteTransactionBackend { public: - using ReadStatement = MockSqliteReadStatement; - using WriteStatement = MockSqliteWriteStatement; + using ReadStatement = NiceMock<MockSqliteReadStatement>; + using WriteStatement = NiceMock<MockSqliteWriteStatement>; MOCK_METHOD1(execute, void (Utils::SmallStringView sqlStatement)); diff --git a/tests/unit/unittest/mocksqlitereadstatement.cpp b/tests/unit/unittest/mocksqlitereadstatement.cpp index b9cecd4d1a..04d2a07c14 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.cpp +++ b/tests/unit/unittest/mocksqlitereadstatement.cpp @@ -186,9 +186,10 @@ MockSqliteReadStatement::value<SourceLocation, 3>(const long long &symbolId, con return valueReturnSourceLocation(symbolId, locationKind); } -template <> -SourceEntries -MockSqliteReadStatement::values<SourceEntry, 3>(std::size_t reserveSize, const int &filePathId, const int &projectPartId) +template<> +SourceEntries MockSqliteReadStatement::values<SourceEntry, 4>(std::size_t reserveSize, + const int &filePathId, + const int &projectPartId) { return valuesReturnSourceEntries(reserveSize, filePathId, projectPartId); } diff --git a/tests/unit/unittest/mocksqlitereadstatement.h b/tests/unit/unittest/mocksqlitereadstatement.h index 43c88eb044..5c6fbdef77 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.h +++ b/tests/unit/unittest/mocksqlitereadstatement.h @@ -255,9 +255,10 @@ template <> Utils::optional<SourceLocation> MockSqliteReadStatement::value<SourceLocation, 3>(const long long &symbolId, const int &locationKind); -template <> -SourceEntries -MockSqliteReadStatement::values<SourceEntry, 3>(std::size_t reserveSize, const int&, const int&); +template<> +SourceEntries MockSqliteReadStatement::values<SourceEntry, 4>(std::size_t reserveSize, + const int &, + const int &); template <> Utils::optional<Sources::SourceNameAndDirectoryId> diff --git a/tests/unit/unittest/mocksqlitewritestatement.h b/tests/unit/unittest/mocksqlitewritestatement.h index ee7df6362f..4b369845aa 100644 --- a/tests/unit/unittest/mocksqlitewritestatement.h +++ b/tests/unit/unittest/mocksqlitewritestatement.h @@ -42,8 +42,7 @@ public: MOCK_METHOD0(execute, void ()); - MOCK_METHOD2(bind, - void (int index, Utils::SmallStringView value)); + MOCK_METHOD2(bind, void(int, Utils::SmallStringView)); MOCK_METHOD2(bindValues, void (Utils::SmallStringView, Utils::SmallStringView)); @@ -60,11 +59,11 @@ public: MOCK_METHOD5(write, void (long long, int, int, int, int)); - MOCK_METHOD2(write, - void (uint, Utils::SmallStringView)); + MOCK_METHOD2(write, void(uint, Utils::SmallStringView)); - MOCK_METHOD2(write, - void (Utils::SmallStringView, Utils::SmallStringView)); + MOCK_METHOD2(write, void(int, Utils::SmallStringView)); + + MOCK_METHOD2(write, void(Utils::SmallStringView, Utils::SmallStringView)); MOCK_METHOD3(write, void (Utils::SmallStringView, Utils::SmallStringView, long long)); @@ -103,17 +102,16 @@ public: MOCK_METHOD3(write, void (uint, uint, uint)); - MOCK_METHOD4(write, - void (int, off_t, time_t, bool)); + MOCK_METHOD3(write, void(int, off_t, time_t)); MOCK_METHOD2(write, void (uint, uint)); MOCK_METHOD2(write, void (uchar, int)); - + MOCK_METHOD4(write, void(int, int, uchar, uchar)); MOCK_METHOD2(write, void (long long, int)); - + MOCK_METHOD2(write, void(long long, Utils::SmallStringView)); Utils::SmallString sqlStatement; }; diff --git a/tests/unit/unittest/mocksymbolstorage.h b/tests/unit/unittest/mocksymbolstorage.h index 325e18b1c9..c4b55fcfe4 100644 --- a/tests/unit/unittest/mocksymbolstorage.h +++ b/tests/unit/unittest/mocksymbolstorage.h @@ -46,9 +46,6 @@ public: Utils::Language language, Utils::LanguageVersion languageVersion, Utils::LanguageExtension languageExtension)); - MOCK_METHOD2(updateProjectPartSources, - void(int projectPartId, - const ClangBackEnd::FilePathIds &sourceFilePathIds)); MOCK_CONST_METHOD1(fetchProjectPartArtefact, Utils::optional<ClangBackEnd::ProjectPartArtefact> (ClangBackEnd::FilePathId sourceId)); MOCK_CONST_METHOD1(fetchProjectPartArtefact, diff --git a/tests/unit/unittest/pchcreator-test.cpp b/tests/unit/unittest/pchcreator-test.cpp index d891a08987..3dbafc8aa0 100644 --- a/tests/unit/unittest/pchcreator-test.cpp +++ b/tests/unit/unittest/pchcreator-test.cpp @@ -28,6 +28,7 @@ #include "fakeprocess.h" #include "filesystem-utilities.h" +#include "mockbuilddependenciesstorage.h" #include "mockclangpathwatcher.h" #include "mockpchmanagerclient.h" #include "testenvironment.h" @@ -97,16 +98,22 @@ protected: FileContainer generatedFile{generatedFilePath.clone(), "#pragma once", {}}; NiceMock<MockPchManagerClient> mockPchManagerClient; NiceMock<MockClangPathWatcher> mockClangPathWatcher; - ClangBackEnd::PchCreator creator{environment, database, mockPchManagerClient, mockClangPathWatcher}; + NiceMock<MockBuildDependenciesStorage> mockBuildDependenciesStorage; + ClangBackEnd::PchCreator creator{environment, + database, + mockPchManagerClient, + mockClangPathWatcher, + mockBuildDependenciesStorage}; PchTask pchTask1{ "project1", {id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), id(TESTDATA_DIR "/builddependencycollector/external/external2.h")}, - {id(generatedFilePath), - id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), + {id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external2.h")}, + id(TESTDATA_DIR "/builddependencycollector/external/external2.h"), + id(generatedFilePath), + id(main2Path)}, {}, {}, {}, @@ -134,6 +141,7 @@ TEST_F(PchCreator, CreateProjectPartClangCompilerArguments) ASSERT_THAT(arguments, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -158,6 +166,7 @@ TEST_F(PchCreator, CreateProjectPartClangCompilerArgumentsWithSystemPch) ASSERT_THAT(arguments, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -190,25 +199,24 @@ TEST_F(PchCreatorVerySlowTest, ProjectPartPchsSendToPchManagerClient) creator.doInMainThreadAfterFinished(); } -TEST_F(PchCreatorVerySlowTest, AllIncludesAreWatchedAfterSucess) +TEST_F(PchCreatorVerySlowTest, SourcesAreWatchedAfterSucess) { creator.generatePch(std::move(pchTask1)); - EXPECT_CALL( - mockClangPathWatcher, - updateIdPaths(ElementsAre( - AllOf(Field(&ClangBackEnd::IdPaths::id, "project1"), - Field(&ClangBackEnd::IdPaths::filePathIds, - UnorderedElementsAre( - id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external2.h"))))))); + EXPECT_CALL(mockClangPathWatcher, + updateIdPaths(ElementsAre(AllOf( + Field(&ClangBackEnd::IdPaths::id, "project1"), + Field(&ClangBackEnd::IdPaths::filePathIds, + UnorderedElementsAre( + 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/main2.cpp"))))))); creator.doInMainThreadAfterFinished(); } - -TEST_F(PchCreatorVerySlowTest, AllIncludesAreNotWatchedAfterFail) +TEST_F(PchCreatorVerySlowTest, SourcesAreNotWatchedAfterFail) { pchTask1.systemIncludeSearchPaths = {}; pchTask1.projectIncludeSearchPaths = {}; @@ -222,6 +230,15 @@ TEST_F(PchCreatorVerySlowTest, AllIncludesAreNotWatchedAfterFail) creator.doInMainThreadAfterFinished(); } +TEST_F(PchCreatorVerySlowTest, PchCreationTimeStampsAreUpdated) +{ + creator.generatePch(std::move(pchTask1)); + + EXPECT_CALL(mockBuildDependenciesStorage, updatePchCreationTimeStamp(_, Eq("project1"))); + + creator.doInMainThreadAfterFinished(); +} + TEST_F(PchCreatorVerySlowTest, ProjectPartPchForCreatesPchForPchTask) { creator.generatePch(std::move(pchTask1)); @@ -241,6 +258,15 @@ TEST_F(PchCreatorVerySlowTest, ProjectPartPchCleared) ASSERT_THAT(creator.projectPartPch(), ClangBackEnd::ProjectPartPch{}); } +TEST_F(PchCreatorVerySlowTest, SourcesCleared) +{ + creator.generatePch(std::move(pchTask1)); + + creator.clear(); + + ASSERT_THAT(creator.sources(), IsEmpty()); +} + TEST_F(PchCreatorVerySlowTest, ClangToolCleared) { creator.generatePch(std::move(pchTask1)); @@ -266,7 +292,7 @@ TEST_F(PchCreatorVerySlowTest, FaultyProjectPartPchForCreatesFaultyPchForPchTask ASSERT_THAT(creator.projectPartPch(), AllOf(Field(&ProjectPartPch::projectPartId, Eq("faultyProjectPart")), Field(&ProjectPartPch::pchPath, IsEmpty()), - Field(&ProjectPartPch::lastModified, Eq(-1)))); + Field(&ProjectPartPch::lastModified, Gt(0)))); } TEST_F(PchCreatorVerySlowTest, GeneratedFile) diff --git a/tests/unit/unittest/pchmanagerserver-test.cpp b/tests/unit/unittest/pchmanagerserver-test.cpp index 5a2ca172c0..370667edc8 100644 --- a/tests/unit/unittest/pchmanagerserver-test.cpp +++ b/tests/unit/unittest/pchmanagerserver-test.cpp @@ -55,7 +55,7 @@ class PchManagerServer : public ::testing::Test { server.setClient(&mockPchManagerClient); - ON_CALL(mockProjectParts, update(projectParts)).WillByDefault(Return(projectParts)); + ON_CALL(mockProjectPartsManager, update(projectParts)).WillByDefault(Return(projectParts)); ON_CALL(mockGeneratedFiles, isValid()).WillByDefault(Return(true)); } @@ -67,13 +67,15 @@ class PchManagerServer : public ::testing::Test protected: NiceMock<MockPchTaskGenerator> mockPchTaskGenerator; NiceMock<MockClangPathWatcher> mockClangPathWatcher; - NiceMock<MockProjectParts> mockProjectParts; + NiceMock<MockProjectPartsManager> mockProjectPartsManager; NiceMock<MockGeneratedFiles> mockGeneratedFiles; Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> initializer{database}; ClangBackEnd::FilePathCaching filePathCache{database}; - ClangBackEnd::PchManagerServer server{ - mockClangPathWatcher, mockPchTaskGenerator, mockProjectParts, mockGeneratedFiles}; + ClangBackEnd::PchManagerServer server{mockClangPathWatcher, + mockPchTaskGenerator, + mockProjectPartsManager, + mockGeneratedFiles}; NiceMock<MockPchManagerClient> mockPchManagerClient; SmallString projectPartId1 = "project1"; SmallString projectPartId2 = "project2"; @@ -117,7 +119,7 @@ TEST_F(PchManagerServer, FilterProjectPartsAndSendThemToQueue) { InSequence s; - EXPECT_CALL(mockProjectParts, update(updateProjectPartsMessage.projectsParts)) + EXPECT_CALL(mockProjectPartsManager, update(updateProjectPartsMessage.projectsParts)) .WillOnce(Return(projectParts2)); EXPECT_CALL( mockPchTaskGenerator, addProjectParts(Eq(projectParts2), ElementsAre("toolChainArgument"))); @@ -152,7 +154,7 @@ TEST_F(PchManagerServer, RemoveIncludesFromFileWatcher) TEST_F(PchManagerServer, RemoveProjectPartsFromProjectParts) { - EXPECT_CALL(mockProjectParts, remove(removeProjectPartsMessage.projectsPartIds)); + EXPECT_CALL(mockProjectPartsManager, remove(removeProjectPartsMessage.projectsPartIds)); server.removeProjectParts(removeProjectPartsMessage.clone()); } @@ -161,7 +163,10 @@ TEST_F(PchManagerServer, SetPathWatcherNotifier) { EXPECT_CALL(mockClangPathWatcher, setNotifier(_)); - ClangBackEnd::PchManagerServer server{mockClangPathWatcher, mockPchTaskGenerator, mockProjectParts, mockGeneratedFiles}; + ClangBackEnd::PchManagerServer server{mockClangPathWatcher, + mockPchTaskGenerator, + mockProjectPartsManager, + mockGeneratedFiles}; } TEST_F(PchManagerServer, UpdateProjectPartQueueByPathIds) @@ -169,8 +174,8 @@ TEST_F(PchManagerServer, UpdateProjectPartQueueByPathIds) server.updateProjectParts( ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}}); - EXPECT_CALL(mockProjectParts, projects(ElementsAre(projectPart1.projectPartId))) - .WillOnce(Return(std::vector<ClangBackEnd::ProjectPartContainer>{{projectPart1}})); + EXPECT_CALL(mockProjectPartsManager, projects(ElementsAre(projectPart1.projectPartId))) + .WillOnce(Return(std::vector<ClangBackEnd::ProjectPartContainer>{{projectPart1}})); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(ElementsAre(projectPart1), ElementsAre("toolChainArgument"))); server.pathsWithIdsChanged({projectPartId1}); @@ -213,11 +218,11 @@ TEST_F(PchManagerServer, DontGeneratePchIfGeneratedFilesAreNotValid) { InSequence s; - EXPECT_CALL(mockProjectParts, update(ElementsAre(projectPart1))) + EXPECT_CALL(mockProjectPartsManager, update(ElementsAre(projectPart1))) .WillOnce(Return(ProjectPartContainers{projectPart1})); EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(false)); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)).Times(0); - EXPECT_CALL(mockProjectParts, updateDeferred(ElementsAre(projectPart1))); + EXPECT_CALL(mockProjectPartsManager, updateDeferred(ElementsAre(projectPart1))); server.updateProjectParts( ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}}); @@ -227,11 +232,11 @@ TEST_F(PchManagerServer, GeneratePchIfGeneratedFilesAreValid) { InSequence s; - EXPECT_CALL(mockProjectParts, update(ElementsAre(projectPart1))) + EXPECT_CALL(mockProjectPartsManager, update(ElementsAre(projectPart1))) .WillOnce(Return(ProjectPartContainers{projectPart1})); EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(true)); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)); - EXPECT_CALL(mockProjectParts, updateDeferred(_)).Times(0); + EXPECT_CALL(mockProjectPartsManager, updateDeferred(_)).Times(0); server.updateProjectParts( ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}}); @@ -247,7 +252,7 @@ TEST_F(PchManagerServer, AfterUpdatingGeneratedFilesAreValidSoGeneratePchs) EXPECT_CALL(mockGeneratedFiles, update(updateGeneratedFilesMessage.generatedFiles)); EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(true)); - EXPECT_CALL(mockProjectParts, deferredUpdates()) + EXPECT_CALL(mockProjectPartsManager, deferredUpdates()) .WillOnce(Return(ClangBackEnd::ProjectPartContainers{projectPart1})); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(ElementsAre(projectPart1), ElementsAre("toolChainArgument"))); @@ -265,7 +270,7 @@ TEST_F(PchManagerServer, AfterUpdatingGeneratedFilesAreStillInvalidSoNoPchsGener EXPECT_CALL(mockGeneratedFiles, update(updateGeneratedFilesMessage.generatedFiles)); EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(false)); - EXPECT_CALL(mockProjectParts, deferredUpdates()).Times(0); + EXPECT_CALL(mockProjectPartsManager, deferredUpdates()).Times(0); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)).Times(0); server.updateGeneratedFiles(updateGeneratedFilesMessage.clone()); diff --git a/tests/unit/unittest/pchtaskgenerator-test.cpp b/tests/unit/unittest/pchtaskgenerator-test.cpp index d85432baf2..a6946f7ccf 100644 --- a/tests/unit/unittest/pchtaskgenerator-test.cpp +++ b/tests/unit/unittest/pchtaskgenerator-test.cpp @@ -99,7 +99,7 @@ TEST_F(PchTaskGenerator, AddProjectParts) Field(&PchTaskSet::system, AllOf(Field(&PchTask::projectPartIds, ElementsAre("ProjectPart1")), Field(&PchTask::includes, ElementsAre(5)), - Field(&PchTask::allIncludes, IsEmpty()), + Field(&PchTask::sources, IsEmpty()), Field(&PchTask::compilerMacros, ElementsAre(CompilerMacro{"SE", "4", 4}, CompilerMacro{"WU", "5", 5})), Field(&PchTask::systemIncludeSearchPaths, @@ -116,7 +116,7 @@ TEST_F(PchTaskGenerator, AddProjectParts) &PchTaskSet::project, AllOf(Field(&PchTask::projectPartIds, ElementsAre("ProjectPart1")), Field(&PchTask::includes, ElementsAre(3)), - Field(&PchTask::allIncludes, ElementsAre(1, 2, 3, 4, 5)), + Field(&PchTask::sources, ElementsAre(1, 2, 3, 4, 5)), Field(&PchTask::compilerMacros, ElementsAre(CompilerMacro{"YI", "1", 1}, CompilerMacro{"SAN", "3", 3})), Field(&PchTask::systemIncludeSearchPaths, diff --git a/tests/unit/unittest/pchtasksmerger-test.cpp b/tests/unit/unittest/pchtasksmerger-test.cpp index c279da505e..da61d14adb 100644 --- a/tests/unit/unittest/pchtasksmerger-test.cpp +++ b/tests/unit/unittest/pchtasksmerger-test.cpp @@ -272,14 +272,14 @@ TEST_F(PchTasksMerger, MergeAllIncludes) { Merger::mergePchTasks(systemTask1, systemTask2); - ASSERT_THAT(systemTask1.allIncludes, ElementsAre(1, 2, 3, 11, 12, 13)); + ASSERT_THAT(systemTask1.sources, ElementsAre(1, 2, 3, 11, 12, 13)); } TEST_F(PchTasksMerger, DontAllMergeIncludes) { Merger::mergePchTasks(systemTask1, systemTask3); - ASSERT_THAT(systemTask1.allIncludes, ElementsAre(1, 2, 3)); + ASSERT_THAT(systemTask1.sources, ElementsAre(1, 2, 3)); } TEST_F(PchTasksMerger, MergeProjectIds) diff --git a/tests/unit/unittest/projectparts-test.cpp b/tests/unit/unittest/projectparts-test.cpp index 8ab342b2f1..16f1ef0988 100644 --- a/tests/unit/unittest/projectparts-test.cpp +++ b/tests/unit/unittest/projectparts-test.cpp @@ -25,7 +25,7 @@ #include "googletest.h" -#include <projectparts.h> +#include <projectpartsmanager.h> #include <projectpartcontainer.h> @@ -41,7 +41,7 @@ using ClangBackEnd::FilePathId; class ProjectParts : public testing::Test { protected: - ClangBackEnd::ProjectParts projectParts; + ClangBackEnd::ProjectPartsManager projectParts; FilePathId firstHeader{1}; FilePathId secondHeader{2}; FilePathId firstSource{11}; diff --git a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp index 7e1e730b17..ebd67dccba 100644 --- a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp +++ b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp @@ -102,7 +102,10 @@ TEST_F(RefactoringDatabaseInitializer, AddProjectPartsSourcesTable) { InSequence s; - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, sourceId INTEGER, sourceType INTEGER)"))); + EXPECT_CALL(mockDatabase, + execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, " + "sourceId INTEGER, sourceType INTEGER, pchCreationTimeStamp INTEGER, " + "hasMissingIncludes INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsSources_sourceId_projectPartId ON projectPartsSources(sourceId, projectPartId)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsSources_projectPartId ON projectPartsSources(projectPartId)"))); @@ -124,7 +127,11 @@ TEST_F(RefactoringDatabaseInitializer, AddFileStatusesTable) { InSequence s; - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, size INTEGER, lastModified INTEGER, buildDependencyTimeStamp INTEGER, isInPrecompiledHeader INTEGER)"))); + EXPECT_CALL( + mockDatabase, + execute(Eq( + "CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, size INTEGER, " + "lastModified INTEGER)"))); initializer.createFileStatusesTable(); } @@ -171,13 +178,20 @@ TEST_F(RefactoringDatabaseInitializer, CreateInTheContructor) "TEXT, systemIncludeSearchPaths TEXT, projectIncludeSearchPaths TEXT, " "language INTEGER, languageVersion INTEGER, languageExtension INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectParts_projectPartName ON projectParts(projectPartName)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, sourceId INTEGER, sourceType INTEGER)"))); + EXPECT_CALL(mockDatabase, + execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, " + "sourceId INTEGER, sourceType INTEGER, pchCreationTimeStamp INTEGER, " + "hasMissingIncludes INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsSources_sourceId_projectPartId ON projectPartsSources(sourceId, projectPartId)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsSources_projectPartId ON projectPartsSources(projectPartId)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS usedMacros(usedMacroId INTEGER PRIMARY KEY, sourceId INTEGER, macroName TEXT)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_sourceId_macroName ON usedMacros(sourceId, macroName)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_macroName ON usedMacros(macroName)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, size INTEGER, lastModified INTEGER, buildDependencyTimeStamp INTEGER, isInPrecompiledHeader INTEGER)"))); + EXPECT_CALL( + mockDatabase, + execute(Eq( + "CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, size INTEGER, " + "lastModified INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sourceDependencies(sourceId INTEGER, dependencySourceId INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_sourceId_dependencySourceId ON sourceDependencies(sourceId, dependencySourceId)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS precompiledHeaders(projectPartId INTEGER PRIMARY KEY, projectPchPath TEXT, projectPchBuildTime INTEGER, systemPchPath TEXT, systemPchBuildTime INTEGER)"))); @@ -215,7 +229,10 @@ TEST_F(RefactoringDatabaseInitializer, DontCreateIfAlreadyInitialized) EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS usedMacros(usedMacroId INTEGER PRIMARY KEY, sourceId INTEGER, macroName TEXT)"))).Times(0); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_sourceId_macroName ON usedMacros(sourceId, macroName)"))).Times(0); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_macroName ON usedMacros(macroName)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, size INTEGER, lastModified INTEGER, isInPrecompiledHeader INTEGER)"))).Times(0); + EXPECT_CALL(mockDatabase, + execute(Eq("CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, " + "size INTEGER, lastModified INTEGER, isInPrecompiledHeader INTEGER)"))) + .Times(0); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sourceDependencies(sourceId INTEGER, dependencySourceId INTEGER)"))).Times(0); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_sourceId_dependencySourceId ON sourceDependencies(sourceId, dependencySourceId)"))).Times(0); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS precompiledHeaders(projectPartId INTEGER PRIMARY KEY, pchPath TEXT, pchBuildTime INTEGER)"))).Times(0); diff --git a/tests/unit/unittest/symbolindexer-test.cpp b/tests/unit/unittest/symbolindexer-test.cpp index eecd388f02..ea015bdee6 100644 --- a/tests/unit/unittest/symbolindexer-test.cpp +++ b/tests/unit/unittest/symbolindexer-test.cpp @@ -73,13 +73,6 @@ using ClangBackEnd::SourceLocationKind; using ClangBackEnd::UsedMacros; using OptionalProjectPartArtefact = Utils::optional<ClangBackEnd::ProjectPartArtefact>; -MATCHER_P(IsFileId, fileNameId, - std::string(negation ? "isn't " : "is ") - + PrintToString(ClangBackEnd::FilePathId(fileNameId))) -{ - return arg == ClangBackEnd::FilePathId(fileNameId); -} - struct Data { Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; @@ -211,7 +204,7 @@ protected: SourceLocationEntries sourceLocations{{1, 1, {42, 23}, SourceLocationKind::Declaration}}; FilePathIds sourceFileIds{1, 23}; UsedMacros usedMacros{{"Foo", 1}}; - FileStatuses fileStatus{{2, 3, 4, false}}; + FileStatuses fileStatus{{2, 3, 4}}; SourceDependencies sourceDependencies{{1, 2}, {1, 3}}; Utils::SmallString systemIncludeSearchPathsText{ R"([["/includes", 1, 2], [")" TESTDATA_DIR R"(" ,2 , 3], ["/other/includes", 3, 3]])"}; @@ -269,6 +262,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesInCollector) EXPECT_CALL(mockCollector, setFile(main1PathId, ElementsAre("clang++", + "-w", "-Wno-pragma-once-outside-header", "-DNOMINMAX", "-x", @@ -301,6 +295,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithPrecompiledHeaderInColl EXPECT_CALL(mockCollector, setFile(main1PathId, ElementsAre("clang++", + "-w", "-Wno-pragma-once-outside-header", "-DNOMINMAX", "-x", @@ -335,6 +330,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithoutPrecompiledHeaderInC EXPECT_CALL(mockCollector, setFile(main1PathId, ElementsAre("clang++", + "-w", "-Wno-pragma-once-outside-header", "-DNOMINMAX", "-x", @@ -442,26 +438,6 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsUpdateProjectPartsInStorage) indexer.updateProjectParts({projectPart1, projectPart2}); } -TEST_F(SymbolIndexer, UpdateProjectPartsCallsUpdateProjectPartSourcesWithArtifact) -{ - ON_CALL(mockSymbolStorage, fetchProjectPartArtefact(TypedEq<Utils::SmallStringView>("project1"))).WillByDefault(Return(artefact)); - ON_CALL(mockSymbolStorage, insertOrUpdateProjectPart(Eq("project1"), _, _, _, _, _, _, _)).WillByDefault(Return(-1)); - - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(_, _)); - - indexer.updateProjectParts({projectPart1}); -} - -TEST_F(SymbolIndexer, UpdateProjectPartsCallsUpdateProjectPartSourcesWithoutArtifact) -{ - ON_CALL(mockSymbolStorage, fetchProjectPartArtefact(TypedEq<Utils::SmallStringView>("project2"))).WillByDefault(Return(nullArtefact)); - ON_CALL(mockSymbolStorage, insertOrUpdateProjectPart(Eq("project2"), _, _, _, _, _, _, _)).WillByDefault(Return(3)); - - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(3, ElementsAre(IsFileId(1), IsFileId(23)))); - - indexer.updateProjectParts({projectPart2}); -} - TEST_F(SymbolIndexer, UpdateProjectPartsCallsInsertOrUpdateUsedMacros) { EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(Eq(usedMacros))) @@ -472,7 +448,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInsertOrUpdateUsedMacros) TEST_F(SymbolIndexer, UpdateProjectPartsCallsInsertFileStatuses) { - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(Eq(fileStatus))) + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(Eq(fileStatus))) .Times(2); indexer.updateProjectParts({projectPart1, projectPart2}); @@ -516,6 +492,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithoutProjectPartArtifact) EXPECT_CALL(mockCollector, setFile(main1PathId, ElementsAre("clang++", + "-w", "-Wno-pragma-once-outside-header", "-DNOMINMAX", "-x", @@ -538,9 +515,8 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithoutProjectPartArtifact) EXPECT_CALL(mockCollector, collectSymbols()); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)); - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(TypedEq<int>(12), Eq(sourceFileIds))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(Eq(usedMacros))); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(Eq(fileStatus))); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(Eq(fileStatus))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(Eq(sourceDependencies))); EXPECT_CALL(mockSqliteTransactionBackend, commit()); @@ -569,6 +545,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithProjectPartArtifact) EXPECT_CALL(mockCollector, setFile(Eq(main1PathId), ElementsAre("clang++", + "-w", "-Wno-pragma-once-outside-header", "-DNOMINMAX", "-x", @@ -591,9 +568,8 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithProjectPartArtifact) EXPECT_CALL(mockCollector, collectSymbols()); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)); - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(TypedEq<int>(artefact.projectPartId), Eq(sourceFileIds))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(Eq(usedMacros))); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(Eq(fileStatus))); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(Eq(fileStatus))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(Eq(sourceDependencies))); EXPECT_CALL(mockSqliteTransactionBackend, commit()); @@ -624,6 +600,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderButGetsAnErrorForCollectingS EXPECT_CALL(mockCollector, setFile(main1PathId, ElementsAre("clang++", + "-w", "-Wno-pragma-once-outside-header", "-DNOMINMAX", "-x", @@ -646,9 +623,8 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderButGetsAnErrorForCollectingS EXPECT_CALL(mockCollector, collectSymbols()).WillOnce(Return(false)); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()).Times(0); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)).Times(0); - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(TypedEq<int>(12), Eq(sourceFileIds))).Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(Eq(usedMacros))).Times(0); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(Eq(fileStatus))).Times(0); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(Eq(fileStatus))).Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(Eq(sourceDependencies))) .Times(0); EXPECT_CALL(mockSqliteTransactionBackend, commit()).Times(0); @@ -689,6 +665,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrder) EXPECT_CALL(mockCollector, setFile(Eq(sourceFileIds[0]), ElementsAre("clang++", + "-w", "-DFOO", "-DNOMINMAX", "-x", @@ -711,9 +688,8 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrder) EXPECT_CALL(mockCollector, collectSymbols()); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)); - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(artefact.projectPartId, Eq(sourceFileIds))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(Eq(usedMacros))); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(Eq(fileStatus))); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(Eq(fileStatus))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(Eq(sourceDependencies))); EXPECT_CALL(mockSqliteTransactionBackend, commit()); @@ -732,9 +708,8 @@ TEST_F(SymbolIndexer, HandleEmptyOptionalArtifactInUpdateChangedPath) EXPECT_CALL(mockCollector, collectSymbols()).Times(0); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()).Times(0); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(_, _)).Times(0); - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(An<int>(), _)).Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(_)).Times(0); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(_)).Times(0); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(_)).Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(_)).Times(0); EXPECT_CALL(mockSqliteTransactionBackend, commit()).Times(0); @@ -753,6 +728,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrderButGetsAnErrorForCollectingSy EXPECT_CALL(mockCollector, setFile(Eq(sourceFileIds[0]), ElementsAre("clang++", + "-w", "-DFOO", "-DNOMINMAX", "-x", @@ -775,10 +751,8 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrderButGetsAnErrorForCollectingSy EXPECT_CALL(mockCollector, collectSymbols()).WillOnce(Return(false)); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()).Times(0); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)).Times(0); - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(artefact.projectPartId, Eq(sourceFileIds))) - .Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(Eq(usedMacros))).Times(0); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(Eq(fileStatus))).Times(0); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(Eq(fileStatus))).Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(Eq(sourceDependencies))) .Times(0); EXPECT_CALL(mockSqliteTransactionBackend, commit()).Times(0); @@ -797,6 +771,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathIsUsingPrecompiledHeader) EXPECT_CALL(mockCollector, setFile(Eq(sourceFileIds[0]), ElementsAre("clang++", + "-w", "-DFOO", "-DNOMINMAX", "-x", @@ -833,6 +808,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathIsNotUsingPrecompiledHeaderIfItNotExists) EXPECT_CALL(mockCollector, setFile(Eq(sourceFileIds[0]), ElementsAre("clang++", + "-w", "-DFOO", "-DNOMINMAX", "-x", @@ -950,9 +926,8 @@ TEST_F(SymbolIndexer, DontReparseInUpdateProjectPartsIfDefinesAreTheSame) EXPECT_CALL(mockCollector, collectSymbols()).Times(0); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()).Times(0); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(_, _)).Times(0); - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(An<int>(), _)).Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(_)).Times(0); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(_)).Times(0); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(_)).Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(_)).Times(0); EXPECT_CALL(mockSqliteTransactionBackend, commit()).Times(0); diff --git a/tests/unit/unittest/symbolscollector-test.cpp b/tests/unit/unittest/symbolscollector-test.cpp index 2d7025373f..48e4420dc1 100644 --- a/tests/unit/unittest/symbolscollector-test.cpp +++ b/tests/unit/unittest/symbolscollector-test.cpp @@ -147,7 +147,7 @@ protected: ClangBackEnd::FileStatus fileStatus(Utils::SmallStringView filePath) const { - return {filePathId(filePath), fileSize(filePath), lastModified(filePath), false}; + return {filePathId(filePath), fileSize(filePath), lastModified(filePath)}; } SymbolIndex symbolId(const Utils::SmallString &symbolName) diff --git a/tests/unit/unittest/symbolstorage-test.cpp b/tests/unit/unittest/symbolstorage-test.cpp index f9a3d0a7de..ddd7136252 100644 --- a/tests/unit/unittest/symbolstorage-test.cpp +++ b/tests/unit/unittest/symbolstorage-test.cpp @@ -70,8 +70,6 @@ protected: MockSqliteWriteStatement &deleteNewLocationsTableStatement = storage.m_deleteNewLocationsTableStatement; MockSqliteWriteStatement &insertOrUpdateProjectPartStatement = storage.m_insertOrUpdateProjectPartStatement; MockSqliteReadStatement &getProjectPartIdStatement = storage.m_getProjectPartIdStatement; - MockSqliteWriteStatement &deleteAllProjectPartsSourcesWithProjectPartIdStatement = storage.m_deleteAllProjectPartsSourcesWithProjectPartIdStatement; - MockSqliteWriteStatement &insertProjectPartSourcesStatement = storage.m_insertProjectPartSourcesStatement; MockSqliteReadStatement &getProjectPartArtefactsBySourceId = storage.m_getProjectPartArtefactsBySourceId; MockSqliteReadStatement &getProjectPartArtefactsByProjectPartName = storage.m_getProjectPartArtefactsByProjectPartName; @@ -212,18 +210,6 @@ TEST_F(SymbolStorage, InsertOrUpdateProjectPart) Utils::LanguageExtension::None); } - -TEST_F(SymbolStorage, UpdateProjectPartSources) -{ - InSequence sequence; - - EXPECT_CALL(deleteAllProjectPartsSourcesWithProjectPartIdStatement, write(TypedEq<int>(42))); - EXPECT_CALL(insertProjectPartSourcesStatement, write(TypedEq<int>(42), TypedEq<int>(1))); - EXPECT_CALL(insertProjectPartSourcesStatement, write(TypedEq<int>(42), TypedEq<int>(2))); - - storage.updateProjectPartSources(42, {1, 2}); -} - TEST_F(SymbolStorage, FetchProjectPartArtefactBySourceIdCallsValueInStatement) { EXPECT_CALL(getProjectPartArtefactsBySourceId, valueReturnProjectPartArtefact(1)) diff --git a/tests/unit/unittest/tokenprocessor-test.cpp b/tests/unit/unittest/tokenprocessor-test.cpp index 3383c9a3b9..8d79bc95cb 100644 --- a/tests/unit/unittest/tokenprocessor-test.cpp +++ b/tests/unit/unittest/tokenprocessor-test.cpp @@ -1704,6 +1704,24 @@ TEST_F(TokenProcessor, LambdaLocalVariableCapture) ASSERT_THAT(infos[4], HasOnlyType(HighlightingType::LocalVariable)); } +TEST_F(TokenProcessor, StaticProtectedMember) +{ + const auto infos = translationUnit.fullTokenInfosInRange(sourceRange(693, 31)); + + ClangBackEnd::TokenInfoContainer container(infos[2]); + + ASSERT_THAT(container.extraInfo.accessSpecifier, ClangBackEnd::AccessSpecifier::Protected); +} + +TEST_F(TokenProcessor, StaticPrivateMember) +{ + const auto infos = translationUnit.fullTokenInfosInRange(sourceRange(696, 29)); + + ClangBackEnd::TokenInfoContainer container(infos[2]); + + ASSERT_THAT(container.extraInfo.accessSpecifier, ClangBackEnd::AccessSpecifier::Private); +} + Data *TokenProcessor::d; void TokenProcessor::SetUpTestCase() diff --git a/tests/unit/unittest/usedmacrocollector-test.cpp b/tests/unit/unittest/usedmacrocollector-test.cpp index 61f7fcd99b..31aa4fab38 100644 --- a/tests/unit/unittest/usedmacrocollector-test.cpp +++ b/tests/unit/unittest/usedmacrocollector-test.cpp @@ -68,7 +68,7 @@ protected: ClangBackEnd::FileStatus fileStatus(Utils::SmallStringView filePath) const { - return {filePathId(filePath), fileSize(filePath), lastModified(filePath), false}; + return {filePathId(filePath), fileSize(filePath), lastModified(filePath)}; } protected: Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; diff --git a/tests/unit/unittest/usedmacrofilter-test.cpp b/tests/unit/unittest/usedmacrofilter-test.cpp index bdde5417af..788a443eee 100644 --- a/tests/unit/unittest/usedmacrofilter-test.cpp +++ b/tests/unit/unittest/usedmacrofilter-test.cpp @@ -41,11 +41,13 @@ using ClangBackEnd::CompilerMacros; class UsedMacroFilter : public testing::Test { protected: - SourceEntries includes{{1, SourceType::UserInclude, 0}, - {2, SourceType::SystemInclude, 0}, - {3, SourceType::ProjectInclude, 0}, - {4, SourceType::TopSystemInclude, 0}, - {5, SourceType::TopProjectInclude, 0}}; + SourceEntries sources{{1, SourceType::UserInclude, 0}, + {2, SourceType::SystemInclude, 0}, + {3, SourceType::ProjectInclude, 0}, + {4, SourceType::TopSystemInclude, 0}, + {5, SourceType::TopProjectInclude, 0}, + {6, SourceType::Source, 0}, + {7, SourceType::TopProjectInclude, 0, ClangBackEnd::HasMissingIncludes::Yes}}; UsedMacros usedMacros{{"YI", 1}, {"ER", 2}, {"SE", 2}, @@ -65,57 +67,62 @@ protected: TEST_F(UsedMacroFilter, SystemIncludes) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.systemIncludes, ElementsAre(FilePathId{2}, FilePathId{4})); } TEST_F(UsedMacroFilter, ProjectIncludes) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.projectIncludes, ElementsAre(FilePathId{3}, FilePathId{5})); } TEST_F(UsedMacroFilter, TopSystemIncludes) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.topSystemIncludes, ElementsAre(FilePathId{4})); } TEST_F(UsedMacroFilter, TopProjectIncludes) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.topProjectIncludes, ElementsAre(FilePathId{5})); } -TEST_F(UsedMacroFilter, AllIncludes) +TEST_F(UsedMacroFilter, Sources) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); - - ASSERT_THAT(filter.allIncludes, - ElementsAre(FilePathId{1}, FilePathId{2}, FilePathId{3}, FilePathId{4}, FilePathId{5})); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); + + ASSERT_THAT(filter.sources, + ElementsAre(FilePathId{1}, + FilePathId{2}, + FilePathId{3}, + FilePathId{4}, + FilePathId{5}, + FilePathId{6})); } TEST_F(UsedMacroFilter, SystemUsedMacros) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.systemUsedMacros, ElementsAre("ER", "SE", "LIU")); } TEST_F(UsedMacroFilter, ProjectUsedMacros) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.projectUsedMacros, ElementsAre("QI", "WU", "SAN")); } TEST_F(UsedMacroFilter, SystemCompileMacros) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.systemCompilerMacros, ElementsAre(CompilerMacro{"ER", "2", 2}, @@ -125,7 +132,7 @@ TEST_F(UsedMacroFilter, SystemCompileMacros) TEST_F(UsedMacroFilter, ProjectCompileMacros) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.projectCompilerMacros, ElementsAre(CompilerMacro{"QI"}, |