diff options
author | Eike Ziller <eike.ziller@qt.io> | 2019-06-28 12:50:03 +0200 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2019-06-28 12:50:03 +0200 |
commit | 10098b2508abe6e8df59b7e27ea64e9483f1f8be (patch) | |
tree | b73815f1e8ca7aa12c347706b410050e3eb22caa | |
parent | 5dbfd46bcfe177b8308c70a66f7d404429249f6b (diff) | |
parent | a111f251261159b50e92d6866f2058c66b43e390 (diff) | |
download | qt-creator-10098b2508abe6e8df59b7e27ea64e9483f1f8be.tar.gz |
Merge remote-tracking branch 'origin/4.10'
Conflicts:
CMakeLists.txt
tests/unit/unittest/unittest.pro
Change-Id: I64296ad31502d9b35012da129a28e9277e9fcf8e
149 files changed, 2381 insertions, 1007 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e4cdb41dc..46ab6b8da7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,33 +1,18 @@ cmake_minimum_required(VERSION 3.9) -include(FeatureSummary) - -#BINARY_ARTIFACTS_BRANCH = master -#PROJECT_USER_FILE_EXTENSION = .user +## Add paths to check for cmake modules: +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -set(IDE_VERSION "4.10.82" CACHE STRING "The IDE version.") -set(IDE_VERSION_COMPAT "4.10.82" CACHE STRING "The IDE Compatibility version.") -set(IDE_VERSION_DISPLAY "4.11.0-beta1" CACHE STRING "The IDE display version.") -set(IDE_COPYRIGHT_YEAR "2019" CACHE STRING "The IDE copyright year.") +include(FeatureSummary) +include(QtCreatorIDEBranding) set(IDE_REVISION FALSE CACHE BOOL "Marks the presence of IDE revision string.") set(IDE_REVISION_STR "" CACHE STRING "The IDE revision string.") -set(IDE_SETTINGSVARIANT "QtProject" CACHE STRING "The IDE settings variation.") -set(IDE_COPY_SETTINGSVARIANT "Nokia" CACHE STRING "The IDE settings to initially import.") -set(IDE_DISPLAY_NAME "Qt Creator" CACHE STRING "The IDE display name.") -set(IDE_ID "qtcreator" CACHE STRING "The IDE id (no spaces, lowercase!)") -set(IDE_CASED_ID "QtCreator" CACHE STRING "The cased IDE id (no spaces!)") -set(IDE_BUNDLE_IDENTIFIER "org.qt-project.${IDE_ID}" CACHE STRING "The macOS application bundle identifier.") -mark_as_advanced(IDE_VERSION_COMPAT IDE_VERSION_DISPLAY IDE_COPYRIGHT_YEAR - IDE_REVISION IDE_REVISION_STR IDE_SETTINGSVARIANT IDE_COPY_SETTINGSVARIANT - IDE_DISPLAY_NAME IDE_ID IDE_CASED_ID IDE_BUNDLE_IDENTIFIER) +mark_as_advanced(IDE_REVISION IDE_REVISION_STR) project(QtCreator VERSION ${IDE_VERSION}) -## Add paths to check for cmake modules: -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - # Force C++ standard, do not fall back, do not use compiler extensions set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -127,7 +112,7 @@ endif() set(_IDE_APP_PATH "bin") if (APPLE) - set(_IDE_APP_TARGET "Qt Creator") + set(_IDE_APP_TARGET "${IDE_DISPLAY_NAME}") set(_IDE_OUTPUT_PATH "${_IDE_APP_PATH}/${_IDE_APP_TARGET}.app/Contents") @@ -139,7 +124,7 @@ if (APPLE) set(_IDE_DOC_PATH "${_IDE_OUTPUT_PATH}/Resources/doc") set(_IDE_BIN_PATH "${_IDE_OUTPUT_PATH}/MacOS") else () - set(_IDE_APP_TARGET "qtcreator") + set(_IDE_APP_TARGET "${IDE_ID}") set(_IDE_LIBRARY_BASE_PATH "lib") set(_IDE_LIBRARY_PATH "lib/qtcreator") @@ -154,15 +139,15 @@ else () set(_IDE_BIN_PATH "bin") endif () -set(IDE_APP_PATH "${_IDE_APP_PATH}" CACHE PATH "The target path of the IDE application (relative to CMAKE_INSTALL_PREFIX).") -set(IDE_APP_TARGET "${_IDE_APP_TARGET}" CACHE PATH "The IDE application name.") -set(IDE_PLUGIN_PATH "${_IDE_PLUGIN_PATH}" CACHE PATH "The IDE plugin path (relative to CMAKE_INSTALL_PREFIX).") -set(IDE_LIBRARY_BASE_PATH "${_IDE_LIBRARY_BASE_PATH}" CACHE PATH "The IDE library base path (relative to CMAKE_INSTALL_PREFIX).") -set(IDE_LIBRARY_PATH "${_IDE_LIBRARY_PATH}" CACHE PATH "The IDE library path (relative to CMAKE_INSTALL_PREFIX).") -set(IDE_LIBEXEC_PATH "${_IDE_LIBEXEC_PATH}" CACHE PATH "The IDE libexec path (relative to CMAKE_INSTALL_PREFIX).") -set(IDE_DATA_PATH "${_IDE_DATA_PATH}" CACHE PATH "The IDE data path (relative to CMAKE_INSTALL_PREFIX).") -set(IDE_DOC_PATH "${_IDE_DOC_PATH}" CACHE PATH "The IDE documentation path (relative to CMAKE_INSTALL_PREFIX).") -set(IDE_BIN_PATH "${_IDE_BIN_PATH}" CACHE PATH "The IDE bin path (relative to CMAKE_INSTALL_PREFIX).") +set(IDE_APP_PATH "${_IDE_APP_PATH}") # The target path of the IDE application (relative to CMAKE_INSTALL_PREFIX). +set(IDE_APP_TARGET "${_IDE_APP_TARGET}") # The IDE application name. +set(IDE_PLUGIN_PATH "${_IDE_PLUGIN_PATH}") # The IDE plugin path (relative to CMAKE_INSTALL_PREFIX). +set(IDE_LIBRARY_BASE_PATH "${_IDE_LIBRARY_BASE_PATH}") # The IDE library base path (relative to CMAKE_INSTALL_PREFIX). +set(IDE_LIBRARY_PATH "${_IDE_LIBRARY_PATH}") # The IDE library path (relative to CMAKE_INSTALL_PREFIX). +set(IDE_LIBEXEC_PATH "${_IDE_LIBEXEC_PATH}") # The IDE libexec path (relative to CMAKE_INSTALL_PREFIX). +set(IDE_DATA_PATH "${_IDE_DATA_PATH}") # The IDE data path (relative to CMAKE_INSTALL_PREFIX). +set(IDE_DOC_PATH "${_IDE_DOC_PATH}") # The IDE documentation path (relative to CMAKE_INSTALL_PREFIX). +set(IDE_BIN_PATH "${_IDE_BIN_PATH}") # The IDE bin path (relative to CMAKE_INSTALL_PREFIX). file(RELATIVE_PATH RELATIVE_PLUGIN_PATH "/${IDE_BIN_PATH}" "/${IDE_PLUGIN_PATH}") file(RELATIVE_PATH RELATIVE_LIBEXEC_PATH "/${IDE_BIN_PATH}" "/${IDE_LIBEXEC_PATH}") diff --git a/cmake/QtCreatorIDEBranding.cmake b/cmake/QtCreatorIDEBranding.cmake new file mode 100644 index 0000000000..f7327d19fa --- /dev/null +++ b/cmake/QtCreatorIDEBranding.cmake @@ -0,0 +1,14 @@ +#BINARY_ARTIFACTS_BRANCH = master +#PROJECT_USER_FILE_EXTENSION = .user + +set(IDE_VERSION "4.9.83") # The IDE version. +set(IDE_VERSION_COMPAT "4.9.83") # The IDE Compatibility version. +set(IDE_VERSION_DISPLAY "4.10.0-beta2") # The IDE display version. +set(IDE_COPYRIGHT_YEAR "2019") # The IDE copyright year. + +set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation. +set(IDE_COPY_SETTINGSVARIANT "Nokia") # The IDE settings to initially import. +set(IDE_DISPLAY_NAME "Qt Creator") # The IDE display name. +set(IDE_ID "qtcreator") # The IDE id (no spaces, lowercase!) +set(IDE_CASED_ID "QtCreator") # The cased IDE id (no spaces!) +set(IDE_BUNDLE_IDENTIFIER "org.qt-project.${IDE_ID}") # The macOS application bundle identifier. diff --git a/dist/changes-4.10.0.md b/dist/changes-4.10.0.md index baece64d4f..651c719a32 100644 --- a/dist/changes-4.10.0.md +++ b/dist/changes-4.10.0.md @@ -13,6 +13,12 @@ you can check out from the public Git repository. For example: * Removed support for KDE code paster after removal of official API * Added option for pinning files so they stay open when closing all files (QTCREATORBUG-21899) +* Fixed low contrast of hovered folding markers (QTCREATORBUG-21702) + +### Generic Highlighter + +* Fixed that highlighting definition with MIME type `text/plain` + overrode better matching definitions (QTCREATORBUG-22540) ### Language Client @@ -96,6 +102,9 @@ you can check out from the public Git repository. For example: * Improved auto-insertion of closing curly brace (QTCREATORBUG-18872) * Fixed that snippet completion could get in the way (QTCREATORBUG-21767) +* Fixed crash because of small stack size (QTCREATORBUG-22496) +* Fixed recognition of C++ version (QTCREATORBUG-22444) +* Fixed `unknown argument: '-fno-keep-inline-dllexport'` (QTCREATORBUG-22452) ### Clang Format @@ -105,6 +114,8 @@ you can check out from the public Git repository. For example: ## QML Support * Fixed various formatting issues +* Fixed incorrect syntax warning in JavaScript template literal + (QTCREATORBUG-22474) ## Debugging @@ -127,6 +138,7 @@ you can check out from the public Git repository. For example: * Added gradient picker that allows loading and saving of presets * Added support for changing properties for multiple items at once (QDS-324) * Added missing properties for `LineEdit` and `ComboBox` +* Added all fonts from project directory to font selector (QDS-100) * Updated properties of `Flickable` * Improved handling of errors in state editor (QDS-695) @@ -154,13 +166,12 @@ you can check out from the public Git repository. For example: * Added `Clone` for MSVC toolchains (QTCREATORBUG-22163) * Fixed that `mingw32-make`'s warnings were categorized as errors (QTCREATORBUG-22171) * Fixed bitness detection for MinGW (QTCREATORBUG-22160) +* Fixed registration as post mortem debugger on recent Windows versions ### Linux * Improved auto-detection of toolchains (QTCREATORBUG-19179, QTCREATORBUG-20044, QTCREATORBUG-22081) -### macOS - ### Android * Removed support for MIPS64 @@ -172,13 +183,12 @@ you can check out from the public Git repository. For example: * Added support for opening remote terminal with run environment * Added option for `rsync` flags for deployment (QTCREATORBUG-22352) -### Boot to Qt - ### Bare Metal * Added include path detection and output parsers for `IAR`, `KEIL` and `SDCC` toolchains ## Credits for these changes go to: + Aleksei German Alessandro Ambrosano Alessandro Portale @@ -208,10 +218,12 @@ Ivan Komissarov Joel Smith Jörg Bornemann Kavindra Palaraja +Knud Dollereder Leena Miettinen Luca Carlon Marco Bubke Martin Haase +Michael Weghorn Mitch Curtis Nikolai Kosjar Oliver Wolff diff --git a/dist/changes-4.9.2.md b/dist/changes-4.9.2.md new file mode 100644 index 0000000000..bc99860818 --- /dev/null +++ b/dist/changes-4.9.2.md @@ -0,0 +1,56 @@ +# Qt Creator 4.9.2 + +Qt Creator version 4.9.2 contains bug fixes. + +The most important changes are listed in this document. For a complete +list of changes, see the Git log for the Qt Creator sources that +you can check out from the public Git repository. For example: + + git clone git://code.qt.io/qt-creator/qt-creator.git + git log --cherry-pick --pretty=oneline origin/v4.9.1..v4.9.2 + +## General + +* Fixed display of shortcuts in `Keyboard` preferences (QTCREATORBUG-22333) + +## Editing + +* Fixed disabled editor close button in Design mode (QTCREATORBUG-22553) + +### Syntax Highlighting + +* Fixed highlighting issue while editing (QTCREATORBUG-22290) + +## All Projects + +* Fixed saving state of `Hide Empty Directories` +* Fixed crash that could happen after project parsing failed + +## C++ Support + +* Fixed expansion of `%DATE%` in license templates (QTCREATORBUG-22440) + +## Qt Quick Designer + +* Fixed crash on malformed QML (QDS-778) + +## Platform Specific + +### macOS + +* Re-enabled graphics card switching that was disabled as a workaround + for OpenGL issues on macOS 10.14.4 (QTCREATORBUG-22215) + +## Credits for these changes go to: + +Christian Kandeler +Christian Stenger +David Schulz +Eike Ziller +Leena Miettinen +Michl Voznesensky +Robert Löhning +Thomas Hartmann +Tim Jenssen +Tobias Hunger +Ulf Hermann diff --git a/doc/images/qtcreator-autotests-options-boost.png b/doc/images/qtcreator-autotests-options-boost.png Binary files differnew file mode 100644 index 0000000000..4e1f8c4361 --- /dev/null +++ b/doc/images/qtcreator-autotests-options-boost.png diff --git a/doc/images/qtcreator-autotests-options-google.png b/doc/images/qtcreator-autotests-options-google.png Binary files differindex ce5898e162..a32b5fcabb 100644 --- a/doc/images/qtcreator-autotests-options-google.png +++ b/doc/images/qtcreator-autotests-options-google.png diff --git a/doc/images/qtcreator-autotests-options-qt.png b/doc/images/qtcreator-autotests-options-qt.png Binary files differindex 84a2501717..ed93ac1280 100644 --- a/doc/images/qtcreator-autotests-options-qt.png +++ b/doc/images/qtcreator-autotests-options-qt.png diff --git a/doc/images/qtcreator-autotests-options.png b/doc/images/qtcreator-autotests-options.png Binary files differindex e880c8d616..3fd226939d 100644 --- a/doc/images/qtcreator-autotests-options.png +++ b/doc/images/qtcreator-autotests-options.png diff --git a/doc/images/qtcreator-autotests.png b/doc/images/qtcreator-autotests.png Binary files differindex a7e14d5292..48380a10eb 100644 --- a/doc/images/qtcreator-autotests.png +++ b/doc/images/qtcreator-autotests.png diff --git a/doc/images/qtcreator-cmakeexecutable.png b/doc/images/qtcreator-cmakeexecutable.png Binary files differindex 8b328b0fb9..a0475e0c04 100644 --- a/doc/images/qtcreator-cmakeexecutable.png +++ b/doc/images/qtcreator-cmakeexecutable.png diff --git a/doc/images/qtcreator-tests-view.png b/doc/images/qtcreator-tests-view.png Binary files differindex cb771e06cf..0faf49a5a4 100644 --- a/doc/images/qtcreator-tests-view.png +++ b/doc/images/qtcreator-tests-view.png diff --git a/doc/src/cmake/creator-projects-cmake.qdoc b/doc/src/cmake/creator-projects-cmake.qdoc index 2a29cac9c1..585031ded7 100644 --- a/doc/src/cmake/creator-projects-cmake.qdoc +++ b/doc/src/cmake/creator-projects-cmake.qdoc @@ -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 the Qt Creator documentation. @@ -43,6 +43,9 @@ native build configurations and workspaces that you can use in the compiler environment of your choice. + You can use CMake from \QC to build applications for the desktop and + Android devices. You can also build single files to test your changes. + \QC automatically detects the CMake executable specified in the \c PATH. You can add paths to other CMake executables and use them in different build and run \l{glossary-buildandrun-kit}{kits}. @@ -109,6 +112,8 @@ \li Code completion + \li Path completion + \li Auto-indentation \li Matching parentheses and quotes diff --git a/doc/src/howto/creator-only/creator-autotest.qdoc b/doc/src/howto/creator-only/creator-autotest.qdoc index 4c0205eaa1..05edde5027 100644 --- a/doc/src/howto/creator-only/creator-autotest.qdoc +++ b/doc/src/howto/creator-only/creator-autotest.qdoc @@ -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 the Qt Creator documentation. @@ -31,27 +31,28 @@ \title Running Autotests - \QC integrates the \l{Qt Test} framework and - \l{https://github.com/google/googletest}{Google C++ Testing Framework} for - unit testing applications and libraries. You can use \QC to build and run - Qt tests, Qt Quick tests (QML-based Qt tests), and Google tests for your - projects. + \QC integrates the \l{Qt Test} framework, + \l{https://github.com/google/googletest}{Google C++ Testing Framework}, and + \l{https://www.boost.org/doc/libs/1_70_0/libs/test/doc/html/index.html} + {Boost.Test} for unit testing applications and libraries. You can use \QC to + create, build, and run Qt tests, Qt Quick tests (QML-based Qt tests), Google + tests, and Boost tests for your projects. \image qtcreator-autotests.png \section1 Creating Tests - You can use a wizard to create projects that contain Qt or Google tests. + You can use a wizard to create projects that contain tests. - \section2 Creating Qt Tests + \section2 Creating Qt and Qt Quick Tests - To create a Qt test: + To create a Qt or Qt Quick test: \list 1 \li Select \uicontrol File > \uicontrol {New File or Project} > \uicontrol {Other Project} > \uicontrol {Auto Test Project} > \uicontrol Choose to create a project with boilerplate code for a - Qt test. + Qt test or a Qt Quick test. \li In the \uicontrol {Project and Test Information} dialog, specify settings for the project and test: @@ -59,17 +60,17 @@ \list 1 \li In the \uicontrol {Test framework} field, select - \uicontrol {Qt Test}. + \uicontrol {Qt Test} or \uicontrol {Qt Quick Test}. - \li Select the \uicontrol {GUI Application} check box to create - a Qt application. + \li For a Qt test, select the \uicontrol {GUI Application} check + box to create a Qt application. \li In the \uicontrol {Test case name} field, enter a name for the test case. - \li Select the \uicontrol {Requires QApplication} check box to - add the include statement for QApplication to the main.cpp - file of the project. + \li For a Qt test, select the \uicontrol {Requires \QApplication} + check box to add the include statement for QApplication to + the main.cpp file of the project. \li Select the \uicontrol {Generate initialization and cleanup code} checkbox to add functions to your test that are @@ -135,6 +136,46 @@ \l{https://github.com/google/googletest/blob/master/googletest/docs/primer.md} {Google Test Primer}. + \section2 Creating Boost Tests + + To build and run Boost tests, you must have the Boost.Test installed on the + development host. Typically, it is installed when you install Boost. You can + download Boost from \l{https://www.boost.org/}{Boost.org}. + + If Boost libraries can be found by the used compiler and build system, you + do not need to specify the include directory when creating the test. + + To create a Boost test: + + \list 1 + \li Select \uicontrol File > \uicontrol {New File or Project} > + \uicontrol {Other Project} > \uicontrol {Auto Test Project} > + \uicontrol Choose to create a project with boilerplate code for a + Boost test. + \li In the \uicontrol {Project and Test Information} dialog, specify + settings for the project and test: + \list 1 + \li In the \uicontrol {Test framework} field, select + \uicontrol {Boost Test}. + \li In the \uicontrol {Test suite name} field, enter a name for + the test suite. + \li In the \uicontrol {Test case name} field, enter a name for + the test case. + \li In the \uicontrol {Boost include dir (optional)} field, + enter the path to the directory that contains files needed + by Boost.Test, such as \e version.hpp and a subfolder called + \e test that contains the test header files. + \li In the \uicontrol {Build system} field, select the build + system to use for building the project: qmake, CMake, or + Qbs. + \endlist + \endlist + + \QC creates the test in the specified project directory. + For more information about creating Boost tests, see + \l{https://www.boost.org/doc/libs/1_70_0/libs/test/doc/html/index.html} + {Boost.Test}. + \section1 Setting Up the Google C++ Testing Framework To build and run Google tests, you must have the Google C++ Testing @@ -310,6 +351,30 @@ failures into C++ exceptions, select the \uicontrol {Throw on failure} check box. + \section2 Specifying Settings for Running Boost Tests + + \list 1 + \li To specify settings for running Boost tests, select \uicontrol Tools + > \uicontrol Options > \uicontrol {Testing} > + \uicontrol {Boost Test}. + \image qtcreator-autotests-options-boost.png + \li In the \uicontrol {Log format} field, select the error report + format to specify the type of events you want recorded in the + test report. + \li In the \uicontrol {Report level} field, select the verbosity level + of the test result report. Select \uicontrol No if you do not want + a report. + \li Select the \uicontrol Randomize check box to execute the tests in + a random order, using the seed specified in the \uicontrol Seed + field for initializing the randomizer. + \li Select the \uicontrol {Catch system errors} check box to catch + system errors. + \li Select the \uicontrol {Floating point exceptions} check box to + detect floating point exceptions. + \li Select the \uicontrol {Detect memory leaks} check box to detect + memory leaks. + \endlist + \section1 Viewing Test Output The test results are displayed in the \uicontrol {Test Results} output pane diff --git a/doc/src/overview/creator-only/creator-overview.qdoc b/doc/src/overview/creator-only/creator-overview.qdoc index 790ed4bf0d..09ef2766e4 100644 --- a/doc/src/overview/creator-only/creator-overview.qdoc +++ b/doc/src/overview/creator-only/creator-overview.qdoc @@ -116,9 +116,9 @@ execution. In addition, the QML Profiler enables you to profile Qt Quick applications. - \QC is integrated to the \l{Qt Test} and Google C++ Testing - frameworks for unit testing applications and libraries. You can - use \QC to build and run autotests. + \QC is integrated to the \l{Qt Test}, Google C++ Testing, and + Boost.Test frameworks for unit testing applications and + libraries. You can use \QC to create, build, and run autotests. For more information, see \l{Testing}. \li \b {Publishing} diff --git a/doc/src/overview/creator-only/creator-testing.qdoc b/doc/src/overview/creator-only/creator-testing.qdoc index 39bae4ba17..10df1d7f31 100644 --- a/doc/src/overview/creator-only/creator-testing.qdoc +++ b/doc/src/overview/creator-only/creator-testing.qdoc @@ -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 the Qt Creator documentation. @@ -60,9 +60,8 @@ \li \l{Running Autotests} - You can build and run Qt tests, Qt Quick tests, and Google tests - using \QC. In addition, you can use a wizard to create projects that - contain Qt or Google tests. + You can create, build and run Qt tests, Qt Quick tests, Google + tests, and Boost tests using \QC. \endlist diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index fdfb39746e..2f056c7a93 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -153,7 +153,7 @@ class PlainDumper: if d.isExpanded(): with Children(d): for child in children: - d.putSubItem(child[0], d.fromNativeValue(child[1])) + d.putSubItem(child[0], d.fromNativeValue(gdb.Value(child[1]))) def importPlainDumpers(args): if args == 'off': diff --git a/share/qtcreator/debugger/stdtypes.py b/share/qtcreator/debugger/stdtypes.py index a14029fdc3..3dfbe5bd8b 100644 --- a/share/qtcreator/debugger/stdtypes.py +++ b/share/qtcreator/debugger/stdtypes.py @@ -953,43 +953,27 @@ def qdumpHelper__std__vector(d, value, isLibCpp): innerType = value.type[0] isBool = innerType.name == 'bool' - try: - allocator = value.type[1].name - except: - allocator = '' - - isStdAllocator = allocator == 'std::allocator<%s>' % innerType.name - if isBool: if isLibCpp: - if isStdAllocator: - (start, size) = value.split("pp") # start is 'unsigned long *' - else: - start = value["__begin_"].pointer() - size = value["__size_"] + start = value["__begin_"].pointer() + size = value["__size_"] alloc = size else: - if isStdAllocator: - (start, soffset, pad, finish, foffset, pad, alloc) = value.split("pI@pI@p") - else: - start = value["_M_start"]["_M_p"].pointer() - soffset = value["_M_start"]["_M_offset"] - finish = value["_M_finish"]["_M_p"].pointer() - foffset = value["_M_finish"]["_M_offset"] - alloc = value["_M_end_of_storage"].pointer() + start = value["_M_start"]["_M_p"].pointer() + soffset = value["_M_start"]["_M_offset"].integer() + finish = value["_M_finish"]["_M_p"].pointer() + foffset = value["_M_finish"]["_M_offset"].integer() + alloc = value["_M_end_of_storage"].pointer() size = (finish - start) * 8 + foffset - soffset # 8 is CHAR_BIT. else: - if isStdAllocator: - (start, finish, alloc) = value.split("ppp") + if isLibCpp: + start = value["__begin_"].pointer() + finish = value["__end_"].pointer() + alloc = value["__end_cap_"].pointer() else: - if isLibCpp: - start = value["__begin_"].pointer() - finish = value["__end_"].pointer() - alloc = value["__end_cap_"].pointer() - else: - start = value["_M_start"].pointer() - finish = value["_M_finish"].pointer() - alloc = value["_M_end_of_storage"].pointer() + start = value["_M_start"].pointer() + finish = value["_M_finish"].pointer() + alloc = value["_M_end_of_storage"].pointer() size = int((finish - start) / innerType.size()) d.check(finish <= alloc) if size > 0: @@ -1088,19 +1072,12 @@ def qdump__std__basic_string(d, value): def qdump__std____cxx11__basic_string(d, value): innerType = value.type[0] try: - allocator = value.type[2].name + data = value["_M_dataplus"]["_M_p"].pointer() + size = int(value["_M_string_length"]) except: - allocator = '' - if allocator == 'std::allocator<%s>' % innerType.name: - (data, size) = value.split("pI") - else: - try: - data = value["_M_dataplus"]["_M_p"] - size = int(value["_M_string_length"]) - except: - d.putEmptyValue() - d.putPlainChildren(value) - return + d.putEmptyValue() + d.putPlainChildren(value) + return d.check(0 <= size) #and size <= alloc and alloc <= 100*1000*1000) d.putCharArrayHelper(data, size, innerType, d.currentItemFormat()) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml index 16de1a90ef..5d9ae328d2 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml @@ -39,7 +39,35 @@ StudioControls.ComboBox { onTextColorChanged: setColor() editable: true - model: ["Arial", "Times New Roman", "Courier", "Verdana", "Tahoma"] + + property string fontFilter: "*.ttf *.otf" + + + FileResourcesModel { + modelNodeBackendProperty: modelNodeBackend + filter: comboBox.fontFilter + id: fileModel + } + + function fontUrlToName(url) { + var fontLoader = Qt.createQmlObject('import QtQuick 2.0; FontLoader { source: \"' + url + '\"; }', + comboBox, + "dynamicFontLoader"); + return fontLoader.name + } + + function setupModel() { + var files = fileModel.fileModel + var familyNames = ["Arial", "Times New Roman", "Courier", "Verdana", "Tahoma"] + + files.forEach(function (item, index) { + var name = fontUrlToName(fileModel.dirPath + "/" + item) + familyNames.push(name) + }); + + familyNames.sort() + comboBox.model = familyNames + } onModelChanged: { editText = comboBox.backendValue.valueToString @@ -97,10 +125,12 @@ StudioControls.ComboBox { target: modelNodeBackend onSelectionChanged: { comboBox.editText = backendValue.value + setupModel() } } Component.onCompleted: { + setupModel() //Hack to style the text input for (var i = 0; i < comboBox.children.length; i++) { if (comboBox.children[i].text !== undefined) { diff --git a/share/qtcreator/templates/wizards/files/java/wizard.json b/share/qtcreator/templates/wizards/files/java/wizard.json index 6341319c6b..5a8fae5dc1 100644 --- a/share/qtcreator/templates/wizards/files/java/wizard.json +++ b/share/qtcreator/templates/wizards/files/java/wizard.json @@ -9,7 +9,7 @@ "iconText": "java", "enabled": "%{JS: value('Plugins').indexOf('Android') >= 0}", - "options": [ { "key": "ClassName", "value": "%{JS: value('FileName').charAt(0).toUpperCase() + value('FileName').substr(1).replace(/\\.java$/,'')}" } ], + "options": [ { "key": "ClassName", "value": "%{JS: value('FileName').charAt(0).toUpperCase() + value('FileName').substr(1).replace(/[.]java$/,'')}" } ], "pages" : [ diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/app.qbs b/share/qtcreator/templates/wizards/projects/qtquickapplication/app.qbs index d86ee9b454..27a8b66c3c 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/app.qbs +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/app.qbs @@ -2,7 +2,7 @@ import qbs Application { @if "%{UseVirtualKeyboard}" == "true" - Depends { name: "Qt"; submodules: "quick", "virtualkeyboard" } + Depends { name: "Qt"; submodules: ["quick", "virtualkeyboard"] } @else Depends { name: "Qt.quick" } @endif diff --git a/share/qtcreator/templates/wizards/projects/vcs/bazaar/wizard.json b/share/qtcreator/templates/wizards/projects/vcs/bazaar/wizard.json index a8b4d041e7..f81509c4ed 100644 --- a/share/qtcreator/templates/wizards/projects/vcs/bazaar/wizard.json +++ b/share/qtcreator/templates/wizards/projects/vcs/bazaar/wizard.json @@ -14,7 +14,7 @@ { "key": "vcsId", "value": "B.Bazaar" }, { "key": "vcsName", "value": "%{JS: Vcs.displayName('%{vcsId}')}" }, { "key": "SR", "value": "%{JS: '%{Repo}'.substr('%{Repo}'.indexOf(':') + 1) }" }, - { "key": "defaultDir", "value": "%{JS: '%{SR}'.substr('%{SR}'.lastIndexOf('/') + 1).replace(/\\./, '-') }"}, + { "key": "defaultDir", "value": "%{JS: '%{SR}'.substr('%{SR}'.lastIndexOf('/') + 1).replace(/[.]/g, '-') }"}, { "key": "RevArg", "value": "%{JS: '%{Rev}' !== '' ? '-r' : ''}" }, { "key": "TargetPath", "value": "%{Path}/%{Dir}" } ], diff --git a/share/qtcreator/templates/wizards/projects/vcs/git/wizard.json b/share/qtcreator/templates/wizards/projects/vcs/git/wizard.json index c97698612b..0295468f6f 100644 --- a/share/qtcreator/templates/wizards/projects/vcs/git/wizard.json +++ b/share/qtcreator/templates/wizards/projects/vcs/git/wizard.json @@ -13,8 +13,8 @@ [ { "key": "vcsId", "value": "G.Git" }, { "key": "vcsName", "value": "%{JS: Vcs.displayName('%{vcsId}')}" }, - { "key": "SR", "value": "%{JS: '%{Repo}'.replace(/\\.git$/, '') }"}, - { "key": "defaultDir", "value": "%{JS: '%{SR}'.substr('%{SR}'.lastIndexOf('/') + 1).replace(/\\./, '-') }"}, + { "key": "SR", "value": "%{JS: '%{Repo}'.replace(/[.]git$/, '') }"}, + { "key": "defaultDir", "value": "%{JS: '%{SR}'.substr('%{SR}'.lastIndexOf('/') + 1).replace(/[.]/g, '-') }"}, { "key": "branchArg", "value": "%{JS: '%{Branch}' ? '--branch' : '' }" }, { "key": "TargetPath", "value": "%{Path}/%{Dir}" } ], diff --git a/share/qtcreator/templates/wizards/projects/vcs/mercurial/wizard.json b/share/qtcreator/templates/wizards/projects/vcs/mercurial/wizard.json index 75bd410861..8e655e1eb6 100644 --- a/share/qtcreator/templates/wizards/projects/vcs/mercurial/wizard.json +++ b/share/qtcreator/templates/wizards/projects/vcs/mercurial/wizard.json @@ -14,7 +14,7 @@ { "key": "vcsId", "value": "H.Mercurial" }, { "key": "vcsName", "value": "%{JS: Vcs.displayName('%{vcsId}')}" }, { "key": "SR", "value": "%{JS: '%{Repo}'.substr('%{Repo}'.indexOf(':') + 1) }"}, - { "key": "defaultDir", "value": "%{JS: '%{SR}'.substr('%{SR}'.lastIndexOf('/') + 1).replace(/\\./, '-') }"}, + { "key": "defaultDir", "value": "%{JS: '%{SR}'.substr('%{SR}'.lastIndexOf('/') + 1).replace(/[.]/g, '-') }"}, { "key": "TargetPath", "value": "%{Path}/%{Dir}" } ], diff --git a/share/qtcreator/templates/wizards/projects/vcs/subversion/wizard.json b/share/qtcreator/templates/wizards/projects/vcs/subversion/wizard.json index aef8a28b9a..cfeddbb532 100644 --- a/share/qtcreator/templates/wizards/projects/vcs/subversion/wizard.json +++ b/share/qtcreator/templates/wizards/projects/vcs/subversion/wizard.json @@ -13,8 +13,8 @@ [ { "key": "vcsId", "value": "J.Subversion" }, { "key": "vcsName", "value": "%{JS: Vcs.displayName('%{vcsId}')}" }, - { "key": "SR", "value": "%{JS: '%{Repo}'.replace(/\\/trunk$/, '').replace(/\\/$/, '') }"}, - { "key": "defaultDir", "value": "%{JS: '%{SR}'.substr('%{SR}'.lastIndexOf('/') + 1).replace(/\\./, '-') }"}, + { "key": "SR", "value": "%{JS: '%{Repo}'.replace(/[/]trunk$/, '').replace(/[/]$/, '') }"}, + { "key": "defaultDir", "value": "%{JS: '%{SR}'.substr('%{SR}'.lastIndexOf('/') + 1).replace(/[.]/g, '-') }"}, { "key": "TargetPath", "value": "%{Path}/%{Dir}" } ], diff --git a/share/qtcreator/translations/qtcreator_fr.ts b/share/qtcreator/translations/qtcreator_fr.ts index f1677fa36e..95808e6d7b 100644 --- a/share/qtcreator/translations/qtcreator_fr.ts +++ b/share/qtcreator/translations/qtcreator_fr.ts @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> -<TS version="2.0" language="fr"> +<TS version="2.1" language="fr"> <context> <name>Application</name> <message> @@ -42412,7 +42412,7 @@ au gestionnaire de version (%2)</translation> </message> <message> <source>Set Message Tracepoint at Line %1...</source> - <translation>Définir un message de traçace à la ligne %1...</translation> + <translation>Définir un message de traçage à la ligne %1...</translation> </message> <message> <source>Disassemble Function "%1"</source> @@ -70891,7 +70891,7 @@ réinitialisation du moniteur</translation> <message> <source>Get Started Now</source> <translatorcomment>attention à la longueur du texte, doit reste petit</translatorcomment> - <translation type="unfinished">Démarrer</translation> + <translation>Démarrer</translation> </message> <message> <source>Online Community</source> diff --git a/src/libs/clangsupport/clangpathwatcher.h b/src/libs/clangsupport/clangpathwatcher.h index dab52996c2..7a7d6ccfcf 100644 --- a/src/libs/clangsupport/clangpathwatcher.h +++ b/src/libs/clangsupport/clangpathwatcher.h @@ -1,4 +1,4 @@ -/**************************************************************************** +; /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ @@ -27,71 +27,94 @@ #include "clangpathwatcherinterface.h" #include "clangpathwatchernotifier.h" -#include "changedfilepathcompressor.h" +#include "directorypathcompressor.h" #include "filepathcachinginterface.h" +#include "filesystem.h" #include "stringcache.h" +#include <utils/algorithm.h> + #include <QTimer> namespace ClangBackEnd { +template<class InputIt1, class InputIt2, class Callable> +void set_greedy_intersection_call( + InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable callable) +{ + while (first1 != last1 && first2 != last2) { + if (*first1 < *first2) { + ++first1; + } else { + if (*first2 < *first1) + ++first2; + else + callable(*first1++); + } + } +} + class WatcherEntry { public: ProjectPartId id; - FilePathId pathId; + DirectoryPathId directoryPathId; + FilePathId filePathId; + long long lastModified = -1; friend bool operator==(WatcherEntry first, WatcherEntry second) { - return first.id == second.id && first.pathId == second.pathId; + return first.id == second.id && first.directoryPathId == second.directoryPathId + && first.filePathId == second.filePathId; } friend bool operator<(WatcherEntry first, WatcherEntry second) { - return std::tie(first.pathId, first.id) < std::tie(second.pathId, second.id); + return std::tie(first.directoryPathId, first.filePathId, first.id) + < std::tie(second.directoryPathId, second.filePathId, second.id); } - friend bool operator<(WatcherEntry entry, FilePathId pathId) + friend bool operator<(DirectoryPathId directoryPathId, WatcherEntry entry) { - return entry.pathId < pathId; + return directoryPathId < entry.directoryPathId; } - friend bool operator<(FilePathId pathId, WatcherEntry entry) + friend bool operator<(WatcherEntry entry, DirectoryPathId directoryPathId) { - return pathId < entry.pathId; + return entry.directoryPathId < directoryPathId; } - operator FilePathId() const - { - return pathId; - } + operator FilePathId() const { return filePathId; } + + operator DirectoryPathId() const { return directoryPathId; } }; using WatcherEntries = std::vector<WatcherEntry>; -template <typename FileSystemWatcher, - typename Timer> +template<typename FileSystemWatcher, typename Timer> class CLANGSUPPORT_GCCEXPORT ClangPathWatcher : public ClangPathWatcherInterface { public: ClangPathWatcher(FilePathCachingInterface &pathCache, - ClangPathWatcherNotifier *notifier=nullptr) - : m_changedFilePathCompressor(pathCache), - m_pathCache(pathCache), - m_notifier(notifier) + FileSystemInterface &fileSystem, + ClangPathWatcherNotifier *notifier = nullptr) + : m_pathCache(pathCache) + , m_fileStatusCache(fileSystem) + , m_fileSystem(fileSystem) + , m_notifier(notifier) { QObject::connect(&m_fileSystemWatcher, - &FileSystemWatcher::fileChanged, - [&] (const QString &filePath) { compressChangedFilePath(filePath); }); + &FileSystemWatcher::directoryChanged, + [&](const QString &path) { compressChangedDirectoryPath(path); }); - m_changedFilePathCompressor.setCallback([&] (ClangBackEnd::FilePathIds &&filePathIds) { - addChangedPathForFilePath(std::move(filePathIds)); + m_directoryPathCompressor.setCallback([&](ClangBackEnd::DirectoryPathIds &&directoryPathIds) { + addChangedPathForFilePath(std::move(directoryPathIds)); }); } ~ClangPathWatcher() { - m_changedFilePathCompressor.setCallback([&] (FilePathIds &&) {}); + m_directoryPathCompressor.setCallback([&](DirectoryPathIds &&) {}); } void updateIdPaths(const std::vector<IdPaths> &idPaths) override @@ -109,7 +132,7 @@ public: auto filteredPaths = filterNotWatchedPaths(removedEntries); if (!filteredPaths.empty()) - m_fileSystemWatcher.removePaths(convertWatcherEntriesToQStringList(filteredPaths)); + m_fileSystemWatcher.removePaths(convertWatcherEntriesToDirectoryPathList(filteredPaths)); } void setNotifier(ClangPathWatcherNotifier *notifier) override @@ -164,7 +187,13 @@ public: outputIterator = std::transform(idPath.filePathIds.begin(), idPath.filePathIds.end(), outputIterator, - [&] (FilePathId pathId) { return WatcherEntry{id, pathId}; }); + [&](FilePathId filePathId) { + return WatcherEntry{ + id, + m_pathCache.directoryPathId(filePathId), + filePathId, + m_fileStatusCache.lastModifiedTime(filePathId)}; + }); } std::sort(entries.begin(), entries.end()); @@ -182,7 +211,7 @@ public: mergeToWatchedEntries(newEntries); if (!filteredPaths.empty()) - m_fileSystemWatcher.addPaths(convertWatcherEntriesToQStringList(filteredPaths)); + m_fileSystemWatcher.addPaths(convertWatcherEntriesToDirectoryPathList(filteredPaths)); } void removeUnusedEntries(const WatcherEntries &entries, const ProjectPartIds &ids) @@ -194,33 +223,31 @@ public: auto filteredPaths = filterNotWatchedPaths(oldEntries); if (!filteredPaths.empty()) - m_fileSystemWatcher.removePaths(convertWatcherEntriesToQStringList(filteredPaths)); + m_fileSystemWatcher.removePaths(convertWatcherEntriesToDirectoryPathList(filteredPaths)); } - FileSystemWatcher &fileSystemWatcher() + FileSystemWatcher &fileSystemWatcher() { return m_fileSystemWatcher; } + + QStringList convertWatcherEntriesToDirectoryPathList(const DirectoryPathIds &directoryPathIds) const { - return m_fileSystemWatcher; + return Utils::transform<QStringList>(directoryPathIds, [&](DirectoryPathId id) { + return QString(m_pathCache.directoryPath(id)); + }); } - QStringList convertWatcherEntriesToQStringList( - const WatcherEntries &watcherEntries) + QStringList convertWatcherEntriesToDirectoryPathList(const WatcherEntries &watcherEntries) const { - QStringList paths; - paths.reserve(int(watcherEntries.size())); + DirectoryPathIds directoryPathIds = Utils::transform<DirectoryPathIds>( + watcherEntries, [&](WatcherEntry entry) { return entry.directoryPathId; }); - std::transform(watcherEntries.begin(), - watcherEntries.end(), - std::back_inserter(paths), - [&] (WatcherEntry entry) { - return QString(m_pathCache.filePath(entry.pathId).path()); - }); + std::sort(directoryPathIds.begin(), directoryPathIds.end()); + directoryPathIds.erase(std::unique(directoryPathIds.begin(), directoryPathIds.end()), + directoryPathIds.end()); - return paths; + return convertWatcherEntriesToDirectoryPathList(directoryPathIds); } - template <typename Compare> - WatcherEntries notWatchedEntries(const WatcherEntries &entries, - Compare compare) const + WatcherEntries notWatchedEntries(const WatcherEntries &entries) const { WatcherEntries notWatchedEntries; notWatchedEntries.reserve(entries.size()); @@ -229,24 +256,23 @@ public: entries.end(), m_watchedEntries.cbegin(), m_watchedEntries.cend(), - std::back_inserter(notWatchedEntries), - compare); + std::back_inserter(notWatchedEntries)); return notWatchedEntries; } - WatcherEntries notWatchedEntries(const WatcherEntries &entries) const + DirectoryPathIds notWatchedPaths(const DirectoryPathIds &ids) const { - return notWatchedEntries(entries, std::less<WatcherEntry>()); - } + DirectoryPathIds notWatchedDirectoryIds; + notWatchedDirectoryIds.reserve(ids.size()); - WatcherEntries notWatchedPaths(const WatcherEntries &entries) const - { - auto compare = [] (WatcherEntry first, WatcherEntry second) { - return first.pathId < second.pathId; - }; + std::set_difference(ids.begin(), + ids.end(), + m_watchedEntries.cbegin(), + m_watchedEntries.cend(), + std::back_inserter(notWatchedDirectoryIds)); - return notWatchedEntries(entries, compare); + return notWatchedDirectoryIds; } template <typename Compare> @@ -297,25 +323,24 @@ public: m_watchedEntries = std::move(newWatchedEntries); } - static - WatcherEntries uniquePaths(const WatcherEntries &pathEntries) + static DirectoryPathIds uniquePaths(const WatcherEntries &pathEntries) { - WatcherEntries uniqueEntries; - uniqueEntries.reserve(pathEntries.size()); + DirectoryPathIds uniqueDirectoryIds; + uniqueDirectoryIds.reserve(pathEntries.size()); - auto compare = [] (WatcherEntry first, WatcherEntry second) { - return first.pathId == second.pathId; + auto compare = [](WatcherEntry first, WatcherEntry second) { + return first.directoryPathId == second.directoryPathId; }; std::unique_copy(pathEntries.begin(), pathEntries.end(), - std::back_inserter(uniqueEntries), + std::back_inserter(uniqueDirectoryIds), compare); - return uniqueEntries; + return uniqueDirectoryIds; } - WatcherEntries filterNotWatchedPaths(const WatcherEntries &entries) + DirectoryPathIds filterNotWatchedPaths(const WatcherEntries &entries) const { return notWatchedPaths(uniquePaths(entries)); } @@ -351,40 +376,48 @@ public: oldEntries.end(), std::back_inserter(newWatchedEntries)); - - m_watchedEntries = newWatchedEntries; + m_watchedEntries = std::move(newWatchedEntries); } - void compressChangedFilePath(const QString &filePath) + void compressChangedDirectoryPath(const QString &path) { - m_changedFilePathCompressor.addFilePath(filePath); + m_directoryPathCompressor.addDirectoryPathId( + m_pathCache.directoryPathId(Utils::PathString{path})); } - WatcherEntries watchedEntriesForPaths(ClangBackEnd::FilePathIds &&filePathIds) + WatcherEntries watchedEntriesForPaths(ClangBackEnd::DirectoryPathIds &&directoryPathIds) { WatcherEntries foundEntries; - foundEntries.reserve(filePathIds.size()); - - for (FilePathId pathId : filePathIds) { - auto range = std::equal_range(m_watchedEntries.begin(), m_watchedEntries.end(), pathId); - foundEntries.insert(foundEntries.end(), range.first, range.second); - } + foundEntries.reserve(m_watchedEntries.size()); + + set_greedy_intersection_call(m_watchedEntries.begin(), + m_watchedEntries.end(), + directoryPathIds.begin(), + directoryPathIds.end(), + [&](WatcherEntry &entry) { + m_fileStatusCache.update(entry.filePathId); + auto currentLastModified = m_fileStatusCache.lastModifiedTime( + entry.filePathId); + if (entry.lastModified < currentLastModified) { + foundEntries.push_back(entry); + entry.lastModified = currentLastModified; + } + }); return foundEntries; } - FilePathIds watchedPaths(const FilePathIds &filePathIds) const + FilePathIds watchedPaths(const WatcherEntries &entries) const { - FilePathIds watchedFilePathIds; - watchedFilePathIds.reserve(filePathIds.size()); + auto filePathIds = Utils::transform<FilePathIds>(entries, [](WatcherEntry entry) { + return entry.filePathId; + }); + + std::sort(filePathIds.begin(), filePathIds.end()); - std::set_intersection(m_watchedEntries.begin(), - m_watchedEntries.end(), - filePathIds.begin(), - filePathIds.end(), - std::back_inserter(watchedFilePathIds)); + filePathIds.erase(std::unique(filePathIds.begin(), filePathIds.end()), filePathIds.end()); - return watchedFilePathIds; + return filePathIds; } ProjectPartIds idsForWatcherEntries(const WatcherEntries &foundEntries) @@ -403,21 +436,20 @@ public: ProjectPartIds uniqueIds(ProjectPartIds &&ids) { std::sort(ids.begin(), ids.end()); - auto newEnd = std::unique(ids.begin(), ids.end()); - ids.erase(newEnd, ids.end()); + ids.erase(std::unique(ids.begin(), ids.end()), ids.end()); return std::move(ids); } - void addChangedPathForFilePath(FilePathIds &&filePathIds) + void addChangedPathForFilePath(DirectoryPathIds &&directoryPathIds) { if (m_notifier) { - WatcherEntries foundEntries = watchedEntriesForPaths(std::move(filePathIds)); + WatcherEntries foundEntries = watchedEntriesForPaths(std::move(directoryPathIds)); ProjectPartIds changedIds = idsForWatcherEntries(foundEntries); m_notifier->pathsWithIdsChanged(uniqueIds(std::move(changedIds))); - m_notifier->pathsChanged(watchedPaths(filePathIds)); + m_notifier->pathsChanged(watchedPaths(foundEntries)); } } @@ -428,10 +460,12 @@ public: private: WatcherEntries m_watchedEntries; - ChangedFilePathCompressor<Timer> m_changedFilePathCompressor; FileSystemWatcher m_fileSystemWatcher; + FileStatusCache m_fileStatusCache; + FileSystemInterface &m_fileSystem; FilePathCachingInterface &m_pathCache; ClangPathWatcherNotifier *m_notifier; + DirectoryPathCompressor<Timer> m_directoryPathCompressor; }; } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/clangsupport-lib.pri b/src/libs/clangsupport/clangsupport-lib.pri index df537f5848..dc66408e58 100644 --- a/src/libs/clangsupport/clangsupport-lib.pri +++ b/src/libs/clangsupport/clangsupport-lib.pri @@ -18,6 +18,7 @@ SOURCES += \ $$PWD/clangcodemodelserverproxy.cpp \ $$PWD/alivemessage.cpp \ $$PWD/completionsmessage.cpp \ + $$PWD/filesystem.cpp \ $$PWD/requestcompletionsmessage.cpp \ $$PWD/echomessage.cpp \ $$PWD/endmessage.cpp \ @@ -87,7 +88,8 @@ SOURCES += \ $$PWD/removegeneratedfilesmessage.cpp \ $$PWD/generatedfiles.cpp \ $$PWD/projectpartartefact.cpp \ - $$PWD/projectpartcontainer.cpp + $$PWD/projectpartcontainer.cpp \ + $$PWD/filestatuscache.cpp HEADERS += \ $$PWD/cancelmessage.h \ @@ -109,7 +111,11 @@ HEADERS += \ $$PWD/alivemessage.h \ $$PWD/clangsupportexceptions.h \ $$PWD/completionsmessage.h \ + $$PWD/directoryandfilepathid.h \ + $$PWD/directorypathid.h \ $$PWD/executeinloop.h \ + $$PWD/filesystem.h \ + $$PWD/filesysteminterface.h \ $$PWD/pchpaths.h \ $$PWD/projectpartid.h \ $$PWD/projectpartsstorage.h \ @@ -151,6 +157,7 @@ HEADERS += \ $$PWD/refactoringserverinterface.h \ $$PWD/refactoringserverproxy.h \ $$PWD/referencesmessage.h \ + $$PWD/set_algorithm.h \ $$PWD/unsavedfilesupdatedmessage.h \ $$PWD/removeprojectpartsmessage.h \ $$PWD/requestannotationsmessage.h \ @@ -217,6 +224,8 @@ HEADERS += \ $$PWD/sourceentry.h \ $$PWD/modifiedtimecheckerinterface.h \ $$PWD/environment.h \ + $$PWD/filestatus.h \ + $$PWD/filestatuscache.h \ $$PWD/modifiedtimechecker.h contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols diff --git a/src/libs/clangsupport/directoryandfilepathid.h b/src/libs/clangsupport/directoryandfilepathid.h new file mode 100644 index 0000000000..8969372919 --- /dev/null +++ b/src/libs/clangsupport/directoryandfilepathid.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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 "directorypathid.h" +#include "filepathid.h" + +#include <QDataStream> + +#include <vector> + +namespace ClangBackEnd { +class DirectoryAndFilePathId +{ +public: + constexpr DirectoryAndFilePathId() = default; + + DirectoryAndFilePathId(const char *) = delete; + + DirectoryAndFilePathId(int directoryPathId, int filePathId) + : directoryPathId(directoryPathId) + , filePathId(filePathId) + {} + + bool isValid() const { return directoryPathId.isValid() && filePathId.isValid(); } + + friend bool operator==(DirectoryAndFilePathId first, DirectoryAndFilePathId second) + { + return first.isValid() && first.directoryPathId == second.directoryPathId + && first.filePathId == second.filePathId; + } + + friend bool operator!=(DirectoryAndFilePathId first, DirectoryAndFilePathId second) + { + return !(first == second); + } + + friend bool operator<(DirectoryAndFilePathId first, DirectoryAndFilePathId second) + { + return std::tie(first.directoryPathId, first.filePathId) + < std::tie(second.directoryPathId, second.filePathId); + } + + friend QDataStream &operator<<(QDataStream &out, + const DirectoryAndFilePathId &directoryAndFilePathId) + { + out << directoryAndFilePathId.directoryPathId; + out << directoryAndFilePathId.filePathId; + + return out; + } + + friend QDataStream &operator>>(QDataStream &in, DirectoryAndFilePathId &directoryAndFilePathId) + { + in >> directoryAndFilePathId.directoryPathId; + in >> directoryAndFilePathId.filePathId; + return in; + } + +public: + DirectoryPathId directoryPathId; + FilePathId filePathId; +}; + +using DirectoryAndFilePathIds = std::vector<DirectoryAndFilePathId>; + +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/changedfilepathcompressor.h b/src/libs/clangsupport/directorypathcompressor.h index aa8e1ec71a..cd02948e83 100644 --- a/src/libs/clangsupport/changedfilepathcompressor.h +++ b/src/libs/clangsupport/directorypathcompressor.h @@ -27,53 +27,44 @@ #include "clangsupport_global.h" -#include <filepathid.h> -#include <filepathcache.h> +#include "filepathcachinginterface.h" +#include <QDir> #include <QTimer> -#include <filepathcachinginterface.h> +#include <utils/algorithm.h> #include <functional> namespace ClangBackEnd { -template <typename Timer> -class ChangedFilePathCompressor +template<typename Timer> +class DirectoryPathCompressor { public: - ChangedFilePathCompressor(FilePathCachingInterface &filePathCache) - : m_filePathCache(filePathCache) - { - m_timer.setSingleShot(true); - } + DirectoryPathCompressor() { m_timer.setSingleShot(true); } - virtual ~ChangedFilePathCompressor() - { - } + virtual ~DirectoryPathCompressor() = default; - void addFilePath(const QString &filePath) + void addDirectoryPathId(DirectoryPathId directoryPathIdId) { - FilePathId filePathId = m_filePathCache.filePathId(FilePath(filePath)); + auto found = std::lower_bound(m_directoryPathIds.begin(), + m_directoryPathIds.end(), + directoryPathIdId); - auto found = std::lower_bound(m_filePaths.begin(), m_filePaths.end(), filePathId); - - if (found == m_filePaths.end() || *found != filePathId) - m_filePaths.insert(found, filePathId); + if (found == m_directoryPathIds.end() || *found != directoryPathIdId) + m_directoryPathIds.insert(found, directoryPathIdId); restartTimer(); } - FilePathIds takeFilePathIds() - { - return std::move(m_filePaths); - } + DirectoryPathIds takeDirectoryPathIds() { return std::move(m_directoryPathIds); } - virtual void setCallback(std::function<void(ClangBackEnd::FilePathIds &&)> &&callback) + virtual void setCallback(std::function<void(ClangBackEnd::DirectoryPathIds &&)> &&callback) { - QObject::connect(&m_timer, - &Timer::timeout, - [this, callback=std::move(callback)] { callback(takeFilePathIds()); }); + QObject::connect(&m_timer, &Timer::timeout, [this, callback = std::move(callback)] { + callback(takeDirectoryPathIds()); + }); } unittest_public: @@ -88,9 +79,8 @@ unittest_public: } private: - FilePathIds m_filePaths; + DirectoryPathIds m_directoryPathIds; Timer m_timer; - FilePathCachingInterface &m_filePathCache; }; } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/directorypathid.h b/src/libs/clangsupport/directorypathid.h new file mode 100644 index 0000000000..2fd0b5847e --- /dev/null +++ b/src/libs/clangsupport/directorypathid.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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 <QDataStream> + +#include <vector> + +namespace ClangBackEnd { +class DirectoryPathId +{ +public: + constexpr DirectoryPathId() = default; + + DirectoryPathId(const char *) = delete; + + DirectoryPathId(int directoryPathId) + : directoryPathId(directoryPathId) + {} + + bool isValid() const { return directoryPathId >= 0; } + + friend bool operator==(DirectoryPathId first, DirectoryPathId second) + { + return first.isValid() && first.directoryPathId == second.directoryPathId; + } + + friend bool operator!=(DirectoryPathId first, DirectoryPathId second) + { + return !(first == second); + } + + friend bool operator<(DirectoryPathId first, DirectoryPathId second) + { + return first.directoryPathId < second.directoryPathId; + } + + friend QDataStream &operator<<(QDataStream &out, const DirectoryPathId &directoryPathId) + { + out << directoryPathId.directoryPathId; + + return out; + } + + friend QDataStream &operator>>(QDataStream &in, DirectoryPathId &directoryPathId) + { + in >> directoryPathId.directoryPathId; + + return in; + } + +public: + int directoryPathId = -1; +}; + +using DirectoryPathIds = std::vector<DirectoryPathId>; + +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/filepathcache.h b/src/libs/clangsupport/filepathcache.h index bdd925a79c..4845416d22 100644 --- a/src/libs/clangsupport/filepathcache.h +++ b/src/libs/clangsupport/filepathcache.h @@ -25,9 +25,10 @@ #pragma once +#include "directorypathid.h" +#include "filepath.h" #include "filepathexceptions.h" #include "filepathid.h" -#include "filepath.h" #include "filepathview.h" #include "stringcache.h" @@ -121,10 +122,10 @@ public: { Utils::SmallStringView directoryPath = filePath.directory(); - int directoryId = m_directoryPathCache.stringId(directoryPath, - [&] (const Utils::SmallStringView) { - return m_filePathStorage.fetchDirectoryId(directoryPath); - }); + int directoryId = m_directoryPathCache.stringId( + directoryPath, [&](const Utils::SmallStringView directoryPath) { + return m_filePathStorage.fetchDirectoryId(directoryPath); + }); Utils::SmallStringView fileName = filePath.name(); @@ -136,6 +137,17 @@ public: return fileNameId; } + DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const + { + Utils::SmallStringView path = directoryPath.back() == '/' + ? directoryPath.mid(0, directoryPath.size() - 1) + : directoryPath; + + return m_directoryPathCache.stringId(path, [&](const Utils::SmallStringView directoryPath) { + return m_filePathStorage.fetchDirectoryId(directoryPath); + }); + } + FilePath filePath(FilePathId filePathId) const { if (Q_UNLIKELY(!filePathId.isValid())) @@ -157,6 +169,32 @@ public: return FilePath{directoryPath, entry.fileName}; } + Utils::PathString directoryPath(DirectoryPathId directoryPathId) const + { + if (Q_UNLIKELY(!directoryPathId.isValid())) + throw NoDirectoryPathForInvalidDirectoryPathId(); + + auto fetchDirectoryPath = [&](int id) { return m_filePathStorage.fetchDirectoryPath(id); }; + + return m_directoryPathCache.string(directoryPathId.directoryPathId, fetchDirectoryPath); + } + + DirectoryPathId directoryPathId(FilePathId filePathId) const + { + if (Q_UNLIKELY(!filePathId.isValid())) + throw NoFilePathForInvalidFilePathId(); + + auto fetchSoureNameAndDirectoryId = [&](int id) { + auto entry = m_filePathStorage.fetchSourceNameAndDirectoryId(id); + return FileNameEntry{entry.sourceName, entry.directoryId}; + }; + + FileNameEntry entry = m_fileNameCache.string(filePathId.filePathId, + fetchSoureNameAndDirectoryId); + + return m_fileNameCache.string(filePathId.filePathId, fetchSoureNameAndDirectoryId).directoryId; + } + private: mutable DirectoryPathCache m_directoryPathCache; mutable FileNameCache m_fileNameCache; diff --git a/src/libs/clangsupport/filepathcaching.cpp b/src/libs/clangsupport/filepathcaching.cpp index 0a3fc6ee41..372ed86bd3 100644 --- a/src/libs/clangsupport/filepathcaching.cpp +++ b/src/libs/clangsupport/filepathcaching.cpp @@ -37,4 +37,19 @@ FilePath FilePathCaching::filePath(FilePathId filePathId) const return m_cache.filePath(filePathId); } +DirectoryPathId FilePathCaching::directoryPathId(Utils::SmallStringView directoryPath) const +{ + return m_cache.directoryPathId(directoryPath); +} + +Utils::PathString FilePathCaching::directoryPath(DirectoryPathId directoryPathId) const +{ + return m_cache.directoryPath(directoryPathId); +} + +DirectoryPathId FilePathCaching::directoryPathId(FilePathId filePathId) const +{ + return m_cache.directoryPathId(filePathId); +} + } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/filepathcaching.h b/src/libs/clangsupport/filepathcaching.h index a3337755fd..f69b940b15 100644 --- a/src/libs/clangsupport/filepathcaching.h +++ b/src/libs/clangsupport/filepathcaching.h @@ -50,6 +50,9 @@ public: FilePathId filePathId(FilePathView filePath) const override; FilePath filePath(FilePathId filePathId) const override; + DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const override; + Utils::PathString directoryPath(DirectoryPathId directoryPathId) const override; + DirectoryPathId directoryPathId(FilePathId filePathId) const override; private: Factory m_factory; diff --git a/src/libs/clangsupport/filepathcachinginterface.h b/src/libs/clangsupport/filepathcachinginterface.h index b9668362f7..098fd39ca9 100644 --- a/src/libs/clangsupport/filepathcachinginterface.h +++ b/src/libs/clangsupport/filepathcachinginterface.h @@ -25,6 +25,7 @@ #pragma once +#include "directorypathid.h" #include "filepath.h" #include "filepathid.h" #include "filepathview.h" @@ -40,8 +41,11 @@ public: virtual FilePathId filePathId(FilePathView filePath) const = 0; virtual FilePath filePath(FilePathId filePathId) const = 0; + virtual DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const = 0; + virtual DirectoryPathId directoryPathId(FilePathId filePathId) const = 0; + virtual Utils::PathString directoryPath(DirectoryPathId directoryPathId) const = 0; - template <typename Container> + template<typename Container> FilePathIds filePathIds(Container &&filePaths) const { FilePathIds filePathIds; diff --git a/src/libs/clangsupport/filepathexceptions.h b/src/libs/clangsupport/filepathexceptions.h index 80bded0c66..3174d89479 100644 --- a/src/libs/clangsupport/filepathexceptions.h +++ b/src/libs/clangsupport/filepathexceptions.h @@ -38,6 +38,15 @@ public: } }; +class NoDirectoryPathForInvalidDirectoryPathId : std::exception +{ +public: + const char *what() const noexcept override + { + return "You cannot get a directory path for an invalid directory path id!"; + } +}; + class SourceNameIdDoesNotExists : std::exception { public: diff --git a/src/libs/clangsupport/filepathstorage.h b/src/libs/clangsupport/filepathstorage.h index 5917504dbf..8aba2ef6d2 100644 --- a/src/libs/clangsupport/filepathstorage.h +++ b/src/libs/clangsupport/filepathstorage.h @@ -179,12 +179,32 @@ public: transaction.commit(); - return optionalSourceName.value(); + return *optionalSourceName; } catch (const Sqlite::StatementIsBusy &) { return fetchSourceNameAndDirectoryId(sourceId); } } + int fetchDirectoryId(int sourceId) + { + try { + Sqlite::DeferredTransaction transaction{m_statementFactory.database}; + + ReadStatement &statement = m_statementFactory.selectDirectoryIdFromSourcesBySourceId; + + auto optionalDirectoryId = statement.template value<int>(sourceId); + + if (!optionalDirectoryId) + throw SourceNameIdDoesNotExists(); + + transaction.commit(); + + return *optionalDirectoryId; + } catch (const Sqlite::StatementIsBusy &) { + return fetchDirectoryId(sourceId); + } + } + std::vector<Sources::Source> fetchAllSources() { try { diff --git a/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h b/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h index dbf8071775..27296a1df6 100644 --- a/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h +++ b/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h @@ -69,6 +69,8 @@ public: "SELECT sourceName, directoryId FROM sources WHERE sourceId = ?", database }; + ReadStatement selectDirectoryIdFromSourcesBySourceId{ + "SELECT directoryId FROM sources WHERE sourceId = ?", database}; WriteStatement insertIntoSources{ "INSERT INTO sources(directoryId, sourceName) VALUES (?,?)", database diff --git a/src/tools/clangrefactoringbackend/source/filestatus.h b/src/libs/clangsupport/filestatus.h index da2be4a304..da2be4a304 100644 --- a/src/tools/clangrefactoringbackend/source/filestatus.h +++ b/src/libs/clangsupport/filestatus.h diff --git a/src/libs/clangsupport/filestatuscache.cpp b/src/libs/clangsupport/filestatuscache.cpp new file mode 100644 index 0000000000..e8ed50a833 --- /dev/null +++ b/src/libs/clangsupport/filestatuscache.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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. +** +****************************************************************************/ + +#include "filestatuscache.h" +#include "filesystem.h" + +#include <set_algorithm.h> + +#include <utils/algorithm.h> + +#include <QDateTime> +#include <QFileInfo> + +namespace ClangBackEnd { + +long long FileStatusCache::lastModifiedTime(FilePathId filePathId) const +{ + return findEntry(filePathId).lastModified; +} + +void FileStatusCache::update(FilePathId filePathId) +{ + auto found = std::lower_bound(m_cacheEntries.begin(), + m_cacheEntries.end(), + Internal::FileStatusCacheEntry{filePathId}, + [] (const auto &first, const auto &second) { + return first.filePathId < second.filePathId; + }); + + if (found != m_cacheEntries.end() && found->filePathId == filePathId) + found->lastModified = m_fileSystem.lastModified(filePathId); +} + +void FileStatusCache::update(FilePathIds filePathIds) +{ + std::set_intersection(m_cacheEntries.begin(), + m_cacheEntries.end(), + filePathIds.begin(), + filePathIds.end(), + make_iterator([&](auto &entry) { + entry.lastModified = m_fileSystem.lastModified(entry.filePathId); + })); +} + +FilePathIds FileStatusCache::modified(FilePathIds filePathIds) const +{ + FilePathIds modifiedFilePathIds; + modifiedFilePathIds.reserve(filePathIds.size()); + + std::set_intersection(m_cacheEntries.begin(), + m_cacheEntries.end(), + filePathIds.begin(), + filePathIds.end(), + make_iterator([&](auto &entry) { + auto newLastModified = m_fileSystem.lastModified(entry.filePathId); + if (newLastModified > entry.lastModified) { + modifiedFilePathIds.push_back(entry.filePathId); + entry.lastModified = newLastModified; + } + })); + + Internal::FileStatusCacheEntries newEntries; + newEntries.reserve(filePathIds.size()); + + std::set_difference(filePathIds.begin(), + filePathIds.end(), + m_cacheEntries.begin(), + m_cacheEntries.end(), + make_iterator([&](FilePathId newFilePathId) { + newEntries.emplace_back(newFilePathId, + m_fileSystem.lastModified(newFilePathId)); + modifiedFilePathIds.push_back(newFilePathId); + })); + + if (newEntries.size()) { + Internal::FileStatusCacheEntries mergedEntries; + mergedEntries.reserve(m_cacheEntries.size() + newEntries.size()); + + std::set_union(newEntries.begin(), + newEntries.end(), + m_cacheEntries.begin(), + m_cacheEntries.end(), + std::back_inserter(mergedEntries)); + + m_cacheEntries = std::move(mergedEntries); + } + + std::sort(modifiedFilePathIds.begin(), modifiedFilePathIds.end()); + + return modifiedFilePathIds; +} + +FileStatusCache::size_type FileStatusCache::size() const +{ + return m_cacheEntries.size(); +} + +Internal::FileStatusCacheEntry FileStatusCache::findEntry(FilePathId filePathId) const +{ + auto found = std::lower_bound(m_cacheEntries.begin(), + m_cacheEntries.end(), + Internal::FileStatusCacheEntry{filePathId}, + [] (const auto &first, const auto &second) { + return first.filePathId < second.filePathId; + }); + + if (found != m_cacheEntries.end() && found->filePathId == filePathId) + return *found; + + auto inserted = m_cacheEntries.emplace(found, filePathId, m_fileSystem.lastModified(filePathId)); + + return *inserted; +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/filestatuscache.h b/src/libs/clangsupport/filestatuscache.h index 23195da605..3f0af56b3a 100644 --- a/src/tools/clangrefactoringbackend/source/filestatuscache.h +++ b/src/libs/clangsupport/filestatuscache.h @@ -31,6 +31,8 @@ QT_FORWARD_DECLARE_CLASS(QFileInfo) namespace ClangBackEnd { +class FileSystemInterface; + namespace Internal { class FileStatusCacheEntry { @@ -41,8 +43,23 @@ public: lastModified(lastModified) {} + friend bool operator<(FileStatusCacheEntry first, FileStatusCacheEntry second) + { + return first.filePathId < second.filePathId; + } + + friend bool operator<(FileStatusCacheEntry first, FilePathId second) + { + return first.filePathId < second; + } + + friend bool operator<(FilePathId first, FileStatusCacheEntry second) + { + return first < second.filePathId; + } + public: - ClangBackEnd::FilePathId filePathId; + FilePathId filePathId; long long lastModified; }; @@ -50,27 +67,30 @@ using FileStatusCacheEntries = std::vector<FileStatusCacheEntry>; } -class FileStatusCache +class CLANGSUPPORT_EXPORT FileStatusCache { public: using size_type = Internal::FileStatusCacheEntries::size_type; - FileStatusCache(FilePathCachingInterface &filePathCache); + FileStatusCache(FileSystemInterface &fileSystem) + : m_fileSystem(fileSystem) + {} FileStatusCache &operator=(const FileStatusCache &) = delete; FileStatusCache(const FileStatusCache &) = delete; - long long lastModifiedTime(ClangBackEnd::FilePathId filePathId) const; - void update(ClangBackEnd::FilePathId filePathId); + long long lastModifiedTime(FilePathId filePathId) const; + void update(FilePathId filePathId); + void update(FilePathIds filePathIds); + FilePathIds modified(FilePathIds filePathIds) const; size_type size() const; private: - Internal::FileStatusCacheEntry findEntry(ClangBackEnd::FilePathId filePathId) const; - QFileInfo qFileInfo(ClangBackEnd::FilePathId filePathId) const; + Internal::FileStatusCacheEntry findEntry(FilePathId filePathId) const; private: mutable Internal::FileStatusCacheEntries m_cacheEntries; - FilePathCachingInterface &m_filePathCache; + FileSystemInterface &m_fileSystem; }; } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/filesystem.cpp b/src/libs/clangsupport/filesystem.cpp new file mode 100644 index 0000000000..5b8c037f80 --- /dev/null +++ b/src/libs/clangsupport/filesystem.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "filesystem.h" +#include "filepathcachinginterface.h" + +#include <utils/algorithm.h> + +#include <QDateTime> +#include <QDir> +#include <QFileInfo> + +namespace ClangBackEnd { + +FilePathIds FileSystem::directoryEntries(const QString &directoryPath) const +{ + QDir directory{directoryPath}; + + QFileInfoList fileInfos = directory.entryInfoList(); + + FilePathIds filePathIds = Utils::transform<FilePathIds>(fileInfos, [&](const QFileInfo &fileInfo) { + return m_filePathCache.filePathId(FilePath{fileInfo.path()}); + }); + + std::sort(filePathIds.begin(), filePathIds.end()); + + return filePathIds; +} + +long long FileSystem::lastModified(FilePathId filePathId) const +{ + QFileInfo fileInfo(QString(m_filePathCache.filePath(filePathId))); + + fileInfo.refresh(); + + return fileInfo.lastModified().toMSecsSinceEpoch() / 1000; +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/filesystem.h b/src/libs/clangsupport/filesystem.h new file mode 100644 index 0000000000..ecf332de55 --- /dev/null +++ b/src/libs/clangsupport/filesystem.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** 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 "filestatuscache.h" +#include "filesysteminterface.h" + +namespace ClangBackEnd { +class FilePathCachingInterface; + +class CLANGSUPPORT_EXPORT FileSystem final : public FileSystemInterface +{ +public: + FileSystem(FilePathCachingInterface &filePathCache) + : m_filePathCache(filePathCache) + {} + + FilePathIds directoryEntries(const QString &directoryPath) const override; + long long lastModified(FilePathId filePathId) const override; + +private: + FilePathCachingInterface &m_filePathCache; +}; + +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/filesysteminterface.h b/src/libs/clangsupport/filesysteminterface.h new file mode 100644 index 0000000000..9d64d2a93a --- /dev/null +++ b/src/libs/clangsupport/filesysteminterface.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** 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" + +#include <utils/smallstringview.h> + +namespace ClangBackEnd { + +class FileSystemInterface +{ +public: + virtual FilePathIds directoryEntries(const QString &directoryPath) const = 0; + virtual long long lastModified(FilePathId filePathId) const = 0; + +protected: + ~FileSystemInterface() = default; +}; +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/modifiedtimechecker.h b/src/libs/clangsupport/modifiedtimechecker.h index c9b62c4673..00e8e3ebac 100644 --- a/src/libs/clangsupport/modifiedtimechecker.h +++ b/src/libs/clangsupport/modifiedtimechecker.h @@ -25,23 +25,23 @@ #pragma once -#include "filepathcachinginterface.h" +#include "filesysteminterface.h" #include "modifiedtimecheckerinterface.h" +#include "set_algorithm.h" #include <algorithm> #include <iterator> namespace ClangBackEnd { + template<typename SourceEntries = ::ClangBackEnd::SourceEntries> class ModifiedTimeChecker final : public ModifiedTimeCheckerInterface<SourceEntries> { using SourceEntry = typename SourceEntries::value_type; public: - using GetModifiedTime = std::function<ClangBackEnd::TimeStamp(ClangBackEnd::FilePathView filePath)>; - ModifiedTimeChecker(GetModifiedTime &getModifiedTime, FilePathCachingInterface &filePathCache) - : m_getModifiedTime(getModifiedTime) - , m_filePathCache(filePathCache) + ModifiedTimeChecker(FileSystemInterface &fileSystem) + : m_fileSystem(fileSystem) {} bool isUpToDate(const SourceEntries &sourceEntries) const @@ -51,165 +51,101 @@ public: updateCurrentSourceTimeStamps(sourceEntries); - return compareEntries(sourceEntries); + return compareEntries(sourceEntries) && notReseted(sourceEntries); } - void pathsChanged(const FilePathIds &filePathIds) + void pathsChanged(const FilePathIds &filePathIds) override { - using SourceTimeStampReferences = std::vector<std::reference_wrapper<SourceTimeStamp>>; - - SourceTimeStampReferences timeStampsToUpdate; - timeStampsToUpdate.reserve(filePathIds.size()); - std::set_intersection(m_currentSourceTimeStamps.begin(), m_currentSourceTimeStamps.end(), filePathIds.begin(), filePathIds.end(), - std::back_inserter(timeStampsToUpdate)); + make_iterator([&](SourceTimeStamp &sourceTimeStamp) { + sourceTimeStamp.timeStamp = m_fileSystem.lastModified( + sourceTimeStamp.sourceId); + })); + } + + void reset(const FilePathIds &filePathIds) + { + FilePathIds newResetFilePathIds; + newResetFilePathIds.reserve(newResetFilePathIds.size() + m_resetFilePathIds.size()); + + std::set_union(m_resetFilePathIds.begin(), + m_resetFilePathIds.end(), + filePathIds.begin(), + filePathIds.end(), + std::back_inserter(newResetFilePathIds)); - for (SourceTimeStamp &sourceTimeStamp : timeStampsToUpdate) { - sourceTimeStamp.timeStamp = m_getModifiedTime( - m_filePathCache.filePath(sourceTimeStamp.sourceId)); - } + m_resetFilePathIds = std::move(newResetFilePathIds); } private: bool compareEntries(const SourceEntries &sourceEntries) const { - class CompareSourceId - { - public: - bool operator()(SourceTimeStamp first, SourceTimeStamp second) - { - return first.sourceId < second.sourceId; - } - - bool operator()(::ClangBackEnd::SourceEntry first, ::ClangBackEnd::SourceEntry second) - { - return first.sourceId < second.sourceId; - } - - bool operator()(SourceTimeStamp first, ::ClangBackEnd::SourceEntry second) - { - return first.sourceId < second.sourceId; - } - - bool operator()(::ClangBackEnd::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), - CompareSourceId{}); - - class CompareTime - { - public: - bool operator()(SourceTimeStamp first, SourceTimeStamp second) - { - return first.timeStamp <= second.timeStamp; - } - - bool operator()(::ClangBackEnd::SourceEntry first, ::ClangBackEnd::SourceEntry second) - { - return first.timeStamp <= second.timeStamp; - } - - bool operator()(SourceTimeStamp first, ::ClangBackEnd::SourceEntry second) - { - return first.timeStamp <= second.timeStamp; - } - - bool operator()(::ClangBackEnd::SourceEntry first, SourceTimeStamp second) - { - return first.timeStamp <= second.timeStamp; - } - }; - - return std::lexicographical_compare(currentSourceTimeStamp.begin(), - currentSourceTimeStamp.end(), - sourceEntries.begin(), - sourceEntries.end(), - CompareTime{}); + return set_intersection_compare( + m_currentSourceTimeStamps.begin(), + m_currentSourceTimeStamps.end(), + sourceEntries.begin(), + sourceEntries.end(), + [](auto first, auto second) { return second.timeStamp > first.timeStamp; }, + [](auto first, auto second) { return first.sourceId < second.sourceId; }); } void updateCurrentSourceTimeStamps(const SourceEntries &sourceEntries) const { SourceTimeStamps sourceTimeStamps = newSourceTimeStamps(sourceEntries); - for (SourceTimeStamp &newSourceTimeStamp : sourceTimeStamps) { - newSourceTimeStamp.timeStamp = m_getModifiedTime( - m_filePathCache.filePath(newSourceTimeStamp.sourceId)); - } - auto split = sourceTimeStamps.insert(sourceTimeStamps.end(), m_currentSourceTimeStamps.begin(), m_currentSourceTimeStamps.end()); std::inplace_merge(sourceTimeStamps.begin(), split, sourceTimeStamps.end()); - m_currentSourceTimeStamps = sourceTimeStamps; + m_currentSourceTimeStamps = std::move(sourceTimeStamps); } SourceTimeStamps newSourceTimeStamps(const SourceEntries &sourceEntries) const { - SourceEntries newSourceEntries; - newSourceEntries.reserve(sourceEntries.size()); - - class CompareSourceId - { - public: - bool operator()(SourceTimeStamp first, SourceTimeStamp second) - { - return first.sourceId < second.sourceId; - } - - bool operator()(::ClangBackEnd::SourceEntry first, ::ClangBackEnd::SourceEntry second) - { - return first.sourceId < second.sourceId; - } - - bool operator()(SourceTimeStamp first, ::ClangBackEnd::SourceEntry second) - { - return first.sourceId < second.sourceId; - } - - bool operator()(::ClangBackEnd::SourceEntry first, SourceTimeStamp second) - { - return first.sourceId < second.sourceId; - } - }; + SourceTimeStamps newTimeStamps; + newTimeStamps.reserve(sourceEntries.size()); std::set_difference(sourceEntries.begin(), sourceEntries.end(), m_currentSourceTimeStamps.begin(), m_currentSourceTimeStamps.end(), - std::back_inserter(newSourceEntries), - CompareSourceId{}); + make_iterator([&](const SourceEntry &sourceEntry) { + newTimeStamps.emplace_back(sourceEntry.sourceId, + m_fileSystem.lastModified( + sourceEntry.sourceId)); + }), + [](auto first, auto second) { + return first.sourceId < second.sourceId && first.timeStamp > 0; + }); - SourceTimeStamps newTimeStamps; - newTimeStamps.reserve(newSourceEntries.size()); + return newTimeStamps; + } - std::transform(newSourceEntries.begin(), - newSourceEntries.end(), - std::back_inserter(newTimeStamps), - [](SourceEntry entry) { - return SourceTimeStamp{entry.sourceId, {}}; - }); + bool notReseted(const SourceEntries &sourceEntries) const + { + auto oldSize = m_resetFilePathIds.size(); + FilePathIds newResetFilePathIds; + newResetFilePathIds.reserve(newResetFilePathIds.size()); - return newTimeStamps; + std::set_difference(m_resetFilePathIds.begin(), + m_resetFilePathIds.end(), + sourceEntries.begin(), + sourceEntries.end(), + std::back_inserter(newResetFilePathIds)); + + m_resetFilePathIds = std::move(newResetFilePathIds); + + return oldSize == m_resetFilePathIds.size(); } private: mutable SourceTimeStamps m_currentSourceTimeStamps; - GetModifiedTime &m_getModifiedTime; - FilePathCachingInterface &m_filePathCache; + mutable FilePathIds m_resetFilePathIds; + FileSystemInterface &m_fileSystem; }; } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/modifiedtimecheckerinterface.h b/src/libs/clangsupport/modifiedtimecheckerinterface.h index a0e79b0701..b48c38869e 100644 --- a/src/libs/clangsupport/modifiedtimecheckerinterface.h +++ b/src/libs/clangsupport/modifiedtimecheckerinterface.h @@ -38,6 +38,7 @@ public: ModifiedTimeCheckerInterface &operator=(const ModifiedTimeCheckerInterface &) = delete; virtual bool isUpToDate(const SourceEntries &sourceEntries) const = 0; + virtual void pathsChanged(const FilePathIds &filePathIds) = 0; protected: ~ModifiedTimeCheckerInterface() = default; diff --git a/src/libs/clangsupport/refactoringdatabaseinitializer.h b/src/libs/clangsupport/refactoringdatabaseinitializer.h index a7058d3204..6042264a5d 100644 --- a/src/libs/clangsupport/refactoringdatabaseinitializer.h +++ b/src/libs/clangsupport/refactoringdatabaseinitializer.h @@ -144,11 +144,11 @@ public: table.setName("projectPartsFiles"); 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); + const Sqlite::Column &sourceType = 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}); + table.addIndex({projectPartIdColumn, sourceType}); table.initialize(database); } diff --git a/src/libs/clangsupport/set_algorithm.h b/src/libs/clangsupport/set_algorithm.h new file mode 100644 index 0000000000..39bd3a2055 --- /dev/null +++ b/src/libs/clangsupport/set_algorithm.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** 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 <algorithm> + +namespace ClangBackEnd { + +template<class Callable> +class function_output_iterator +{ +public: + typedef std::output_iterator_tag iterator_category; + typedef void value_type; + typedef void difference_type; + typedef void pointer; + typedef void reference; + + explicit function_output_iterator() {} + + explicit function_output_iterator(const Callable &callable) + : m_callable(&callable) + {} + + function_output_iterator &operator=(const function_output_iterator &iterator) + { + m_callable = iterator.m_callable; + + return *this; + } + + struct helper + { + helper(const Callable *callable) + : m_callable(callable) + {} + template<class T> + helper &operator=(T &&value) + { + (*m_callable)(std::forward<T>(value)); + return *this; + } + const Callable *m_callable; + }; + + helper operator*() { return helper(m_callable); } + function_output_iterator &operator++() { return *this; } + function_output_iterator &operator++(int) { return *this; } + +private: + const Callable *m_callable; +}; + +template<typename Callable> +function_output_iterator<Callable> make_iterator(const Callable &callable) +{ + return function_output_iterator<Callable>(callable); +} + +template<class InputIt1, class InputIt2, class Callable, class Compare> +bool set_intersection_compare( + InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable call, Compare comp) +{ + while (first1 != last1 && first2 != last2) { + if (comp(*first1, *first2)) { + ++first1; + } else { + if (!comp(*first2, *first1)) { + if (call(*first2, *first1++)) + return false; + } + ++first2; + } + } + + return true; +} +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/sourceentry.h b/src/libs/clangsupport/sourceentry.h index c593f1fcd3..5e8769d14f 100644 --- a/src/libs/clangsupport/sourceentry.h +++ b/src/libs/clangsupport/sourceentry.h @@ -131,6 +131,10 @@ public: return first.sourceId < second.sourceId; } + friend bool operator<(SourceEntry first, FilePathId second) { return first.sourceId < second; } + + friend bool operator<(FilePathId first, SourceEntry second) { return first < second.sourceId; } + friend bool operator==(SourceEntry first, SourceEntry second) { return first.sourceId == second.sourceId && first.sourceType == second.sourceType diff --git a/src/libs/languageserverprotocol/icontent.h b/src/libs/languageserverprotocol/icontent.h index af14604739..1b57165b2e 100644 --- a/src/libs/languageserverprotocol/icontent.h +++ b/src/libs/languageserverprotocol/icontent.h @@ -92,7 +92,7 @@ using ResponseHandler = std::function<void(const QByteArray &, QTextCodec *)>; using ResponseHandlers = std::function<void(MessageId, const QByteArray &, QTextCodec *)>; using MethodHandler = std::function<void(const QString, MessageId, const IContent *)>; -inline LANGUAGESERVERPROTOCOL_EXPORT uint qHash(const LanguageServerProtocol::MessageId &id) +inline uint qHash(const LanguageServerProtocol::MessageId &id) { if (Utils::holds_alternative<int>(id)) return QT_PREPEND_NAMESPACE(qHash(Utils::get<int>(id))); @@ -102,8 +102,7 @@ inline LANGUAGESERVERPROTOCOL_EXPORT uint qHash(const LanguageServerProtocol::Me } template <typename Error> -inline LANGUAGESERVERPROTOCOL_EXPORT QDebug operator<<(QDebug stream, - const LanguageServerProtocol::MessageId &id) +inline QDebug operator<<(QDebug stream, const LanguageServerProtocol::MessageId &id) { if (Utils::holds_alternative<int>(id)) stream << Utils::get<int>(id); diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index deb95ea1d3..e5243830cd 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -1676,7 +1676,7 @@ bool Check::visit(CallExpression *ast) if (!whiteListedFunction && !isMathFunction && !isDateFunction && !isDirectInConnectionsScope) addMessage(ErrFunctionsNotSupportedInQmlUi, location); - static const QStringList globalFunctions = {"String", "Boolean", "Date", "Number", "Object", "QT_TR_NOOP", "QT_TRANSLATE_NOOP", "QT_TRID_NOOP"}; + static const QStringList globalFunctions = {"String", "Boolean", "Date", "Number", "Object", "Array", "QT_TR_NOOP", "QT_TRANSLATE_NOOP", "QT_TRID_NOOP"}; if (!name.isEmpty() && name.at(0).isUpper() && !globalFunctions.contains(name)) { addMessage(WarnExpectedNewWithUppercaseFunction, location); diff --git a/src/libs/utils/smallstringview.h b/src/libs/utils/smallstringview.h index 6052ff8777..911ba2eafd 100644 --- a/src/libs/utils/smallstringview.h +++ b/src/libs/utils/smallstringview.h @@ -179,6 +179,10 @@ public: return m_pointer[0] == characterToSearch; } + char back() const { return m_pointer[m_size - 1]; } + + char operator[](std::size_t index) { return m_pointer[index]; } + private: const char *m_pointer = ""; size_type m_size = 0; diff --git a/src/plugins/autotest/autotestunittests.cpp b/src/plugins/autotest/autotestunittests.cpp index eeeeb599de..614a61a6c2 100644 --- a/src/plugins/autotest/autotestunittests.cpp +++ b/src/plugins/autotest/autotestunittests.cpp @@ -77,8 +77,9 @@ void AutoTestUnitTests::initTestCase() if (!qgetenv("BOOST_INCLUDE_DIR").isEmpty()) { m_checkBoost = true; } else { - if (QFileInfo::exists("/usr/include/boost/version.hpp") - || QFileInfo::exists("/usr/local/include/boost/version.hpp")) { + if (Utils::HostOsInfo::isLinuxHost() + && (QFileInfo::exists("/usr/include/boost/version.hpp") + || QFileInfo::exists("/usr/local/include/boost/version.hpp"))) { qDebug() << "Found boost at system level - will run boost parser test."; m_checkBoost = true; } diff --git a/src/plugins/autotest/boost/boosttestoutputreader.h b/src/plugins/autotest/boost/boosttestoutputreader.h index e16c1fb996..91c38cb62f 100644 --- a/src/plugins/autotest/boost/boosttestoutputreader.h +++ b/src/plugins/autotest/boost/boosttestoutputreader.h @@ -37,6 +37,7 @@ enum class ReportLevel; class BoostTestOutputReader : public TestOutputReader { + Q_OBJECT public: BoostTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface, QProcess *testApplication, const QString &buildDirectory, diff --git a/src/plugins/baremetal/iarewtoolchain.cpp b/src/plugins/baremetal/iarewtoolchain.cpp index f18bcdaa8b..ad70d78b16 100644 --- a/src/plugins/baremetal/iarewtoolchain.cpp +++ b/src/plugins/baremetal/iarewtoolchain.cpp @@ -411,9 +411,9 @@ QList<ToolChain *> IarToolChainFactory::autoDetect(const QList<ToolChain *> &alr QString registryKey; QString subExePath; } knowToolchains[] = { - {"EWARM", "\\arm\\bin\\iccarm.exe"}, - {"EWAVR", "\\avr\\bin\\iccavr.exe"}, - {"EW8051", "\\8051\\bin\\icc8051.exe"}, + {{"EWARM"}, {"\\arm\\bin\\iccarm.exe"}}, + {{"EWAVR"}, {"\\avr\\bin\\iccavr.exe"}}, + {{"EW8051"}, {"\\8051\\bin\\icc8051.exe"}}, }; QSettings registry(kRegistryNode, QSettings::NativeFormat); diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp index c8f7d9f7d1..403433aec6 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp @@ -144,7 +144,7 @@ void ClangCodeModelPlugin::createCompilationDBButton() message = tr("Clang compilation database generated at \"%1\".") .arg(QDir::toNativeSeparators(result.filePath)); } else { - message = tr("Generating clang compilation database failed: %1").arg(result.error); + message = tr("Generating Clang compilation database failed: %1").arg(result.error); } Core::MessageManager::write(message, Core::MessageManager::Flash); m_generateCompilationDBAction->setEnabled( diff --git a/src/plugins/clangtools/clangselectablefilesdialog.cpp b/src/plugins/clangtools/clangselectablefilesdialog.cpp index e48679aa05..c6ad76ff0a 100644 --- a/src/plugins/clangtools/clangselectablefilesdialog.cpp +++ b/src/plugins/clangtools/clangselectablefilesdialog.cpp @@ -295,6 +295,7 @@ SelectableFilesDialog::SelectableFilesDialog(const ProjectInfo &projectInfo, CppTools::ClangDiagnosticConfigsSelectionWidget *diagnosticConfigsSelectionWidget = m_ui->clangToolsBasicSettings->ui()->clangDiagnosticConfigsSelectionWidget; QCheckBox *buildBeforeAnalysis = m_ui->clangToolsBasicSettings->ui()->buildBeforeAnalysis; + buildBeforeAnalysis->setToolTip(hintAboutBuildBeforeAnalysis()); ClangToolsProjectSettings *settings = ClangToolsProjectSettingsManager::getSettings(m_project); m_customDiagnosticConfig = diagnosticConfiguration(settings); @@ -337,6 +338,8 @@ SelectableFilesDialog::SelectableFilesDialog(const ProjectInfo &projectInfo, m_customDiagnosticConfig = currentConfigId; }); connect(buildBeforeAnalysis, &QCheckBox::toggled, [this](bool checked) { + if (!checked) + showHintAboutBuildBeforeAnalysis(); if (m_ui->globalOrCustom->currentIndex() == CustomSettings) m_buildBeforeAnalysis = checked; }); diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp index b1572b0010..0c2ca841e6 100644 --- a/src/plugins/clangtools/clangtoolruncontrol.cpp +++ b/src/plugins/clangtools/clangtoolruncontrol.cpp @@ -477,6 +477,16 @@ void ClangToolRunControl::finalize() if (m_filesNotAnalyzed != 0) { QString msg = tr("%1: Not all files could be analyzed.").arg(toolName); TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID); + if (m_target && !m_target->activeBuildConfiguration()->buildDirectory().exists() + && !ClangToolsProjectSettingsManager::getSettings(m_target->project()) + ->buildBeforeAnalysis()) { + msg = tr("%1: You might need to build the project to generate or update source " + "files. To build automatically, enable \"Build the project before starting " + "analysis\".") + .arg(toolName); + TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID); + } + TaskHub::requestPopup(); } diff --git a/src/plugins/clangtools/clangtoolsconfigwidget.cpp b/src/plugins/clangtools/clangtoolsconfigwidget.cpp index ad966ab518..b634875f97 100644 --- a/src/plugins/clangtools/clangtoolsconfigwidget.cpp +++ b/src/plugins/clangtools/clangtoolsconfigwidget.cpp @@ -56,9 +56,12 @@ ClangToolsConfigWidget::ClangToolsConfigWidget( [settings](int count) { settings->setSimultaneousProcesses(count); }); QCheckBox *buildBeforeAnalysis = m_ui->clangToolsBasicSettings->ui()->buildBeforeAnalysis; + buildBeforeAnalysis->setToolTip(hintAboutBuildBeforeAnalysis()); buildBeforeAnalysis->setCheckState(settings->savedBuildBeforeAnalysis() ? Qt::Checked : Qt::Unchecked); connect(buildBeforeAnalysis, &QCheckBox::toggled, [settings](bool checked) { + if (!checked) + showHintAboutBuildBeforeAnalysis(); settings->setBuildBeforeAnalysis(checked); }); diff --git a/src/plugins/clangtools/clangtoolsprojectsettings.cpp b/src/plugins/clangtools/clangtoolsprojectsettings.cpp index bc8a3cabb6..55573c8ee6 100644 --- a/src/plugins/clangtools/clangtoolsprojectsettings.cpp +++ b/src/plugins/clangtools/clangtoolsprojectsettings.cpp @@ -87,7 +87,9 @@ void ClangToolsProjectSettings::load() m_useGlobalSettings = useGlobalVariant.isValid() ? useGlobalVariant.toBool() : true; m_diagnosticConfig = Core::Id::fromSetting( m_project->namedSettings(SETTINGS_KEY_DIAGNOSTIC_CONFIG)); - m_buildBeforeAnalysis = m_project->namedSettings(SETTINGS_KEY_BUILD_BEFORE_ANALYSIS).toBool(); + + const QVariant value = m_project->namedSettings(SETTINGS_KEY_BUILD_BEFORE_ANALYSIS); + m_buildBeforeAnalysis = value.isValid() ? value.toBool() : true; auto toFileName = [](const QString &s) { return Utils::FilePath::fromString(s); }; diff --git a/src/plugins/clangtools/clangtoolsutils.cpp b/src/plugins/clangtools/clangtoolsutils.cpp index 3e811500ac..173d97e31d 100644 --- a/src/plugins/clangtools/clangtoolsutils.cpp +++ b/src/plugins/clangtools/clangtoolsutils.cpp @@ -25,6 +25,7 @@ #include "clangtoolsutils.h" +#include "clangtool.h" #include "clangtoolsdiagnostic.h" #include "clangtoolssettings.h" @@ -32,8 +33,9 @@ #include <projectexplorer/projectexplorerconstants.h> -#include <utils/hostosinfo.h> +#include <utils/checkablemessagebox.h> #include <utils/environment.h> +#include <utils/hostosinfo.h> #include <utils/synchronousprocess.h> #include <QCoreApplication> @@ -49,5 +51,24 @@ QString createFullLocationString(const Debugger::DiagnosticLocation &location) + QLatin1Char(':') + QString::number(location.column); } +QString hintAboutBuildBeforeAnalysis() +{ + return ClangTool::tr( + "In general, the project should be built before starting the analysis to ensure that the " + "code to analyze is valid.<br/><br/>" + "Building the project might also run code generators that update the source files as " + "necessary."); +} + +void showHintAboutBuildBeforeAnalysis() +{ + Utils::CheckableMessageBox::doNotShowAgainInformation( + Core::ICore::dialogParent(), + ClangTool::tr("Info About Build the Project Before Analysis"), + hintAboutBuildBeforeAnalysis(), + Core::ICore::settings(), + "ClangToolsDisablingBuildBeforeAnalysisHint"); +} + } // namespace Internal } // namespace ClangTools diff --git a/src/plugins/clangtools/clangtoolsutils.h b/src/plugins/clangtools/clangtoolsutils.h index 6d3a7a90ca..05acb953c5 100644 --- a/src/plugins/clangtools/clangtoolsutils.h +++ b/src/plugins/clangtools/clangtoolsutils.h @@ -41,5 +41,8 @@ namespace Internal { QString createFullLocationString(const Debugger::DiagnosticLocation &location); +QString hintAboutBuildBeforeAnalysis(); +void showHintAboutBuildBeforeAnalysis(); + } // namespace Internal } // namespace ClangTools diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 813d12739d..f1073e6bb2 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -2429,12 +2429,12 @@ void EditorManager::closeOtherDocuments(IDocument *document) closeDocuments(documentsToClose, true); } -void EditorManager::closeAllDocuments() +bool EditorManager::closeAllDocuments() { // Only close the files that aren't pinned. const QList<DocumentModel::Entry *> entriesToClose = Utils::filtered(DocumentModel::entries(), Utils::equal(&DocumentModel::Entry::pinned, false)); - EditorManager::closeDocuments(entriesToClose); + return EditorManager::closeDocuments(entriesToClose); } // SLOT connected to action @@ -2631,7 +2631,7 @@ void EditorManager::closeDocument(DocumentModel::Entry *entry) closeDocuments({entry->document}); } -void EditorManager::closeDocuments(const QList<DocumentModel::Entry *> &entries) +bool EditorManager::closeDocuments(const QList<DocumentModel::Entry *> &entries) { QList<IDocument *> documentsToClose; for (DocumentModel::Entry *entry : entries) { @@ -2642,7 +2642,7 @@ void EditorManager::closeDocuments(const QList<DocumentModel::Entry *> &entries) else documentsToClose << entry->document; } - closeDocuments(documentsToClose); + return closeDocuments(documentsToClose); } bool EditorManager::closeEditors(const QList<IEditor*> &editorsToClose, bool askAboutModifiedEditors) diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h index 41429aedb1..5be379ceb2 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.h +++ b/src/plugins/coreplugin/editormanager/editormanager.h @@ -128,9 +128,9 @@ public: static bool closeDocument(IDocument *document, bool askAboutModifiedEditors = true); static bool closeDocuments(const QList<IDocument *> &documents, bool askAboutModifiedEditors = true); static void closeDocument(DocumentModel::Entry *entry); - static void closeDocuments(const QList<DocumentModel::Entry *> &entries); + static bool closeDocuments(const QList<DocumentModel::Entry *> &entries); static void closeOtherDocuments(IDocument *document); - static void closeAllDocuments(); + static bool closeAllDocuments(); static void addCurrentPositionToNavigationHistory(const QByteArray &saveState = QByteArray()); static void cutForwardNavigationHistory(); diff --git a/src/plugins/coreplugin/idocument.cpp b/src/plugins/coreplugin/idocument.cpp index 8fde404064..aab9845f1a 100644 --- a/src/plugins/coreplugin/idocument.cpp +++ b/src/plugins/coreplugin/idocument.cpp @@ -79,7 +79,6 @@ public: bool hasWriteWarning = false; bool restored = false; bool isSuspendAllowed = false; - bool pinned = false; }; } // namespace Internal diff --git a/src/plugins/coreplugin/ioutputpane.h b/src/plugins/coreplugin/ioutputpane.h index d219e2aeff..b7800a65c8 100644 --- a/src/plugins/coreplugin/ioutputpane.h +++ b/src/plugins/coreplugin/ioutputpane.h @@ -41,6 +41,8 @@ class QWidget; QT_END_NAMESPACE namespace Core { +class CommandButton; +class IContext; class CORE_EXPORT IOutputPane : public QObject { @@ -93,6 +95,7 @@ signals: void setBadgeNumber(int number); void zoomIn(int range); void zoomOut(int range); + void resetZoom(); void wheelZoomEnabledChanged(bool enabled); void fontChanged(const QFont &font); @@ -103,7 +106,7 @@ protected: Qt::CaseSensitivity filterCaseSensitivity() const { return m_filterCaseSensitivity; } void setFilteringEnabled(bool enable); QWidget *filterWidget() const { return m_filterOutputLineEdit; } - + void setupContext(const char *context, QWidget *widget); void setZoomButtonsEnabled(bool enabled); private: @@ -115,11 +118,12 @@ private: Id filterRegexpActionId() const; Id filterCaseSensitivityActionId() const; - QToolButton * const m_zoomInButton = nullptr; - QToolButton * const m_zoomOutButton = nullptr; + Core::CommandButton * const m_zoomInButton; + Core::CommandButton * const m_zoomOutButton; QAction *m_filterActionRegexp = nullptr; QAction *m_filterActionCaseSensitive = nullptr; Utils::FancyLineEdit *m_filterOutputLineEdit = nullptr; + IContext *m_context = nullptr; bool m_filterRegexp = false; Qt::CaseSensitivity m_filterCaseSensitivity = Qt::CaseInsensitive; }; diff --git a/src/plugins/coreplugin/messageoutputwindow.cpp b/src/plugins/coreplugin/messageoutputwindow.cpp index 7aabaefbbc..c7c752e155 100644 --- a/src/plugins/coreplugin/messageoutputwindow.cpp +++ b/src/plugins/coreplugin/messageoutputwindow.cpp @@ -56,6 +56,7 @@ MessageOutputWindow::MessageOutputWindow() connect(this, &IOutputPane::zoomIn, m_widget, &Core::OutputWindow::zoomIn); connect(this, &IOutputPane::zoomOut, m_widget, &Core::OutputWindow::zoomOut); + connect(this, &IOutputPane::resetZoom, m_widget, &Core::OutputWindow::resetZoom); connect(this, &IOutputPane::fontChanged, m_widget, &OutputWindow::setBaseFont); connect(this, &IOutputPane::wheelZoomEnabledChanged, m_widget, &OutputWindow::setWheelZoomEnabled); @@ -65,6 +66,7 @@ MessageOutputWindow::MessageOutputWindow() setupFilterUi("MessageOutputPane.Filter"); setFilteringEnabled(true); + setupContext(Constants::C_GENERAL_OUTPUT_PANE, m_widget); } MessageOutputWindow::~MessageOutputWindow() diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp index 951fed419b..7cf2ec2c90 100644 --- a/src/plugins/coreplugin/outputpanemanager.cpp +++ b/src/plugins/coreplugin/outputpanemanager.cpp @@ -35,6 +35,7 @@ #include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/actionmanager/command.h> +#include <coreplugin/actionmanager/commandbutton.h> #include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/ieditor.h> #include <coreplugin/find/optionspopup.h> @@ -90,24 +91,27 @@ static bool g_managerConstructed = false; // For debugging reasons. IOutputPane::IOutputPane(QObject *parent) : QObject(parent), - m_zoomInButton(new QToolButton), - m_zoomOutButton(new QToolButton) + m_zoomInButton(new Core::CommandButton), + m_zoomOutButton(new Core::CommandButton) { // We need all pages first. Ignore latecomers and shout. QTC_ASSERT(!g_managerConstructed, return); g_outputPanes.append(OutputPaneData(this)); - m_zoomInButton->setToolTip(tr("Increase Font Size")); m_zoomInButton->setIcon(Utils::Icons::PLUS_TOOLBAR.icon()); + m_zoomInButton->setCommandId(Constants::ZOOM_IN); connect(m_zoomInButton, &QToolButton::clicked, this, [this] { emit zoomIn(1); }); - m_zoomOutButton->setToolTip(tr("Decrease Font Size")); m_zoomOutButton->setIcon(Utils::Icons::MINUS.icon()); + m_zoomOutButton->setCommandId(Constants::ZOOM_OUT); connect(m_zoomOutButton, &QToolButton::clicked, this, [this] { emit zoomOut(1); }); } IOutputPane::~IOutputPane() { + if (m_context) + ICore::removeContextObject(m_context); + const int i = Utils::indexOf(g_outputPanes, Utils::equal(&OutputPaneData::pane, this)); QTC_ASSERT(i >= 0, return); delete g_outputPanes.at(i).button; @@ -174,6 +178,26 @@ void IOutputPane::setFilteringEnabled(bool enable) m_filterOutputLineEdit->setEnabled(enable); } +void IOutputPane::setupContext(const char *context, QWidget *widget) +{ + QTC_ASSERT(!m_context, return); + m_context = new IContext(this); + m_context->setContext(Context(context)); + m_context->setWidget(widget); + ICore::addContextObject(m_context); + + const auto zoomInAction = new QAction(this); + Core::ActionManager::registerAction(zoomInAction, Constants::ZOOM_IN, m_context->context()); + connect(zoomInAction, &QAction::triggered, this, [this] { emit zoomIn(1); }); + const auto zoomOutAction = new QAction(this); + Core::ActionManager::registerAction(zoomOutAction, Constants::ZOOM_OUT, m_context->context()); + connect(zoomOutAction, &QAction::triggered, this, [this] { emit zoomOut(1); }); + const auto resetZoomAction = new QAction(this); + Core::ActionManager::registerAction(resetZoomAction, Constants::ZOOM_RESET, + m_context->context()); + connect(resetZoomAction, &QAction::triggered, this, &IOutputPane::resetZoom); +} + void IOutputPane::setZoomButtonsEnabled(bool enabled) { m_zoomInButton->setEnabled(enabled); diff --git a/src/plugins/coreplugin/outputwindow.h b/src/plugins/coreplugin/outputwindow.h index 88692d5ab7..204a1106a9 100644 --- a/src/plugins/coreplugin/outputwindow.h +++ b/src/plugins/coreplugin/outputwindow.h @@ -75,6 +75,7 @@ public: void setBaseFont(const QFont &newFont); float fontZoom() const; void setFontZoom(float zoom); + void resetZoom() { setFontZoom(0); } void setWheelZoomEnabled(bool enabled); void updateFilterProperties(const QString &filterText, Qt::CaseSensitivity caseSensitivity, bool regexp); diff --git a/src/plugins/cppeditor/cppparsecontext.cpp b/src/plugins/cppeditor/cppparsecontext.cpp index 7c98fbba8f..521cc49328 100644 --- a/src/plugins/cppeditor/cppparsecontext.cpp +++ b/src/plugins/cppeditor/cppparsecontext.cpp @@ -111,14 +111,16 @@ QString ParseContextModel::currentId() const return m_projectParts[m_currentIndex]->id(); } -int ParseContextModel::rowCount(const QModelIndex &) const +int ParseContextModel::rowCount(const QModelIndex &parent) const { + if (parent.isValid()) + return 0; return m_projectParts.size(); } QVariant ParseContextModel::data(const QModelIndex &index, int role) const { - if (m_projectParts.isEmpty()) + if (!index.isValid() || index.row() < 0 || index.row() >= m_projectParts.size()) return QVariant(); const int row = index.row(); diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp index 7d12b33f05..3d74ad8d32 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.cpp +++ b/src/plugins/cpptools/compileroptionsbuilder.cpp @@ -709,6 +709,7 @@ void CompilerOptionsBuilder::evaluateCompilerFlags() qgetenv("QTC_CLANG_CMD_OPTIONS_BLACKLIST")) .split(';', QString::SkipEmptyParts); + const Core::Id &toolChain = m_projectPart.toolchainType; bool containsDriverMode = false; bool skipNext = false; for (const QString &option : m_projectPart.compilerFlags) { @@ -720,6 +721,13 @@ void CompilerOptionsBuilder::evaluateCompilerFlags() if (userBlackList.contains(option)) continue; + // TODO: Make it possible that the clang binary/driver ignores unknown options, + // as it is done for libclang/clangd (not checking for OPT_UNKNOWN). + if (toolChain == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID) { + if (option == "-fkeep-inline-dllexport" || option == "-fno-keep-inline-dllexport") + continue; + } + // Ignore warning flags as these interfere with our user-configured diagnostics. // Note that once "-w" is provided, no warnings will be emitted, even if "-Wall" follows. if (m_useBuildSystemWarnings == UseBuildSystemWarnings::No @@ -755,7 +763,7 @@ void CompilerOptionsBuilder::evaluateCompilerFlags() // Check whether a language version is already used. QString theOption = option; - if (theOption.startsWith("-std=")) { + if (theOption.startsWith("-std=") || theOption.startsWith("--std=")) { m_compilerFlags.isLanguageVersionSpecified = true; theOption.replace("=c18", "=c17"); theOption.replace("=gnu18", "=gnu17"); @@ -772,7 +780,6 @@ void CompilerOptionsBuilder::evaluateCompilerFlags() m_compilerFlags.flags.append(theOption); } - const Core::Id &toolChain = m_projectPart.toolchainType; if (!containsDriverMode && (toolChain == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID || toolChain == ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID)) { diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 26c075dfe1..79f779a295 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1759,9 +1759,9 @@ void DebuggerPlugin::attachExternalApplication(RunControl *rc) ProcessHandle pid = rc->applicationProcessHandle(); auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); runControl->setTarget(rc->target()); + runControl->setDisplayName(tr("Process %1").arg(pid.pid())); auto debugger = new DebuggerRunTool(runControl); debugger->setAttachPid(pid); - debugger->setRunControlName(tr("Process %1").arg(pid.pid())); debugger->setStartMode(AttachExternal); debugger->setCloseMode(DetachAtClose); debugger->startRunControl(); diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 50465770d9..a1b8db2169 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -605,7 +605,7 @@ BaseSettingsWidget::BaseSettingsWidget(const BaseSettings *settings, QWidget *pa mainLayout->addLayout(mimeLayout, row, 1); m_filePattern->setPlaceholderText(tr("File pattern")); mainLayout->addWidget(m_filePattern, ++row, 1); - mainLayout->addWidget(new QLabel(tr("Startup Behavior:")), ++row, 0); + mainLayout->addWidget(new QLabel(tr("Startup behavior:")), ++row, 0); for (int behavior = 0; behavior < BaseSettings::LastSentinel ; ++behavior) m_startupBehavior->addItem(startupBehaviorString(BaseSettings::StartBehavior(behavior))); m_startupBehavior->setCurrentIndex(settings->m_startBehavior); @@ -650,8 +650,8 @@ QString BaseSettingsWidget::name() const LanguageFilter BaseSettingsWidget::filter() const { - return {m_mimeTypes->text().split(filterSeparator), - m_filePattern->text().split(filterSeparator)}; + return {m_mimeTypes->text().split(filterSeparator, QString::SkipEmptyParts), + m_filePattern->text().split(filterSeparator, QString::SkipEmptyParts)}; } BaseSettings::StartBehavior BaseSettingsWidget::startupBehavior() const @@ -784,10 +784,10 @@ QString StdIOSettingsWidget::arguments() const bool LanguageFilter::isSupported(const Utils::FilePath &filePath, const QString &mimeType) const { - if (mimeTypes.isEmpty() && filePattern.isEmpty()) - return true; if (mimeTypes.contains(mimeType)) return true; + if (filePattern.isEmpty() && filePath.isEmpty()) + return mimeTypes.isEmpty(); auto regexps = Utils::transform(filePattern, [](const QString &pattern){ return QRegExp(pattern, Utils::HostOsInfo::fileNameCaseSensitivity(), QRegExp::Wildcard); }); diff --git a/src/plugins/perfprofiler/perfprofilertool.cpp b/src/plugins/perfprofiler/perfprofilertool.cpp index 5af097a9ec..bb71f925da 100644 --- a/src/plugins/perfprofiler/perfprofilertool.cpp +++ b/src/plugins/perfprofiler/perfprofilertool.cpp @@ -157,6 +157,9 @@ PerfProfilerTool::PerfProfilerTool() tracePointsAction->setEnabled(m_startAction->isEnabled()); }); + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, + this, &PerfProfilerTool::updateRunActions); + m_recordButton = new QToolButton; m_clearButton = new QToolButton; m_filterButton = new QToolButton; @@ -341,9 +344,6 @@ void PerfProfilerTool::createViews() menu1->exec(m_flameGraphView->mapToGlobal(pos)); }); - connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, - this, &PerfProfilerTool::updateRunActions); - m_perspective.addToolBarAction(m_startAction); m_perspective.addToolBarAction(m_stopAction); m_perspective.addToolBarWidget(m_recordButton); diff --git a/src/plugins/projectexplorer/appoutputpane.cpp b/src/plugins/projectexplorer/appoutputpane.cpp index 7631f26cac..df9fd503ba 100644 --- a/src/plugins/projectexplorer/appoutputpane.cpp +++ b/src/plugins/projectexplorer/appoutputpane.cpp @@ -213,6 +213,7 @@ AppOutputPane::AppOutputPane() : connect(this, &Core::IOutputPane::zoomIn, this, &AppOutputPane::zoomIn); connect(this, &Core::IOutputPane::zoomOut, this, &AppOutputPane::zoomOut); + connect(this, &IOutputPane::resetZoom, this, &AppOutputPane::resetZoom); m_settingsButton->setToolTip(tr("Open Settings Page")); m_settingsButton->setIcon(Utils::Icons::SETTINGS_TOOLBAR.icon()); @@ -247,6 +248,7 @@ AppOutputPane::AppOutputPane() : setupFilterUi("AppOutputPane.Filter"); setFilteringEnabled(false); setZoomButtonsEnabled(false); + setupContext("Core.AppOutputPane", m_mainWidget); } AppOutputPane::~AppOutputPane() @@ -662,6 +664,12 @@ void AppOutputPane::zoomOut(int range) tab.window->zoomOut(range); } +void AppOutputPane::resetZoom() +{ + for (const RunControlTab &tab : qAsConst(m_runControlTabs)) + tab.window->resetZoom(); +} + void AppOutputPane::enableButtons(const RunControl *rc) { if (rc) { diff --git a/src/plugins/projectexplorer/appoutputpane.h b/src/plugins/projectexplorer/appoutputpane.h index 5fc88219fc..6d7936042e 100644 --- a/src/plugins/projectexplorer/appoutputpane.h +++ b/src/plugins/projectexplorer/appoutputpane.h @@ -120,6 +120,7 @@ private: void zoomIn(int range); void zoomOut(int range); + void resetZoom(); void enableButtons(const RunControl *rc); diff --git a/src/plugins/projectexplorer/compileoutputwindow.cpp b/src/plugins/projectexplorer/compileoutputwindow.cpp index 91cc2fb22c..d92bcc4bbe 100644 --- a/src/plugins/projectexplorer/compileoutputwindow.cpp +++ b/src/plugins/projectexplorer/compileoutputwindow.cpp @@ -177,6 +177,7 @@ CompileOutputWindow::CompileOutputWindow(QAction *cancelBuildAction) : connect(this, &IOutputPane::zoomIn, m_outputWindow, &Core::OutputWindow::zoomIn); connect(this, &IOutputPane::zoomOut, m_outputWindow, &Core::OutputWindow::zoomOut); + connect(this, &IOutputPane::resetZoom, m_outputWindow, &Core::OutputWindow::resetZoom); connect(TextEditor::TextEditorSettings::instance(), &TextEditor::TextEditorSettings::fontSettingsChanged, this, updateFontSettings); connect(TextEditor::TextEditorSettings::instance(), &TextEditor::TextEditorSettings::behaviorSettingsChanged, @@ -194,6 +195,7 @@ CompileOutputWindow::CompileOutputWindow(QAction *cancelBuildAction) : m_handler = new ShowOutputTaskHandler(this); ExtensionSystem::PluginManager::addObject(m_handler); + setupContext(C_COMPILE_OUTPUT, m_outputWindow); loadSettings(); updateFromSettings(); } diff --git a/src/plugins/projectexplorer/environmentwidget.cpp b/src/plugins/projectexplorer/environmentwidget.cpp index 673aa61cfc..43758e0a36 100644 --- a/src/plugins/projectexplorer/environmentwidget.cpp +++ b/src/plugins/projectexplorer/environmentwidget.cpp @@ -381,7 +381,7 @@ void EnvironmentWidget::amendPathList(const PathListModifier &modifier) { const QString varName = d->m_model->indexToVariable(d->m_environmentView->currentIndex()); const QString dir = QDir::toNativeSeparators( - QFileDialog::getExistingDirectory(this, tr("Choose a directory"))); + QFileDialog::getExistingDirectory(this, tr("Choose Directory"))); if (dir.isEmpty()) return; QModelIndex index = d->m_model->variableToIndex(varName); diff --git a/src/plugins/projectexplorer/filterkitaspectsdialog.cpp b/src/plugins/projectexplorer/filterkitaspectsdialog.cpp index 418ae03564..12bd7ccf13 100644 --- a/src/plugins/projectexplorer/filterkitaspectsdialog.cpp +++ b/src/plugins/projectexplorer/filterkitaspectsdialog.cpp @@ -92,7 +92,7 @@ class FilterKitAspectsModel : public TreeModel<TreeItem, FilterTreeItem> public: FilterKitAspectsModel(const Kit *kit, QObject *parent) : TreeModel(parent) { - setHeader({tr("Setting"), tr("Visible")}); + setHeader({FilterKitAspectsDialog::tr("Setting"), FilterKitAspectsDialog::tr("Visible")}); for (const KitAspect * const aspect : KitManager::kitAspects()) { if (kit && !aspect->isApplicableToKit(kit)) continue; diff --git a/src/plugins/projectexplorer/filterkitaspectsdialog.h b/src/plugins/projectexplorer/filterkitaspectsdialog.h index 441abd658d..f59a58f683 100644 --- a/src/plugins/projectexplorer/filterkitaspectsdialog.h +++ b/src/plugins/projectexplorer/filterkitaspectsdialog.h @@ -37,6 +37,7 @@ namespace Internal { class FilterKitAspectsDialog : public QDialog { + Q_OBJECT public: FilterKitAspectsDialog(const Kit *kit, QWidget *parent); QSet<Core::Id> irrelevantAspects() const; diff --git a/src/plugins/projectexplorer/importwidget.cpp b/src/plugins/projectexplorer/importwidget.cpp index eac2c44c94..33db7d48df 100644 --- a/src/plugins/projectexplorer/importwidget.cpp +++ b/src/plugins/projectexplorer/importwidget.cpp @@ -63,10 +63,14 @@ ImportWidget::ImportWidget(QWidget *parent) : connect(importButton, &QAbstractButton::clicked, this, &ImportWidget::handleImportRequest); connect(m_pathChooser->lineEdit(), &QLineEdit::returnPressed, this, [this] { if (m_pathChooser->isValid()) { + m_ownsReturnKey = true; handleImportRequest(); // The next return should trigger the "Configure" button. - QTimer::singleShot(0, this, QOverload<>::of(&QWidget::setFocus)); + QTimer::singleShot(0, this, [this] { + setFocus(); + m_ownsReturnKey = false; + }); } }); @@ -79,9 +83,9 @@ void ImportWidget::setCurrentDirectory(const Utils::FilePath &dir) m_pathChooser->setFileName(dir); } -bool ImportWidget::lineEditHasFocus() const +bool ImportWidget::ownsReturnKey() const { - return m_pathChooser->lineEdit()->hasFocus(); + return m_ownsReturnKey; } void ImportWidget::handleImportRequest() diff --git a/src/plugins/projectexplorer/importwidget.h b/src/plugins/projectexplorer/importwidget.h index 8999bc117d..5c63beecdb 100644 --- a/src/plugins/projectexplorer/importwidget.h +++ b/src/plugins/projectexplorer/importwidget.h @@ -44,7 +44,7 @@ public: void setCurrentDirectory(const Utils::FilePath &dir); - bool lineEditHasFocus() const; + bool ownsReturnKey() const; signals: void importFrom(const Utils::FilePath &dir); @@ -53,6 +53,7 @@ private: void handleImportRequest(); Utils::PathChooser *m_pathChooser; + bool m_ownsReturnKey = false; }; } // namespace Internal diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp index 7141148ef8..7684de0795 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp @@ -104,7 +104,7 @@ public: : QDialog(parent), m_view(new Utils::TreeView(this)) { setWindowTitle(QCoreApplication::translate("ProjectExplorer::JsonWizard", - "Choose project file")); + "Choose Project File")); const auto model = new ProjectFilesModel(candidates, this); m_view->setSelectionMode(Utils::TreeView::ExtendedSelection); m_view->setSelectionBehavior(Utils::TreeView::SelectRows); @@ -121,7 +121,7 @@ public: const auto layout = new QVBoxLayout(this); layout->addWidget(new QLabel(QCoreApplication::translate("ProjectExplorer::JsonWizard", "The project contains more than one project file. " - "Please select the one you would like to use."))); + "Select the one you would like to use."))); layout->addWidget(m_view); layout->addWidget(buttonBox); } diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 15f345dc5b..60cd9a6e21 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -1298,6 +1298,7 @@ MsvcToolChainConfigWidget::MsvcToolChainConfigWidget(ToolChain *tc) m_mainLayout->removeRow(m_mainLayout->rowCount() - 1); QHBoxLayout *hLayout = new QHBoxLayout(); + m_varsBatPathCombo->setObjectName("varsBatCombo"); m_varsBatPathCombo->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); m_varsBatPathCombo->setEditable(true); for (const MsvcToolChain *tmpTc : g_availableMsvcToolchains) { @@ -1442,6 +1443,7 @@ ClangClToolChainConfigWidget::ClangClToolChainConfigWidget(ToolChain *tc) : { m_mainLayout->removeRow(m_mainLayout->rowCount() - 1); + m_varsBatDisplayCombo->setObjectName("varsBatCombo"); m_varsBatDisplayCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents); m_mainLayout->addRow(tr("Initialization:"), m_varsBatDisplayCombo); diff --git a/src/plugins/projectexplorer/parseissuesdialog.cpp b/src/plugins/projectexplorer/parseissuesdialog.cpp index 5b6015b5a5..7b0d3758e6 100644 --- a/src/plugins/projectexplorer/parseissuesdialog.cpp +++ b/src/plugins/projectexplorer/parseissuesdialog.cpp @@ -71,14 +71,14 @@ ParseIssuesDialog::ParseIssuesDialog(QWidget *parent) : QDialog(parent), d(new P d->clearTasksCheckBox.setText(tr("Clear existing tasks")); d->clearTasksCheckBox.setChecked(true); - const auto loadFileButton = new QPushButton(tr("Load from file...")); + const auto loadFileButton = new QPushButton(tr("Load from File...")); connect(loadFileButton, &QPushButton::clicked, this, [this] { const QString filePath = QFileDialog::getOpenFileName(this, tr("Choose File")); if (filePath.isEmpty()) return; QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) { - QMessageBox::critical(this, tr("Could not open file"), + QMessageBox::critical(this, tr("Could Not Open File"), tr("Could not open file: \"%1\": %2") .arg(filePath, file.errorString())); return; @@ -116,7 +116,7 @@ ParseIssuesDialog::ParseIssuesDialog(QWidget *parent) : QDialog(parent), d(new P // TODO: Only very few parsers are available from a Kit (basically just the Toolchain one). // If we introduced factories for IOutputParsers, we could offer the user // to combine arbitrary parsers here. - const auto parserGroupBox = new QGroupBox(tr("Parsing options")); + const auto parserGroupBox = new QGroupBox(tr("Parsing Options")); layout->addWidget(parserGroupBox); const auto parserLayout = new QVBoxLayout(parserGroupBox); const auto kitChooserWidget = new QWidget; @@ -153,7 +153,7 @@ void ParseIssuesDialog::accept() { std::unique_ptr<IOutputParser> parser(d->kitChooser.currentKit()->createOutputParser()); if (!parser) { - QMessageBox::critical(this, tr("Cannot parse"), tr("Cannot parse: The chosen kit does " + QMessageBox::critical(this, tr("Cannot Parse"), tr("Cannot parse: The chosen kit does " "not provide an output parser.")); return; } diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 420d6dad32..f34547cc95 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -667,7 +667,7 @@ void Project::changeRootProjectDirectory() { Utils::FilePath rootPath = Utils::FilePath::fromString( QFileDialog::getExistingDirectory(Core::ICore::dialogParent(), - tr("Select The Root Directory"), + tr("Select the Root Directory"), rootProjectDirectory().toString(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks)); @@ -679,7 +679,7 @@ void Project::changeRootProjectDirectory() } /*! - Returns the common root directory that contains all files which belongs to a project. + Returns the common root directory that contains all files which belong to a project. */ Utils::FilePath Project::rootProjectDirectory() const { diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index d5c5fb9ce5..2f029ccedd 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -1780,7 +1780,7 @@ void ProjectExplorerPlugin::unloadProject(Project *project) void ProjectExplorerPluginPrivate::closeAllProjects() { - if (!EditorManager::closeAllEditors()) + if (!EditorManager::closeAllDocuments()) return; // Action has been cancelled SessionManager::closeAllProjects(); @@ -1935,15 +1935,15 @@ void ProjectExplorerPluginPrivate::setStartupProject(Project *project) bool ProjectExplorerPluginPrivate::closeAllFilesInProject(const Project *project) { QTC_ASSERT(project, return false); - QList<IDocument *> openFiles = DocumentModel::openedDocuments(); - Utils::erase(openFiles, [project](const IDocument *doc) { - return !project->isKnownFile(doc->filePath()); + QList<DocumentModel::Entry *> openFiles = DocumentModel::entries(); + Utils::erase(openFiles, [project](const DocumentModel::Entry *entry) { + return entry->pinned || !project->isKnownFile(entry->fileName()); }); for (const Project * const otherProject : SessionManager::projects()) { if (otherProject == project) continue; - Utils::erase(openFiles, [otherProject](const IDocument *doc) { - return otherProject->isKnownFile(doc->filePath()); + Utils::erase(openFiles, [otherProject](const DocumentModel::Entry *entry) { + return otherProject->isKnownFile(entry->fileName()); }); } return EditorManager::closeDocuments(openFiles); @@ -3470,7 +3470,7 @@ void ProjectExplorerPluginPrivate::addExistingProjects() QTC_ASSERT(projectNode, return); const QString dir = directoryFor(currentNode); QStringList subProjectFilePaths = QFileDialog::getOpenFileNames( - ICore::mainWindow(), tr("Please choose a project file"), dir, + ICore::mainWindow(), tr("Choose Project File"), dir, projectNode->subProjectFileNamePatterns().join(";;")); if (!ProjectTree::hasNode(projectNode)) return; diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp index 839f021f2b..08010bb50b 100644 --- a/src/plugins/projectexplorer/projectmodels.cpp +++ b/src/plugins/projectexplorer/projectmodels.cpp @@ -457,7 +457,7 @@ public: : m_buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel)), m_buttonGroup(new QButtonGroup(this)) { - setWindowTitle(tr("Please choose a drop action")); + setWindowTitle(tr("Choose Drop Action")); const bool offerFileIo = !defaultTargetDir.isEmpty(); auto * const layout = new QVBoxLayout(this); layout->addWidget(new QLabel(tr("You just dragged some files from one project node to " @@ -469,8 +469,8 @@ public: m_buttonGroup->addButton(moveButton, int(DropAction::Move)); layout->addWidget(moveButton); if (offerFileIo) { - copyButton->setText(tr("Copy only the file references")); - moveButton->setText(tr("Move only the file references")); + copyButton->setText(tr("Copy Only File References")); + moveButton->setText(tr("Move Only File References")); auto * const copyWithFilesButton = new QRadioButton(tr("Copy file references and files"), this); m_buttonGroup->addButton(copyWithFilesButton, int(DropAction::CopyWithFiles)); @@ -506,8 +506,8 @@ public: } }); } else { - copyButton->setText(tr("Copy the file references")); - moveButton->setText(tr("Move the file references")); + copyButton->setText(tr("Copy File References")); + moveButton->setText(tr("Move File References")); moveButton->setChecked(true); } connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index c0dba5c020..0006d7678c 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -332,7 +332,7 @@ void TargetSetupPage::setProjectImporter(ProjectImporter *importer) bool TargetSetupPage::importLineEditHasFocus() const { - return m_importWidget->lineEditHasFocus(); + return m_importWidget->ownsReturnKey(); } void TargetSetupPage::setNoteText(const QString &text) diff --git a/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp b/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp index 623b20a1a4..95b7c8eb5b 100644 --- a/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp +++ b/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp @@ -164,7 +164,7 @@ KitAspect::ItemList QmakeKitAspect::toUserOutput(const Kit *k) const void QmakeKitAspect::addToMacroExpander(Kit *kit, MacroExpander *expander) const { - expander->registerVariable("Qmake:mkspec", tr("Mkspec configured for qmake by the Kit."), + expander->registerVariable("Qmake:mkspec", tr("Mkspec configured for qmake by the kit."), [kit]() -> QString { return QDir::toNativeSeparators(mkspec(kit)); }); diff --git a/src/plugins/qmakeprojectmanager/qmakesettings.cpp b/src/plugins/qmakeprojectmanager/qmakesettings.cpp index f3c2bf9760..37c0a4ce39 100644 --- a/src/plugins/qmakeprojectmanager/qmakesettings.cpp +++ b/src/plugins/qmakeprojectmanager/qmakesettings.cpp @@ -103,7 +103,7 @@ public: m_warnAgainstUnalignedBuildDirCheckbox.setText(tr("Warn if a project's source and " "build directories are not at the same level")); m_warnAgainstUnalignedBuildDirCheckbox.setToolTip(tr("Qmake has subtle bugs that " - "can trigger if source and build directory are not at the same level.")); + "can be triggered if source and build directory are not at the same level.")); m_warnAgainstUnalignedBuildDirCheckbox.setChecked( QmakeSettings::warnAgainstUnalignedBuildDir()); m_alwaysRunQmakeCheckbox.setText(tr("Run qmake on every build")); diff --git a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h index 028d3a21b4..0535a8f52e 100644 --- a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h +++ b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h @@ -165,6 +165,7 @@ const int priorityGenericToolBar = 50; const int priorityLast = 60; const char addImagesDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "Image Files"); +const char addFontsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "Font Files"); } //ComponentCoreConstants diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index 6edbacec36..37e1fdfd53 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -1026,6 +1026,13 @@ void DesignerActionManager::createDefaultAddResourceHandler() registerAddResourceHandler(AddResourceHandler(ComponentCoreConstants::addImagesDisplayString, "*.svg", ModelNodeOperations::addImageToProject)); + + registerAddResourceHandler(AddResourceHandler(ComponentCoreConstants::addFontsDisplayString, + "*.ttf", + ModelNodeOperations::addFontToProject)); + registerAddResourceHandler(AddResourceHandler(ComponentCoreConstants::addFontsDisplayString, + "*.otf", + ModelNodeOperations::addFontToProject)); } void DesignerActionManager::addDesignerAction(ActionInterface *newAction) diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index 3c31998576..9f880c453b 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -966,6 +966,38 @@ void addTabBarToStackedContainer(const SelectionContext &selectionContext) } +bool addFontToProject(const QStringList &fileNames, const QString &defaultDirectory) +{ + QString directory = AddImagesDialog::getDirectory(fileNames, defaultDirectory); + + if (directory.isEmpty()) + return true; + + bool allSuccessful = true; + for (const QString &fileName : fileNames) { + const QString targetFile = directory + "/" + QFileInfo(fileName).fileName(); + const bool success = QFile::copy(fileName, targetFile); + + auto document = QmlDesignerPlugin::instance()->currentDesignDocument(); + + QTC_ASSERT(document, return false); + + if (success) { + ProjectExplorer::Node *node = ProjectExplorer::ProjectTree::nodeForFile(document->fileName()); + if (node) { + ProjectExplorer::FolderNode *containingFolder = node->parentFolderNode(); + if (containingFolder) + containingFolder->addFiles(QStringList(targetFile)); + } + } else { + allSuccessful = false; + } + } + + return allSuccessful; +} + + bool addImageToProject(const QStringList &fileNames, const QString &defaultDirectory) { QString directory = AddImagesDialog::getDirectory(fileNames, defaultDirectory); diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h index e3396a303e..52dfaf6f1d 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h @@ -73,6 +73,7 @@ void increaseIndexOfStackedContainer(const SelectionContext &selectionContext); void decreaseIndexOfStackedContainer(const SelectionContext &selectionContext); void addTabBarToStackedContainer(const SelectionContext &selectionContext); bool addImageToProject(const QStringList &fileNames, const QString &directory); +bool addFontToProject(const QStringList &fileNames, const QString &directory); } // namespace ModelNodeOperationso } //QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h index cfffeeaca4..f686631079 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h +++ b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h @@ -27,6 +27,7 @@ #include <qmlitemnode.h> +#include <QDir> #include <QObject> #include <QStringList> #include <QUrl> diff --git a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp index 4263a1e498..aec85826a2 100644 --- a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp +++ b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp @@ -256,6 +256,11 @@ QList<DeployableFile> QnxDeployQtLibrariesDialog::gatherFiles( if (dirPath.isEmpty()) return result; + static const QStringList unusedDirs = {"include", "mkspecs", "cmake", "pkgconfig"}; + const QString dp = dirPath.endsWith('/') ? dirPath.left(dirPath.size() - 1) : dirPath; + if (unusedDirs.contains(dp)) + return result; + QDir dir(dirPath); QFileInfoList list = dir.entryInfoList(nameFilters, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); @@ -265,6 +270,10 @@ QList<DeployableFile> QnxDeployQtLibrariesDialog::gatherFiles( result.append(gatherFiles(fileInfo.absoluteFilePath(), baseDirPath.isEmpty() ? dirPath : baseDirPath)); } else { + static const QStringList unusedSuffixes = {"cmake", "la", "prl", "a", "pc"}; + if (unusedSuffixes.contains(fileInfo.suffix())) + continue; + QString remoteDir; if (baseDirPath.isEmpty()) { remoteDir = fullRemoteDirectory() + QLatin1Char('/') + diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp index 96c41218e8..8af1a6aebd 100644 --- a/src/plugins/remotelinux/makeinstallstep.cpp +++ b/src/plugins/remotelinux/makeinstallstep.cpp @@ -118,13 +118,13 @@ bool MakeInstallStep::init() } QDir rootDir(rootDirPath); if (cleanInstallRoot() && !rootDir.removeRecursively()) { - emit addTask(Task(Task::Error, tr("The install root '%1' could not be cleaned.") + emit addTask(Task(Task::Error, tr("The install root \"%1\" could not be cleaned.") .arg(installRoot().toUserOutput()), FilePath(), -1, Constants::TASK_CATEGORY_BUILDSYSTEM)); return false; } if (!rootDir.exists() && !QDir::root().mkpath(rootDirPath)) { - emit addTask(Task(Task::Error, tr("The install root '%1' could not be created.") + emit addTask(Task(Task::Error, tr("The install root \"%1\" could not be created.") .arg(installRoot().toUserOutput()), FilePath(), -1, Constants::TASK_CATEGORY_BUILDSYSTEM)); return false; diff --git a/src/plugins/texteditor/highlighter.cpp b/src/plugins/texteditor/highlighter.cpp index d1f7dbc1bf..bbeff2a484 100644 --- a/src/plugins/texteditor/highlighter.cpp +++ b/src/plugins/texteditor/highlighter.cpp @@ -33,6 +33,7 @@ #include <coreplugin/icore.h> #include <coreplugin/messagemanager.h> #include <utils/mimetypes/mimedatabase.h> +#include <utils/qtcassert.h> #include <DefinitionDownloader> #include <Format> @@ -119,6 +120,8 @@ Highlighter::Definition Highlighter::definitionForDocument(const TextDocument *d Highlighter::Definition Highlighter::definitionForMimeType(const QString &mimeType) { + if (mimeType.isEmpty()) + return {}; const Definitions definitions = definitionsForMimeType(mimeType); if (definitions.size() == 1) return definitions.first(); @@ -140,13 +143,23 @@ Highlighter::Definition Highlighter::definitionForName(const QString &name) Highlighter::Definitions Highlighter::definitionsForDocument(const TextDocument *document) { - const Utils::MimeType mimeType = Utils::mimeTypeForName(document->mimeType()); - Definitions definitions; - if (mimeType.isValid()) - definitions = Highlighter::definitionsForMimeType(mimeType.name()); - if (definitions.isEmpty()) - definitions = Highlighter::definitionsForFileName(document->filePath()); - return definitions; + QTC_ASSERT(document, return {}); + const Utils::MimeType &mimeType = Utils::mimeTypeForName(document->mimeType()); + if (mimeType.isValid()) { + if (mimeType.name() == "text/plain") { + // text/plain is the base mime type for all text types so ignore it and try matching the + // file name against the pattern and only if no definition can be found for the + // file name try matching the mime type + const Definitions &fileNameDefinitions = definitionsForFileName(document->filePath()); + if (!fileNameDefinitions.isEmpty()) + return fileNameDefinitions; + return definitionsForMimeType(mimeType.name()); + } + const Definitions &mimeTypeDefinitions = definitionsForMimeType(mimeType.name()); + if (!mimeTypeDefinitions.isEmpty()) + return mimeTypeDefinitions; + } + return definitionsForFileName(document->filePath()); } static Highlighter::Definition definitionForSetting(const QString &settingsKey, @@ -193,6 +206,7 @@ Highlighter::Definitions Highlighter::definitionsForFileName(const Utils::FilePa void Highlighter::rememberDefintionForDocument(const Highlighter::Definition &definition, const TextDocument *document) { + QTC_ASSERT(document, return ); if (!definition.isValid()) return; const QString &mimeType = document->mimeType(); diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 2d7a98457d..6a699c4686 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -630,7 +630,7 @@ MemcheckToolPrivate::MemcheckToolPrivate() }); action = new QAction(this); - action->setText(tr("Valgrind Memory Analyzer with GDB")); + action->setText(MemcheckTool::tr("Valgrind Memory Analyzer with GDB")); action->setToolTip(MemcheckTool::tr("Valgrind Analyze Memory with GDB uses the " "Memcheck tool to find memory leaks.\nWhen a problem is detected, " "the application is interrupted and can be debugged.")); @@ -650,7 +650,7 @@ MemcheckToolPrivate::MemcheckToolPrivate() } else { action = new QAction(MemcheckTool::tr("Heob"), this); Core::Command *cmd = Core::ActionManager::registerAction(action, "Memcheck.Local"); - cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+H"))); + cmd->setDefaultKeySequence(QKeySequence(MemcheckTool::tr("Ctrl+Alt+H"))); connect(action, &QAction::triggered, this, &MemcheckToolPrivate::heobAction); menu->addAction(cmd, Debugger::Constants::G_ANALYZER_TOOLS); connect(m_startAction, &QAction::changed, action, [action, this] { @@ -659,7 +659,7 @@ MemcheckToolPrivate::MemcheckToolPrivate() } action = new QAction(this); - action->setText(tr("Valgrind Memory Analyzer (External Application)")); + action->setText(MemcheckTool::tr("Valgrind Memory Analyzer (External Application)")); action->setToolTip(toolTip); menu->addAction(ActionManager::registerAction(action, "Memcheck.Remote"), Debugger::Constants::G_ANALYZER_REMOTE_TOOLS); @@ -724,7 +724,7 @@ void MemcheckToolPrivate::heobAction() } } if (!hasLocalRc) { - const QString msg = tr("Heob: No local run configuration available."); + const QString msg = MemcheckTool::tr("Heob: No local run configuration available."); TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID); TaskHub::requestPopup(); return; @@ -733,7 +733,7 @@ void MemcheckToolPrivate::heobAction() || abi.os() != Abi::WindowsOS || abi.binaryFormat() != Abi::PEFormat || (abi.wordWidth() != 32 && abi.wordWidth() != 64)) { - const QString msg = tr("Heob: No toolchain available."); + const QString msg = MemcheckTool::tr("Heob: No toolchain available."); TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID); TaskHub::requestPopup(); return; @@ -746,7 +746,7 @@ void MemcheckToolPrivate::heobAction() // target executable if (executable.isEmpty()) { - const QString msg = tr("Heob: No executable set."); + const QString msg = MemcheckTool::tr("Heob: No executable set."); TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID); TaskHub::requestPopup(); return; @@ -754,7 +754,7 @@ void MemcheckToolPrivate::heobAction() if (!QFile::exists(executable)) executable = Utils::HostOsInfo::withExecutableSuffix(executable); if (!QFile::exists(executable)) { - const QString msg = tr("Heob: Cannot find %1.").arg(executable); + const QString msg = MemcheckTool::tr("Heob: Cannot find %1.").arg(executable); TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID); TaskHub::requestPopup(); return; @@ -775,9 +775,11 @@ void MemcheckToolPrivate::heobAction() const QString heob = QString("heob%1.exe").arg(abi.wordWidth()); const QString heobPath = dialog.path() + '/' + heob; if (!QFile::exists(heobPath)) { - QMessageBox::critical(Core::ICore::mainWindow(), tr("Heob"), - tr("The %1 executables must be in the appropriate location.") - .arg("<a href=\"https://github.com/ssbssa/heob/releases\">Heob</a>")); + QMessageBox::critical( + Core::ICore::mainWindow(), + MemcheckTool::tr("Heob"), + MemcheckTool::tr("The %1 executables must be in the appropriate location.") + .arg("<a href=\"https://github.com/ssbssa/heob/releases\">Heob</a>")); return; } @@ -786,13 +788,19 @@ void MemcheckToolPrivate::heobAction() const QString dwarfstack = QString("dwarfstack%1.dll").arg(abi.wordWidth()); const QString dwarfstackPath = dialog.path() + '/' + dwarfstack; if (!QFile::exists(dwarfstackPath) - && CheckableMessageBox::doNotShowAgainInformation( - Core::ICore::mainWindow(), tr("Heob"), - tr("Heob used with MinGW projects needs the %1 DLLs for proper stacktrace resolution.") - .arg("<a href=\"https://github.com/ssbssa/dwarfstack/releases\">Dwarfstack</a>"), - ICore::settings(), "HeobDwarfstackInfo", - QDialogButtonBox::Ok | QDialogButtonBox::Cancel, - QDialogButtonBox::Ok) != QDialogButtonBox::Ok) + && CheckableMessageBox::doNotShowAgainInformation( + Core::ICore::mainWindow(), + MemcheckTool::tr("Heob"), + MemcheckTool::tr("Heob used with MinGW projects needs the %1 DLLs for proper " + "stacktrace resolution.") + .arg( + "<a " + "href=\"https://github.com/ssbssa/dwarfstack/releases\">Dwarfstack</a>"), + ICore::settings(), + "HeobDwarfstackInfo", + QDialogButtonBox::Ok | QDialogButtonBox::Cancel, + QDialogButtonBox::Ok) + != QDialogButtonBox::Ok) return; } @@ -837,7 +845,9 @@ void MemcheckToolPrivate::heobAction() CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED | CREATE_NEW_CONSOLE, envPtr, reinterpret_cast<LPCWSTR>(workingDirectory.utf16()), &si, &pi)) { DWORD e = GetLastError(); - const QString msg = tr("Heob: Cannot create %1 process (%2).").arg(heob).arg(qt_error_string(e)); + const QString msg = MemcheckTool::tr("Heob: Cannot create %1 process (%2).") + .arg(heob) + .arg(qt_error_string(e)); TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID); TaskHub::requestPopup(); return; diff --git a/src/plugins/vcsbase/vcsoutputwindow.cpp b/src/plugins/vcsbase/vcsoutputwindow.cpp index d5b4a48b8e..da3cb8fa29 100644 --- a/src/plugins/vcsbase/vcsoutputwindow.cpp +++ b/src/plugins/vcsbase/vcsoutputwindow.cpp @@ -239,7 +239,7 @@ void OutputWindowPlainTextEdit::appendLinesWithStyle(const QString &s, setFormat(style); if (style == VcsOutputWindow::Command) { - const QString timeStamp = QTime::currentTime().toString("\nHH:mm "); + const QString timeStamp = QTime::currentTime().toString("\nHH:mm:ss "); appendLines(timeStamp + s, repository); } else { appendLines(s, repository); @@ -291,22 +291,17 @@ VcsOutputWindow::VcsOutputWindow() Q_ASSERT(d->passwordRegExp.isValid()); m_instance = this; - auto updateFontSettings = [] { - d->widget.setBaseFont(TextEditor::TextEditorSettings::fontSettings().font()); - }; - auto updateBehaviorSettings = [] { d->widget.setWheelZoomEnabled( TextEditor::TextEditorSettings::behaviorSettings().m_scrollWheelZooming); }; - updateFontSettings(); updateBehaviorSettings(); + setupContext(Internal::C_VCS_OUTPUT_PANE, &d->widget); connect(this, &IOutputPane::zoomIn, &d->widget, &Core::OutputWindow::zoomIn); connect(this, &IOutputPane::zoomOut, &d->widget, &Core::OutputWindow::zoomOut); - connect(TextEditor::TextEditorSettings::instance(), &TextEditor::TextEditorSettings::fontSettingsChanged, - this, updateFontSettings); + connect(this, &IOutputPane::resetZoom, &d->widget, &Core::OutputWindow::resetZoom); connect(TextEditor::TextEditorSettings::instance(), &TextEditor::TextEditorSettings::behaviorSettingsChanged, this, updateBehaviorSettings); } diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index 01233fc46f..6e75847eb9 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -1702,7 +1702,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFunction( if (m_valuemapStack.count() >= 100) { evalError(fL1S("Ran into infinite recursion (depth > 100).")); - vr = ReturnFalse; + vr = ReturnError; } else { m_valuemapStack.push(ProValueMap()); m_locationStack.push(m_current); diff --git a/src/shared/qbs b/src/shared/qbs -Subproject 59cc3f249b1f507afda1757e6edd1ba25970fa1 +Subproject e0ac40e53c5fc16b675ea2ac63fb5f3a6cab3de diff --git a/src/shared/registryaccess/registryaccess.h b/src/shared/registryaccess/registryaccess.h index 2880aa6677..cfd945d35a 100644 --- a/src/shared/registryaccess/registryaccess.h +++ b/src/shared/registryaccess/registryaccess.h @@ -45,6 +45,7 @@ enum AccessMode { static const char *debuggerApplicationFileC = "qtcdebugger"; static const WCHAR *debuggerRegistryKeyC = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"; static const WCHAR *debuggerRegistryValueNameC = L"Debugger"; +static const WCHAR *autoRegistryValueNameC = L"Auto"; static inline QString wCharToQString(const WCHAR *w) { diff --git a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp index 0ce49e829d..bcf05e5d04 100644 --- a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp +++ b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp @@ -31,6 +31,7 @@ #include <environment.h> #include <executeinloop.h> #include <filepathcaching.h> +#include <filesystem.h> #include <generatedfiles.h> #include <modifiedtimechecker.h> #include <pchcreator.h> @@ -179,7 +180,8 @@ struct Data // because we have a cycle dependency Sqlite::Database database; ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database}; ClangBackEnd::FilePathCaching filePathCache{database}; - ClangPathWatcher<QFileSystemWatcher, QTimer> includeWatcher{filePathCache}; + ClangBackEnd::FileSystem fileSystem{filePathCache}; + ClangPathWatcher<QFileSystemWatcher, QTimer> includeWatcher{filePathCache, fileSystem}; ApplicationEnvironment environment; ProjectPartsStorage<> projectPartsStorage{database}; PrecompiledHeaderStorage<> preCompiledHeaderStorage{database}; @@ -212,12 +214,7 @@ struct Data // because we have a cycle dependency ClangBackEnd::BuildDependencyCollector buildDependencyCollector{filePathCache, generatedFiles, environment}; - std::function<TimeStamp(FilePathView filePath)> getModifiedTime{ - [&](ClangBackEnd::FilePathView path) -> TimeStamp { - return QFileInfo(QString(path)).lastModified().toSecsSinceEpoch(); - }}; - ClangBackEnd::ModifiedTimeChecker<ClangBackEnd::SourceEntries> modifiedTimeChecker{getModifiedTime, - filePathCache}; + ClangBackEnd::ModifiedTimeChecker<ClangBackEnd::SourceEntries> modifiedTimeChecker{fileSystem}; ClangBackEnd::BuildDependenciesProvider buildDependencyProvider{buildDependencyStorage, modifiedTimeChecker, buildDependencyCollector, diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h b/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h index 8c8c51a6cd..187a27cf89 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h @@ -66,10 +66,9 @@ public: } } - FilePathIds fetchSources(ProjectPartId projectPartId) const override + FilePathIds fetchPchSources(ProjectPartId projectPartId) const override { - return fetchProjectPartsFilesStatement.template values<FilePathId>(1024, - projectPartId.projectPathId); + return fetchPchSourcesStatement.template values<FilePathId>(1024, projectPartId.projectPathId); } void insertOrUpdateFileStatuses(const FileStatuses &fileStatuses) override @@ -252,8 +251,10 @@ public: "CONFLICT(sourceId, projectPartId) DO UPDATE SET sourceType = ?003, " "hasMissingIncludes = ?004", database}; - mutable ReadStatement fetchProjectPartsFilesStatement{ - "SELECT sourceId FROM projectPartsFiles WHERE projectPartId = ? ORDER BY sourceId", database}; + mutable ReadStatement fetchPchSourcesStatement{ + "SELECT sourceId FROM projectPartsFiles WHERE projectPartId = ? AND sourceType IN (0, 1, " + "3, 4) ORDER BY sourceId", + database}; mutable ReadStatement fetchSourceDependenciesStatement{ "WITH RECURSIVE collectedDependencies(sourceId) AS (VALUES(?) UNION " "SELECT dependencySourceId FROM sourceDependencies, " diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h b/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h index 1166564b32..a1c20811aa 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h @@ -56,7 +56,7 @@ public: virtual UsedMacros fetchUsedMacros(FilePathId sourceId) const = 0; virtual ProjectPartId fetchProjectPartId(Utils::SmallStringView projectPartName) = 0; virtual void updatePchCreationTimeStamp(long long pchCreationTimeStamp, ProjectPartId projectPartId) = 0; - virtual FilePathIds fetchSources(ProjectPartId projectPartId) const = 0; + virtual FilePathIds fetchPchSources(ProjectPartId projectPartId) const = 0; protected: ~BuildDependenciesStorageInterface() = default; diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp index cd7b492868..15c9a19547 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp @@ -114,7 +114,7 @@ void PchCreator::generatePch(PchTask &&pchTask) { m_projectPartPch.projectPartId = pchTask.projectPartId(); m_projectPartPch.lastModified = QDateTime::currentSecsSinceEpoch(); - + m_sources = std::move(pchTask.sources); if (pchTask.includes.empty()) return; @@ -127,10 +127,9 @@ void PchCreator::generatePch(PchTask &&pchTask) m_clangTool.addFile(std::move(headerFilePath), content.clone(), std::move(commandLine)); bool success = generatePch(NativeFilePath{headerFilePath}, content); - if (success) { - m_sources = pchTask.sources; - m_projectPartPch.pchPath = std::move(pchOutputPath); - } + + if (success) + m_projectPartPch.pchPath = std::move(pchOutputPath); } const ProjectPartPch &PchCreator::projectPartPch() diff --git a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h index 9db3c683b9..2d16b484a1 100644 --- a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h +++ b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h @@ -128,23 +128,26 @@ private: case SourceType::TopSystemInclude: topSystemIncludes.emplace_back(source.sourceId); systemIncludes.emplace_back(source.sourceId); + sources.emplace_back(source.sourceId); break; case SourceType::SystemInclude: systemIncludes.emplace_back(source.sourceId); + sources.emplace_back(source.sourceId); break; case SourceType::TopProjectInclude: topProjectIncludes.emplace_back(source.sourceId); projectIncludes.emplace_back(source.sourceId); + sources.emplace_back(source.sourceId); break; case SourceType::ProjectInclude: projectIncludes.emplace_back(source.sourceId); + sources.emplace_back(source.sourceId); break; case SourceType::UserInclude: case SourceType::Source: break; } - sources.emplace_back(source.sourceId); } static Utils::SmallStringVector filterUsedMarcos(const UsedMacros &usedMacros, diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri index e7e83da788..a3da84d83b 100644 --- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri @@ -17,8 +17,6 @@ HEADERS += \ $$PWD/symbolsvisitorbase.h \ $$PWD/usedmacro.h \ $$PWD/sourcedependency.h \ - $$PWD/filestatus.h \ - $$PWD/filestatuscache.h \ $$PWD/indexdataconsumer.h \ $$PWD/sourcesmanager.h \ $$PWD/symbolindexertaskqueue.h \ @@ -67,5 +65,4 @@ HEADERS += \ SOURCES += \ $$PWD/filestatuspreprocessorcallbacks.cpp \ $$PWD/sourcerangefilter.cpp \ - $$PWD/symbolindexer.cpp \ - $$PWD/filestatuscache.cpp + $$PWD/symbolindexer.cpp diff --git a/src/tools/clangrefactoringbackend/source/filestatuscache.cpp b/src/tools/clangrefactoringbackend/source/filestatuscache.cpp deleted file mode 100644 index 14ad48da14..0000000000 --- a/src/tools/clangrefactoringbackend/source/filestatuscache.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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. -** -****************************************************************************/ - -#include "filestatuscache.h" - -#include <QDateTime> -#include <QFileInfo> - -namespace ClangBackEnd { - -FileStatusCache::FileStatusCache(FilePathCachingInterface &filePathCache) - : m_filePathCache(filePathCache) -{ - -} - -long long FileStatusCache::lastModifiedTime(FilePathId filePathId) const -{ - return findEntry(filePathId).lastModified; -} - -void FileStatusCache::update(FilePathId filePathId) -{ - auto found = std::lower_bound(m_cacheEntries.begin(), - m_cacheEntries.end(), - Internal::FileStatusCacheEntry{filePathId}, - [] (const auto &first, const auto &second) { - return first.filePathId < second.filePathId; - }); - - if (found != m_cacheEntries.end() && found->filePathId == filePathId) { - QFileInfo fileInfo = qFileInfo(filePathId); - found->lastModified = fileInfo.lastModified().toMSecsSinceEpoch() / 1000; - } -} - -FileStatusCache::size_type FileStatusCache::size() const -{ - return m_cacheEntries.size(); -} - -Internal::FileStatusCacheEntry FileStatusCache::findEntry(FilePathId filePathId) const -{ - auto found = std::lower_bound(m_cacheEntries.begin(), - m_cacheEntries.end(), - Internal::FileStatusCacheEntry{filePathId}, - [] (const auto &first, const auto &second) { - return first.filePathId < second.filePathId; - }); - - if (found != m_cacheEntries.end() && found->filePathId == filePathId) - return *found; - - QFileInfo fileInfo = qFileInfo(filePathId); - auto inserted = m_cacheEntries.emplace(found, - filePathId, - fileInfo.lastModified().toMSecsSinceEpoch() / 1000); - - return *inserted; -} - -QFileInfo FileStatusCache::qFileInfo(FilePathId filePathId) const -{ - QFileInfo fileInfo(QString(m_filePathCache.filePath(filePathId))); - - fileInfo.refresh(); - - return fileInfo; -} - -} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp index 1ee61eb67c..4f3a6f172f 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp @@ -87,8 +87,8 @@ SymbolIndexer::SymbolIndexer(SymbolIndexerTaskQueueInterface &symbolIndexerTaskQ void SymbolIndexer::updateProjectParts(ProjectPartContainers &&projectParts) { - for (ProjectPartContainer &projectPart : projectParts) - updateProjectPart(std::move(projectPart)); + for (ProjectPartContainer &projectPart : projectParts) + updateProjectPart(std::move(projectPart)); } void SymbolIndexer::updateProjectPart(ProjectPartContainer &&projectPart) @@ -145,7 +145,7 @@ void SymbolIndexer::updateProjectPart(ProjectPartContainer &&projectPart) } m_pathWatcher.updateIdPaths( - {{projectPartId, m_buildDependencyStorage.fetchSources(projectPartId)}}); + {{projectPartId, m_buildDependencyStorage.fetchPchSources(projectPartId)}}); m_symbolIndexerTaskQueue.addOrUpdateTasks(std::move(symbolIndexerTask)); m_symbolIndexerTaskQueue.processEntries(); } @@ -154,6 +154,8 @@ void SymbolIndexer::pathsWithIdsChanged(const ProjectPartIds &) {} void SymbolIndexer::pathsChanged(const FilePathIds &filePathIds) { + m_modifiedTimeChecker.pathsChanged(filePathIds); + FilePathIds dependentSourcePathIds = m_symbolStorage.fetchDependentSourceIds(filePathIds); std::vector<SymbolIndexerTask> symbolIndexerTask; diff --git a/src/tools/clangrefactoringbackend/source/symbolindexer.h b/src/tools/clangrefactoringbackend/source/symbolindexer.h index 64b442bf33..d969cd8026 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexer.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexer.h @@ -29,8 +29,8 @@ #include "symbolindexertaskqueueinterface.h" #include "symbolstorageinterface.h" #include "builddependenciesstorageinterface.h" -#include "clangpathwatcher.h" +#include <clangpathwatcher.h> #include <filecontainerv2.h> #include <modifiedtimecheckerinterface.h> #include <precompiledheaderstorageinterface.h> diff --git a/src/tools/clangrefactoringbackend/source/symbolindexing.h b/src/tools/clangrefactoringbackend/source/symbolindexing.h index 5c391503bf..936a34af00 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexing.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexing.h @@ -39,6 +39,7 @@ #include <projectpartsstorage.h> #include <filepathcachingfwd.h> +#include <filesystem.h> #include <modifiedtimechecker.h> #include <refactoringdatabaseinitializer.h> @@ -142,16 +143,12 @@ private: PrecompiledHeaderStorage<Sqlite::Database> m_precompiledHeaderStorage; ProjectPartsStorage<Sqlite::Database> m_projectPartsStorage; SymbolStorage m_symbolStorage; - ClangPathWatcher<QFileSystemWatcher, QTimer> m_sourceWatcher{m_filePathCache}; - FileStatusCache m_fileStatusCache{m_filePathCache}; + FileSystem m_fileSytem{m_filePathCache}; + ClangPathWatcher<QFileSystemWatcher, QTimer> m_sourceWatcher{m_filePathCache, m_fileSytem}; + FileStatusCache m_fileStatusCache{m_fileSytem}; SymbolsCollectorManager m_collectorManger; ProgressCounter m_progressCounter; - std::function<TimeStamp(FilePathView filePath)> getModifiedTime{ - [&](ClangBackEnd::FilePathView path) -> TimeStamp { - return QFileInfo(QString(path)).lastModified().toSecsSinceEpoch(); - }}; - ModifiedTimeChecker<ClangBackEnd::SourceTimeStamps> m_modifiedTimeChecker{getModifiedTime, - m_filePathCache}; + ModifiedTimeChecker<ClangBackEnd::SourceTimeStamps> m_modifiedTimeChecker{m_fileSytem}; SymbolIndexer m_indexer; SymbolIndexerTaskQueue m_indexerQueue; SymbolIndexerTaskScheduler m_indexerScheduler; diff --git a/src/tools/clangrefactoringbackend/source/symbolscollector.cpp b/src/tools/clangrefactoringbackend/source/symbolscollector.cpp index 071837ac52..ab5a00fc6b 100644 --- a/src/tools/clangrefactoringbackend/source/symbolscollector.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolscollector.cpp @@ -129,7 +129,11 @@ bool SymbolsCollector::collectSymbols() auto actionFactory = ClangBackEnd::newFrontendActionFactory(&m_collectSymbolsAction); - return tool.run(actionFactory.get()) != 1; + bool noErrors = tool.run(actionFactory.get()) != 1; + + m_clangTool = ClangTool(); + + return noErrors; } void SymbolsCollector::doInMainThreadAfterFinished() diff --git a/src/tools/clangrefactoringbackend/source/symbolscollector.h b/src/tools/clangrefactoringbackend/source/symbolscollector.h index cc7ca4396c..e103471372 100644 --- a/src/tools/clangrefactoringbackend/source/symbolscollector.h +++ b/src/tools/clangrefactoringbackend/source/symbolscollector.h @@ -63,6 +63,8 @@ public: bool isUsed() const override; void setIsUsed(bool isUsed) override; + bool isClean() const { return m_clangTool.isClean(); } + private: FilePathCaching m_filePathCache; ClangTool m_clangTool; diff --git a/src/tools/qtcdebugger/main.cpp b/src/tools/qtcdebugger/main.cpp index 38507c8539..6beda7c1ec 100644 --- a/src/tools/qtcdebugger/main.cpp +++ b/src/tools/qtcdebugger/main.cpp @@ -419,6 +419,15 @@ static bool registerDebuggerKey(const WCHAR *key, do { if (!openRegistryKey(HKEY_LOCAL_MACHINE, key, true, &handle, access, errorMessage)) break; + + // Make sure to automatically open the qtcdebugger dialog on a crash + QString autoVal; + registryReadStringKey(handle, autoRegistryValueNameC, &autoVal, errorMessage); + if (autoVal != "1") { + if (!registryWriteStringKey(handle, autoRegistryValueNameC, "1", errorMessage)) + break; + } + // Save old key, which might be missing QString oldDebugger; if (isRegistered(handle, call, errorMessage, &oldDebugger)) { diff --git a/tests/system/objects.map b/tests/system/objects.map index 276ae23b35..c6064297c7 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -76,10 +76,10 @@ :FormEditorStack.menuBar_QDesignerMenuBar {container=':*Qt Creator.FormEditorStack_Designer::Internal::FormEditorStack' name='menuBar' type='QDesignerMenuBar' visible='1'} :FormEditorStack_qdesigner_internal::FormWindow {container=':*Qt Creator.FormEditorStack_Designer::Internal::FormEditorStack' type='qdesigner_internal::FormWindow' unnamed='1' visible='1'} :FormEditorStack_qdesigner_internal::PropertyLineEdit {container=':*Qt Creator.FormEditorStack_Designer::Internal::FormEditorStack' type='qdesigner_internal::PropertyLineEdit' unnamed='1' visible='1'} -:Git Repository Clone.Cancel_QPushButton {text='Cancel' type='QPushButton' visible='1' window=':New Text File_ProjectExplorer::JsonWizard'} -:Git Repository Clone.Finish_QPushButton {text~='(Finish|Done)' type='QPushButton' visible='1' window=':New Text File_ProjectExplorer::JsonWizard'} -:Git Repository Clone.Result._QLabel {type='QLabel' unnamed='1' visible='1' window=':New Text File_ProjectExplorer::JsonWizard'} -:Git Repository Clone.logPlainTextEdit_QPlainTextEdit {type='QPlainTextEdit' unnamed='1' visible='1' window=':New Text File_ProjectExplorer::JsonWizard'} +:Git Repository Clone.Cancel_QPushButton {text='Cancel' type='QPushButton' visible='1' window=':New_ProjectExplorer::JsonWizard'} +:Git Repository Clone.Finish_QPushButton {text~='(Finish|Done)' type='QPushButton' visible='1' window=':New_ProjectExplorer::JsonWizard'} +:Git Repository Clone.Result._QLabel {type='QLabel' unnamed='1' visible='1' window=':New_ProjectExplorer::JsonWizard'} +:Git Repository Clone.logPlainTextEdit_QPlainTextEdit {type='QPlainTextEdit' unnamed='1' visible='1' window=':New_ProjectExplorer::JsonWizard'} :Go to slot.OK_QPushButton {text='OK' type='QPushButton' unnamed='1' visible='1' window=':Go to slot_QDialog'} :Go to slot.Select signal_QGroupBox {name='groupBox' title='Select signal' type='QGroupBox' visible='1' window=':Go to slot_QDialog'} :Go to slot_QDialog {name='SelectSignalDialog' type='QDialog' visible='1' windowTitle='Go to slot'} @@ -88,14 +88,14 @@ :Hits_QResultWidget {aboveWidget=':Hits_QLabel' type='QResultWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Kits_QtVersion_QComboBox {container=':qt_tabwidget_stackedwidget_QWidget' leftWidget=':QtVersionLabel_KitPage' type='QComboBox' unnamed='1' visible='1'} :Locals and Expressions_Debugger::Internal::WatchTreeView {container=':Debugger.Docks.LocalsAndWatchersDockWidget.Inspector_QFrame' name='WatchWindow' type='Debugger::Internal::WatchTreeView' visible='1'} -:Minimal required Qt version:_QLabel {text='Minimal required Qt version:' type='QLabel' unnamed='1' visible='1' window=':New Text File_ProjectExplorer::JsonWizard'} -:New Text File.Add to project:_QLabel {name='projectLabel' text='Add to project:' type='QLabel' visible='1' window=':New Text File_ProjectExplorer::JsonWizard'} -:New Text File.nameLineEdit_Utils::FileNameValidatingLineEdit {name='nameLineEdit' type='Utils::FileNameValidatingLineEdit' visible='1' window=':New Text File_ProjectExplorer::JsonWizard'} -:New Text File_ProjectExplorer::JsonWizard {type='ProjectExplorer::JsonWizard' unnamed='1' visible='1'} +:Minimal required Qt version:_QLabel {text='Minimal required Qt version:' type='QLabel' unnamed='1' visible='1' window=':New_ProjectExplorer::JsonWizard'} +:New Text File.Add to project:_QLabel {name='projectLabel' text='Add to project:' type='QLabel' visible='1' window=':New_ProjectExplorer::JsonWizard'} +:New Text File.nameLineEdit_Utils::FileNameValidatingLineEdit {name='nameLineEdit' type='Utils::FileNameValidatingLineEdit' visible='1' window=':New_ProjectExplorer::JsonWizard'} :New.comboBox_QComboBox {name='comboBox' type='QComboBox' visible='1' window=':New_Core::Internal::NewDialog'} :New.frame_QFrame {name='frame' type='QFrame' visible='1' window=':New_Core::Internal::NewDialog'} :New.templateCategoryView_QTreeView {name='templateCategoryView' type='QTreeView' visible='1' window=':New_Core::Internal::NewDialog'} :New_Core::Internal::NewDialog {name='Core__Internal__NewDialog' type='Core::Internal::NewDialog' visible='1' windowTitle?='New*'} +:New_ProjectExplorer::JsonWizard {type='ProjectExplorer::JsonWizard' unnamed='1' visible='1'} :Next_QPushButton {text~='(Next.*|Continue)' type='QPushButton' visible='1'} :No valid kits found._QLabel {text?='*No valid kits found.*' type='QLabel' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :OpenDocuments_Widget {type='Core::Internal::OpenEditorsWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='Open Documents'} @@ -163,10 +163,6 @@ :Qt Creator_Utils::BuildDirectoryLineEdit {name='shadowBuildDirEditLineEdit' type='Utils::FancyLineEdit' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Qt Creator_Utils::NavigationTreeView {type='Utils::NavigationTreeView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Qt Creator_Utils::NavigationTreeView::QExpandingLineEdit {container=':Qt Creator_Utils::NavigationTreeView' type='QExpandingLineEdit' unnamed='1' visible='1'} -:Qt Gui Application.Form file:_QLabel {name='formLabel' text='Form file:' type='QLabel' visible='1' window=':Qt Gui Application_QmakeProjectManager::Internal::GuiAppWizardDialog'} -:Qt Gui Application.Header file:_QLabel {name='headerLabel' text='Header file:' type='QLabel' visible='1' window=':Qt Gui Application_QmakeProjectManager::Internal::GuiAppWizardDialog'} -:Qt Gui Application.Source file:_QLabel {name='sourceLabel' text='Source file:' type='QLabel' visible='1' window=':Qt Gui Application_QmakeProjectManager::Internal::GuiAppWizardDialog'} -:Qt Gui Application_QmakeProjectManager::Internal::GuiAppWizardDialog {type='QmakeProjectManager::Internal::GuiAppWizardDialog' unnamed='1' visible='1' windowTitle='Qt Widgets Application'} :QtSupport__Internal__QtVersionManager.QLabel {container=':qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget' text?='Qt version *' type='QLabel' unnamed='1' visible='1'} :QtSupport__Internal__QtVersionManager.errorLabel.QLabel {container=':qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget' name='errorLabel' type='QLabel' visible='1'} :QtSupport__Internal__QtVersionManager.qmake_QLabel {container=':qt_tabwidget_stackedwidget.QtSupport__Internal__QtVersionManager_QtSupport::Internal::QtOptionsPageWidget' name='qmakePath' type='QLabel' visible='1'} @@ -186,7 +182,6 @@ :Select a Git Commit.workingDirectoryEdit_QLineEdit {type='Utils::FancyLineEdit' unnamed='1' visible='1' window=':Select a Git Commit_Git::Internal::ChangeSelectionDialog'} :Select a Git Commit_Git::Internal::ChangeSelectionDialog {name='Git__Internal__ChangeSelectionDialog' type='Git::Internal::ChangeSelectionDialog' visible='1' windowTitle='Select a Git Commit'} :Select signal.signalList_QTreeView {container=':Go to slot.Select signal_QGroupBox' name='signalList' type='QTreeView' visible='1'} -:Select signal.signalList_QTreeWidget {container=':Go to slot.Select signal_QGroupBox' name='signalList' type='QTreeWidget' visible='1'} :Send to Codepaster.Cancel_QPushButton {text='Cancel' type='QPushButton' unnamed='1' visible='1' window=':Send to Codepaster_CodePaster::PasteView'} :Send to Codepaster.Description:_QLabel {name='descriptionLabel' text='Description:' type='QLabel' visible='1' window=':Send to Codepaster_CodePaster::PasteView'} :Send to Codepaster.Paste_QPushButton {text='Paste' type='QPushButton' unnamed='1' visible='1' window=':Send to Codepaster_CodePaster::PasteView'} @@ -200,12 +195,12 @@ :Take a UI Tour_Utils::CheckableMessageBox {type='Utils::CheckableMessageBox' unnamed='1' visible='1' windowTitle='Take a UI Tour'} :User Interface.languageBox_QComboBox {container=':Core__Internal__GeneralSettings.User Interface_QGroupBox' name='languageBox' type='QComboBox' visible='1'} :Widget Box_qdesigner_internal::WidgetBoxTreeWidget {container=':*Qt Creator.Widget Box_QDockWidget' type='qdesigner_internal::WidgetBoxTreeWidget' unnamed='1' visible='1'} -:Working Copy_Utils::BaseValidatingLineEdit {type='Utils::FancyLineEdit' unnamed='1' visible='1' window=':New Text File_ProjectExplorer::JsonWizard'} +:Working Copy_Utils::BaseValidatingLineEdit {type='Utils::FancyLineEdit' unnamed='1' visible='1' window=':New_ProjectExplorer::JsonWizard'} :WritePermissions_Core::Internal::ReadOnlyFilesDialog {name='Core__Internal__ReadOnlyFilesDialog' type='Core::ReadOnlyFilesDialog' visible='1' windowTitle='Files Without Write Permissions'} :addToVersionControlComboBox_QComboBox {name='addToVersionControlComboBox' type='QComboBox' visible='1'} -:formFileLineEdit_Utils::FileNameValidatingLineEdit {buddy=':Qt Gui Application.Form file:_QLabel' name='formFileLineEdit' type='Utils::FileNameValidatingLineEdit' visible='1'} +:formFileLineEdit_Utils::FileNameValidatingLineEdit {name='FormFileName' type='Utils::FancyLineEdit' visible='1' window=':New_ProjectExplorer::JsonWizard'} :frame.templateDescription_QTextBrowser {container=':New.frame_QFrame' name='templateDescription' type='QTextBrowser' visible='1'} -:headerFileLineEdit_Utils::FileNameValidatingLineEdit {buddy=':Qt Gui Application.Header file:_QLabel' name='headerFileLineEdit' type='Utils::FileNameValidatingLineEdit' visible='1'} +:headerFileLineEdit_Utils::FileNameValidatingLineEdit {name='HdrFileName' type='Utils::FancyLineEdit' visible='1' window=':New_ProjectExplorer::JsonWizard'} :popupFrame_Proposal_QListView {container=':popupFrame_TextEditor::GenericProposalWidget' type='QListView' unnamed='1' visible='1'} :popupFrame_TextEditor::GenericProposalWidget {name='m_popupFrame' type='TextEditor::GenericProposalWidget' visible='1'} :projectComboBox_QComboBox {buddy=':New Text File.Add to project:_QLabel' name='projectComboBox' type='QComboBox' visible='1'} @@ -222,7 +217,7 @@ :scrollArea.Edit build configuration:_QLabel {text='Edit build configuration:' type='QLabel' unnamed='1' visible='1'} :scrollArea.Library not available_QLabel {name='qmlDebuggingWarningText' text?='Library not available*' type='QLabel' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :scrollArea.qmlDebuggingLibraryCheckBox_QCheckBox {name='qmlDebuggingLibraryCheckBox' type='QCheckBox' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} -:sourceFileLineEdit_Utils::FileNameValidatingLineEdit {buddy=':Qt Gui Application.Source file:_QLabel' name='sourceFileLineEdit' type='Utils::FileNameValidatingLineEdit' visible='1'} +:sourceFileLineEdit_Utils::FileNameValidatingLineEdit {name='SrcFileName' type='Utils::FancyLineEdit' visible='1' window=':New_ProjectExplorer::JsonWizard'} :splitter.Commit File(s)_VcsBase::QActionPushButton {text~='(Commit .+/.+ File.*)' type='VcsBase::QActionPushButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :splitter.Description_QGroupBox {container=':Qt Creator.splitter_QSplitter' name='descriptionBox' title='Description' type='QGroupBox' visible='1'} :splitter.Files_QGroupBox {container=':Qt Creator.splitter_QSplitter' name='groupBox' title='Files' type='QGroupBox' visible='1'} diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index a4be7f14d1..a0eea63b82 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -53,17 +53,17 @@ def openQmakeProject(projectPath, targets=Targets.desktopTargetClasses(), fromWe def openCmakeProject(projectPath, buildDir): def additionalFunction(): - pChooser = waitForObject("{leftWidget={text='Default' type='QCheckBox' unnamed='1' " + pChooser = waitForObject("{leftWidget={text='Debug' type='QCheckBox' unnamed='1' " "visible='1'} type='Utils::PathChooser' unnamed='1' visible='1'}") lineEdit = getChildByClass(pChooser, "Utils::FancyLineEdit") replaceEditorContent(lineEdit, buildDir) - # disable all build configurations except "Default" - configs = ['Debug', 'Release', 'Release with Debug Information', 'Minimum Size Release'] + # disable all build configurations except "Debug" + configs = ['Release', 'Release with Debug Information', 'Minimum Size Release'] for checkbox in configs: ensureChecked(waitForObject("{text='%s' type='QCheckBox' unnamed='1' visible='1' " "window=':Qt Creator_Core::Internal::MainWindow'}" % checkbox), False) - ensureChecked(waitForObject("{text='Default' type='QCheckBox' unnamed='1' visible='1' " + ensureChecked(waitForObject("{text='Debug' type='QCheckBox' unnamed='1' visible='1' " "window=':Qt Creator_Core::Internal::MainWindow'}"), True) invokeMenuItem("File", "Open File or Project...") @@ -216,7 +216,7 @@ def createProject_Qt_GUI(path, projectName, checks = True, addToVersionControl = template = "Qt Widgets Application" available = __createProjectOrFileSelectType__(" Application", template) __createProjectSetNameAndPath__(path, projectName, checks) - __selectQtVersionDesktop__(checks, available, True) + __handleBuildSystem__(None) if checks: exp_filename = "mainwindow" @@ -234,6 +234,7 @@ def createProject_Qt_GUI(path, projectName, checks = True, addToVersionControl = test.compare(findObject(":formFileLineEdit_Utils::FileNameValidatingLineEdit").text, ui_file) clickButton(waitForObject(":Next_QPushButton")) + __selectQtVersionDesktop__(checks, available, True) expectedFiles = [] if checks: diff --git a/tests/system/suite_debugger/tst_qml_locals/test.py b/tests/system/suite_debugger/tst_qml_locals/test.py index 0430c306c9..f85a2d3b23 100644 --- a/tests/system/suite_debugger/tst_qml_locals/test.py +++ b/tests/system/suite_debugger/tst_qml_locals/test.py @@ -122,7 +122,8 @@ def fetchItems(index, valIndex, treeView): tree.setName(name) tree.setValue(value) for row in range(model.rowCount(index)): - tree.addChild(fetchItems(model.index(row, 0, index), model.index(row, 1, index), treeView)) + tree.addChild(fetchItems(model.index(row, 0, index), + model.index(row, 2, index), treeView)) return tree def checkForEmptyRows(items, isRootCheck=True): diff --git a/tests/system/suite_editors/tst_edit_externally/test.py b/tests/system/suite_editors/tst_edit_externally/test.py index ec6fcd9203..9c2ea61d2c 100644 --- a/tests/system/suite_editors/tst_edit_externally/test.py +++ b/tests/system/suite_editors/tst_edit_externally/test.py @@ -47,7 +47,8 @@ def main(): mBox = ("{text?='The file * has been changed on disk. Do you want to reload it?' " "type='QMessageBox' unnamed='1' visible='1'}") - popupText = "The file <i>%s</i> has been changed on disk. Do you want to reload it?" + popupText = ("<p>The file <i>%s</i> has been changed on disk. Do you want to reload it?</p>" + "<p>The default behavior can be set in Tools > Options > Environment > System.</p>") formerContent = None for i, currentFile in enumerate(files): diff --git a/tests/system/suite_general/tst_default_settings/test.py b/tests/system/suite_general/tst_default_settings/test.py index 928f890b2a..3270f619e5 100644 --- a/tests/system/suite_general/tst_default_settings/test.py +++ b/tests/system/suite_general/tst_default_settings/test.py @@ -121,14 +121,8 @@ def __compFunc__(it, foundComp, foundCompNames): pathLineEdit = findObject(":Path.Utils_BaseValidatingLineEdit") foundComp.append(str(pathLineEdit.text)) except: - objectString = ("{buddy={container=':qt_tabwidget_stackedwidget_QWidget'" - " text='Initialization:' type='QLabel' unnamed='1' visible='1'}" - " type='%s' unnamed='1' visible='1'}") - try: - foundText = findObject(objectString % "QLabel").text - except: - foundText = findObject(objectString % "QComboBox").currentText - foundComp.append({it:str(foundText)}) + varsBatCombo = waitForObjectExists("{name='varsBatCombo' type='QComboBox' visible='1'}") + foundComp.append({it:str(varsBatCombo.currentText)}) foundCompNames.append(it) diff --git a/tests/system/suite_tools/tst_designer_goto_slot/test.py b/tests/system/suite_tools/tst_designer_goto_slot/test.py index eadea648ae..f1e47727db 100644 --- a/tests/system/suite_tools/tst_designer_goto_slot/test.py +++ b/tests/system/suite_tools/tst_designer_goto_slot/test.py @@ -50,14 +50,8 @@ def main(): waitFor("macHackActivateContextMenuItem('Go to slot...', con[0])", 6000) else: activateItem(waitForObjectItem("{type='QMenu' unnamed='1' visible='1'}", "Go to slot...")) - try: - # Creator built with Qt <= 5.9 - signalWidgetObject = waitForObject(":Select signal.signalList_QTreeWidget", 5000) - signalName = con[2] - except: - # Creator built with Qt >= 5.10 - signalWidgetObject = waitForObject(":Select signal.signalList_QTreeView") - signalName = con[1] + "." + con[2] + signalWidgetObject = waitForObject(":Select signal.signalList_QTreeView") + signalName = con[1] + "." + con[2] waitForObjectItem(signalWidgetObject, signalName) clickItem(signalWidgetObject, signalName, 5, 5, 0, Qt.LeftButton) clickButton(waitForObject(":Go to slot.OK_QPushButton")) diff --git a/tests/system/suite_tools/tst_git_clone/test.py b/tests/system/suite_tools/tst_git_clone/test.py index dbafe77690..476c1be365 100644 --- a/tests/system/suite_tools/tst_git_clone/test.py +++ b/tests/system/suite_tools/tst_git_clone/test.py @@ -55,7 +55,7 @@ def verifyCloneLog(targetDir, canceled): if canceled: test.warning("Could not find resultLabel", "Cloning might have failed before clicking 'Cancel'") - return object.exists(":New Text File_ProjectExplorer::JsonWizard") + return object.exists(":New_ProjectExplorer::JsonWizard") else: test.fail("Could not find resultLabel") return True diff --git a/tests/system/suite_tools/tst_git_local/test.py b/tests/system/suite_tools/tst_git_local/test.py index d5617642f4..8cbdfc42c6 100644 --- a/tests/system/suite_tools/tst_git_local/test.py +++ b/tests/system/suite_tools/tst_git_local/test.py @@ -146,9 +146,9 @@ def verifyClickCommit(): "Verifying whether diff editor contains pointless_header.h file.") test.verify(pointlessHeader not in diffOriginal, "Verifying whether original does not contain pointless_header.h file.") - test.verify("HEADERS += \\\n mainwindow.h \\\n pointless_header.h\n" in diffChanged, + test.verify("HEADERS += \\\n mainwindow.h \\\n pointless_header.h\n" in diffChanged, "Verifying whether diff editor has pointless_header.h listed in pro file.") - test.verify("HEADERS += \\\n mainwindow.h\n\n" in diffOriginal + test.verify("HEADERS += \\\n mainwindow.h\n\n" in diffOriginal and "pointless_header.h" not in diffOriginal, "Verifying whether original has no additional header in pro file.") test.verify(original.readOnly and changed.readOnly, @@ -173,7 +173,7 @@ def main(): % os.path.join(srcPath, projectName, ".git").replace("\\", "/") in str(vcsLog), "Has initialization of repo been logged:\n%s " % vcsLog) createLocalGitConfig(os.path.join(srcPath, projectName, ".git")) - commitMessages = [commit("Initial Commit", "Committed 5 files.")] + commitMessages = [commit("Initial Commit", "Committed 6 files.")] clickButton(waitForObject(":*Qt Creator.Clear_QToolButton")) headerName = "pointless_header.h" addCPlusPlusFile(headerName, "C++ Header File", projectName + ".pro", diff --git a/tests/unit/unittest/builddependenciesstorage-test.cpp b/tests/unit/unittest/builddependenciesstorage-test.cpp index 052ed452f0..d14b94fe30 100644 --- a/tests/unit/unittest/builddependenciesstorage-test.cpp +++ b/tests/unit/unittest/builddependenciesstorage-test.cpp @@ -70,7 +70,7 @@ protected: MockSqliteWriteStatement &updatePchCreationTimeStampStatement = storage.updatePchCreationTimeStampStatement; MockSqliteWriteStatement &deleteAllProjectPartsFilesWithProjectPartNameStatement = storage.deleteAllProjectPartsFilesWithProjectPartNameStatement; - MockSqliteReadStatement &fetchProjectPartsFilesStatement = storage.fetchProjectPartsFilesStatement; + MockSqliteReadStatement &fetchProjectPartsFilesStatement = storage.fetchPchSourcesStatement; }; TEST_F(BuildDependenciesStorage, ConvertStringsToJson) @@ -238,7 +238,7 @@ TEST_F(BuildDependenciesStorage, FetchSources) ClangBackEnd::FilePathIds result{3, 5, 7}; EXPECT_CALL(fetchProjectPartsFilesStatement, valuesReturnFilePathIds(_, 22)).WillOnce(Return(result)); - auto sources = storage.fetchSources(22); + auto sources = storage.fetchPchSources(22); ASSERT_THAT(sources, result); } diff --git a/tests/unit/unittest/changedfilepathcompressor-test.cpp b/tests/unit/unittest/changedfilepathcompressor-test.cpp deleted file mode 100644 index 08e66a2541..0000000000 --- a/tests/unit/unittest/changedfilepathcompressor-test.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "googletest.h" - -#include "mocktimer.h" - -#include <changedfilepathcompressor.h> -#include <filepathcaching.h> -#include <refactoringdatabaseinitializer.h> - -namespace { - -using testing::ElementsAre; -using testing::Invoke; -using testing::IsEmpty; -using testing::NiceMock; - -using ClangBackEnd::FilePath; -using ClangBackEnd::FilePathId; - -class ChangedFilePathCompressor : public testing::Test -{ -protected: - void SetUp() - { - compressor.setCallback(mockCompressorCallback.AsStdFunction()); - } - - FilePathId filePathId(const QString &filePath) - { - Utils::SmallString utf8FilePath{filePath}; - - return filePathCache.filePathId(ClangBackEnd::FilePathView{utf8FilePath}); - } - -protected: - Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; - ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> initializer{database}; - ClangBackEnd::FilePathCaching filePathCache{database}; - NiceMock<MockFunction<void (const ClangBackEnd::FilePathIds &filePathIds)>> mockCompressorCallback; - ClangBackEnd::ChangedFilePathCompressor<NiceMock<MockTimer>> compressor{filePathCache}; - NiceMock<MockTimer> &mockTimer = compressor.timer(); - QString filePath1{"filePath1"}; - QString filePath2{"filePath2"}; - FilePathId filePathId1 = filePathId(filePath1); - FilePathId filePathId2 = filePathId(filePath2); -}; - -TEST_F(ChangedFilePathCompressor, AddFilePath) -{ - compressor.addFilePath(filePath1); - - ASSERT_THAT(compressor.takeFilePathIds(), ElementsAre(filePathId(filePath1))); -} - -TEST_F(ChangedFilePathCompressor, NoFilePathsAferTakenThem) -{ - compressor.addFilePath(filePath1); - - compressor.takeFilePathIds(); - - ASSERT_THAT(compressor.takeFilePathIds(), IsEmpty()); -} - -TEST_F(ChangedFilePathCompressor, CallRestartTimerAfterAddingPath) -{ - EXPECT_CALL(mockTimer, start(20)); - - compressor.addFilePath(filePath1); -} - -TEST_F(ChangedFilePathCompressor, CallTimeOutAfterAddingPath) -{ - EXPECT_CALL(mockCompressorCallback, Call(ElementsAre(filePathId1, filePathId2))); - - compressor.addFilePath(filePath1); - compressor.addFilePath(filePath2); -} - -TEST_F(ChangedFilePathCompressor, RemoveDuplicates) -{ - EXPECT_CALL(mockCompressorCallback, Call(ElementsAre(filePathId1, filePathId2))); - - compressor.addFilePath(filePath1); - compressor.addFilePath(filePath2); - compressor.addFilePath(filePath1); -} - -} diff --git a/tests/unit/unittest/clangpathwatcher-test.cpp b/tests/unit/unittest/clangpathwatcher-test.cpp index 00fe91dc49..f4d99e358d 100644 --- a/tests/unit/unittest/clangpathwatcher-test.cpp +++ b/tests/unit/unittest/clangpathwatcher-test.cpp @@ -25,10 +25,11 @@ #include "googletest.h" -#include "mocktimer.h" +#include "mockclangpathwatchernotifier.h" #include "mockfilepathcaching.h" +#include "mockfilesystem.h" #include "mockqfilesystemwatcher.h" -#include "mockclangpathwatchernotifier.h" +#include "mocktimer.h" #include <clangpathwatcher.h> @@ -55,91 +56,126 @@ using ClangBackEnd::WatcherEntry; class ClangPathWatcher : public testing::Test { protected: - void SetUp(); + void SetUp() + { + ON_CALL(mockFilePathCache, filePathId(Eq(path1))).WillByDefault(Return(pathIds[0])); + ON_CALL(mockFilePathCache, filePathId(Eq(path2))).WillByDefault(Return(pathIds[1])); + ON_CALL(mockFilePathCache, filePathId(Eq(path3))).WillByDefault(Return(pathIds[2])); + ON_CALL(mockFilePathCache, filePathId(Eq(path4))).WillByDefault(Return(pathIds[3])); + ON_CALL(mockFilePathCache, filePathId(Eq(path5))).WillByDefault(Return(pathIds[4])); + ON_CALL(mockFilePathCache, filePath(Eq(pathIds[0]))).WillByDefault(Return(FilePath{path1})); + ON_CALL(mockFilePathCache, filePath(Eq(pathIds[1]))).WillByDefault(Return(FilePath{path2})); + ON_CALL(mockFilePathCache, filePath(Eq(pathIds[2]))).WillByDefault(Return(FilePath{path3})); + ON_CALL(mockFilePathCache, filePath(Eq(pathIds[3]))).WillByDefault(Return(FilePath{path4})); + ON_CALL(mockFilePathCache, filePath(Eq(pathIds[4]))).WillByDefault(Return(FilePath{path5})); + ON_CALL(mockFilePathCache, directoryPathId(TypedEq<FilePathId>(pathIds[0]))) + .WillByDefault(Return(directoryPaths[0])); + ON_CALL(mockFilePathCache, directoryPathId(TypedEq<FilePathId>(pathIds[1]))) + .WillByDefault(Return(directoryPaths[0])); + ON_CALL(mockFilePathCache, directoryPathId(TypedEq<FilePathId>(pathIds[2]))) + .WillByDefault(Return(directoryPaths[1])); + ON_CALL(mockFilePathCache, directoryPathId(TypedEq<FilePathId>(pathIds[3]))) + .WillByDefault(Return(directoryPaths[1])); + ON_CALL(mockFilePathCache, directoryPathId(TypedEq<FilePathId>(pathIds[4]))) + .WillByDefault(Return(directoryPaths[2])); + ON_CALL(mockFileSystem, lastModified(_)).WillByDefault(Return(1)); + ON_CALL(mockFilePathCache, + directoryPathId(TypedEq<Utils::SmallStringView>(directoryPathString))) + .WillByDefault(Return(directoryPaths[0])); + ON_CALL(mockFilePathCache, + directoryPathId(TypedEq<Utils::SmallStringView>(directoryPathString2))) + .WillByDefault(Return(directoryPaths[1])); + ON_CALL(mockFilePathCache, directoryPath(Eq(directoryPaths[0]))) + .WillByDefault(Return(directoryPath)); + ON_CALL(mockFilePathCache, directoryPath(Eq(directoryPaths[1]))) + .WillByDefault(Return(directoryPath2)); + ON_CALL(mockFilePathCache, directoryPath(Eq(directoryPaths[2]))) + .WillByDefault(Return(directoryPath3)); + ON_CALL(mockFileSystem, directoryEntries(Eq(directoryPath))) + .WillByDefault(Return(FilePathIds{pathIds[0], pathIds[1]})); + ON_CALL(mockFileSystem, directoryEntries(Eq(directoryPath2))) + .WillByDefault(Return(FilePathIds{pathIds[2], pathIds[3]})); + ON_CALL(mockFileSystem, directoryEntries(Eq(directoryPath3))) + .WillByDefault(Return(FilePathIds{pathIds[4]})); + } static WatcherEntries sorted(WatcherEntries &&entries) { std::stable_sort(entries.begin(), entries.end()); - return entries; + return std::move(entries); } protected: - NiceMock<MockFilePathCaching> filePathCache; + NiceMock<MockFilePathCaching> mockFilePathCache; NiceMock<MockClangPathWatcherNotifier> notifier; - Watcher watcher{filePathCache, ¬ifier}; + NiceMock<MockFileSystem> mockFileSystem; + Watcher watcher{mockFilePathCache, mockFileSystem, ¬ifier}; NiceMock<MockQFileSytemWatcher> &mockQFileSytemWatcher = watcher.fileSystemWatcher(); ProjectPartId id1{2}; ProjectPartId id2{3}; ProjectPartId id3{4}; FilePathView path1{"/path/path1"}; FilePathView path2{"/path/path2"}; + FilePathView path3{"/path2/path1"}; + FilePathView path4{"/path2/path2"}; + FilePathView path5{"/path3/path"}; QString path1QString = QString(path1.toStringView()); QString path2QString = QString(path2.toStringView()); - FilePathIds pathIds = {1, 2}; + QString directoryPath = "/path"; + QString directoryPath2 = "/path2"; + QString directoryPath3 = "/path3"; + Utils::PathString directoryPathString = directoryPath; + Utils::PathString directoryPathString2 = directoryPath2; + FilePathIds pathIds = {1, 2, 3, 4, 5}; + ClangBackEnd::DirectoryPathIds directoryPaths = {1, 2, 3}; ClangBackEnd::ProjectPartIds ids{id1, id2, id3}; - WatcherEntry watcherEntry1{ids[0], pathIds[0]}; - WatcherEntry watcherEntry2{ids[1], pathIds[0]}; - WatcherEntry watcherEntry3{ids[0], pathIds[1]}; - WatcherEntry watcherEntry4{ids[1], pathIds[1]}; - WatcherEntry watcherEntry5{ids[2], pathIds[1]}; + WatcherEntry watcherEntry1{ids[0], directoryPaths[0], pathIds[0]}; + WatcherEntry watcherEntry2{ids[1], directoryPaths[0], pathIds[0]}; + WatcherEntry watcherEntry3{ids[0], directoryPaths[0], pathIds[1]}; + WatcherEntry watcherEntry4{ids[1], directoryPaths[0], pathIds[1]}; + WatcherEntry watcherEntry5{ids[2], directoryPaths[0], pathIds[1]}; + WatcherEntry watcherEntry6{ids[0], directoryPaths[1], pathIds[2]}; + WatcherEntry watcherEntry7{ids[1], directoryPaths[1], pathIds[3]}; }; -TEST_F(ClangPathWatcher, ConvertWatcherEntriesToQStringList) -{ - auto convertedList = watcher.convertWatcherEntriesToQStringList(sorted({watcherEntry1, watcherEntry3})); - - ASSERT_THAT(convertedList, ElementsAre(path1QString, path2QString)); -} - -TEST_F(ClangPathWatcher, UniquePaths) -{ - auto uniqueEntries = watcher.uniquePaths(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4})); - - ASSERT_THAT(uniqueEntries, ElementsAre(watcherEntry1, watcherEntry3)); -} - -TEST_F(ClangPathWatcher, NotWatchedEntries) -{ - watcher.addEntries({watcherEntry1, watcherEntry4}); - - auto newEntries = watcher.notWatchedEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4})); - - ASSERT_THAT(newEntries, ElementsAre(watcherEntry2, watcherEntry3)); -} - TEST_F(ClangPathWatcher, AddIdPaths) { - EXPECT_CALL(mockQFileSytemWatcher, addPaths(QStringList{path1QString, path2QString})); + EXPECT_CALL(mockQFileSytemWatcher, + addPaths(UnorderedElementsAre(QString(directoryPath), QString(directoryPath2)))); - watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}}); + watcher.updateIdPaths( + {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}}); } TEST_F(ClangPathWatcher, UpdateIdPathsCallsAddPathInFileWatcher) { - watcher.updateIdPaths({{id1, {pathIds[0]}}, {id2, {pathIds[0]}}}); + watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}}); - EXPECT_CALL(mockQFileSytemWatcher, addPaths(QStringList{path2QString})); + EXPECT_CALL(mockQFileSytemWatcher, addPaths(UnorderedElementsAre(QString(directoryPath2)))); - watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}}); + watcher.updateIdPaths( + {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}}); } TEST_F(ClangPathWatcher, UpdateIdPathsAndRemoveUnusedPathsCallsRemovePathInFileWatcher) { - watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}, {id3, {pathIds[0]}}}); + watcher.updateIdPaths( + {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}}); - EXPECT_CALL(mockQFileSytemWatcher, removePaths(QStringList{path2QString})); + EXPECT_CALL(mockQFileSytemWatcher, removePaths(UnorderedElementsAre(QString(directoryPath2)))); - watcher.updateIdPaths({{id1, {pathIds[0]}}, {id2, {pathIds[0]}}}); + watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}}); } TEST_F(ClangPathWatcher, UpdateIdPathsAndRemoveUnusedPathsDoNotCallsRemovePathInFileWatcher) { - watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}, {id3, {pathIds[0]}}}); + watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2]}}, + {id2, {pathIds[0], pathIds[1], pathIds[3]}}, + {id3, {pathIds[0]}}}); - EXPECT_CALL(mockQFileSytemWatcher, removePaths(QStringList{path2QString})) - .Times(0); + EXPECT_CALL(mockQFileSytemWatcher, removePaths(_)).Times(0); - watcher.updateIdPaths({{id1, {pathIds[1]}}, {id2, {pathIds[0]}}}); + watcher.updateIdPaths({{id1, {pathIds[1]}}, {id2, {pathIds[3]}}}); } TEST_F(ClangPathWatcher, UpdateIdPathsAndRemoveUnusedPaths) @@ -165,36 +201,18 @@ TEST_F(ClangPathWatcher, ExtractSortedIdsFromConvertIdPaths) ASSERT_THAT(entriesAndIds.second, ElementsAre(ids[0], ids[1], ids[2])); } -TEST_F(ClangPathWatcher, NotWatchedPaths) -{ - watcher.mergeToWatchedEntries(sorted({watcherEntry1})); - - auto newEntries = watcher.notWatchedPaths({watcherEntry2, watcherEntry3}); - - ASSERT_THAT(newEntries, ElementsAre(watcherEntry3)); -} - -TEST_F(ClangPathWatcher, AddedPaths) -{ - watcher.mergeToWatchedEntries(sorted({watcherEntry1, watcherEntry2})); - - auto filteredEntries = watcher.filterNotWatchedPaths({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4}); - - ASSERT_THAT(filteredEntries, ElementsAre(watcherEntry3)); -} - TEST_F(ClangPathWatcher, MergeEntries) { - watcher.mergeToWatchedEntries(sorted({watcherEntry1, watcherEntry4})); + watcher.updateIdPaths({{id1, {pathIds[0]}}, {id2, {pathIds[1]}}}); ASSERT_THAT(watcher.watchedEntries(), ElementsAre(watcherEntry1, watcherEntry4)); } TEST_F(ClangPathWatcher, MergeMoreEntries) { - watcher.mergeToWatchedEntries(sorted({watcherEntry1, watcherEntry4})); + watcher.updateIdPaths({{id2, {pathIds[0], pathIds[1]}}}); - watcher.mergeToWatchedEntries(sorted({watcherEntry2, watcherEntry3})); + watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}}); ASSERT_THAT(watcher.watchedEntries(), ElementsAre(watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4)); } @@ -204,48 +222,48 @@ TEST_F(ClangPathWatcher, AddEmptyEntries) EXPECT_CALL(mockQFileSytemWatcher, addPaths(_)) .Times(0); - watcher.addEntries({}); + watcher.updateIdPaths({}); } TEST_F(ClangPathWatcher, AddEntriesWithSameIdAndDifferentPaths) { - EXPECT_CALL(mockQFileSytemWatcher, addPaths(QStringList{path1QString, path2QString})); + EXPECT_CALL(mockQFileSytemWatcher, + addPaths(ElementsAre(directoryPath, directoryPath2, directoryPath3))); - watcher.addEntries({watcherEntry1, watcherEntry3}); + watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2], pathIds[4]}}}); } TEST_F(ClangPathWatcher, AddEntriesWithDifferentIdAndSamePaths) { - EXPECT_CALL(mockQFileSytemWatcher, addPaths(QStringList{path1QString})); + EXPECT_CALL(mockQFileSytemWatcher, addPaths(ElementsAre(directoryPath))); - watcher.addEntries({watcherEntry1, watcherEntry2}); + watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}}); } TEST_F(ClangPathWatcher, DontAddNewEntriesWithSameIdAndSamePaths) { - watcher.addEntries({watcherEntry1}); + watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2], pathIds[3], pathIds[4]}}}); - EXPECT_CALL(mockQFileSytemWatcher, addPaths(QStringList{path1QString})) - .Times(0); + EXPECT_CALL(mockQFileSytemWatcher, addPaths(_)).Times(0); - watcher.addEntries({watcherEntry1}); + watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2], pathIds[3], pathIds[4]}}}); } TEST_F(ClangPathWatcher, DontAddNewEntriesWithDifferentIdAndSamePaths) { - watcher.addEntries({watcherEntry1}); + watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2], pathIds[3], pathIds[4]}}}); - EXPECT_CALL(mockQFileSytemWatcher, addPaths(QStringList{path1QString})) - .Times(0); + EXPECT_CALL(mockQFileSytemWatcher, addPaths(_)).Times(0); - watcher.addEntries({watcherEntry2}); + watcher.updateIdPaths({{id2, {pathIds[0], pathIds[1], pathIds[2], pathIds[3], pathIds[4]}}}); } TEST_F(ClangPathWatcher, RemoveEntriesWithId) { - watcher.addEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4, watcherEntry5})); + watcher.updateIdPaths( + {{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}, {id3, {pathIds[1]}}}); - watcher.removeIdsFromWatchedEntries({ids[0]}); + watcher.removeIds({id1}); ASSERT_THAT(watcher.watchedEntries(), ElementsAre(watcherEntry2, watcherEntry4, watcherEntry5)); } @@ -260,37 +278,52 @@ TEST_F(ClangPathWatcher, RemoveNoPathsForEmptyIds) TEST_F(ClangPathWatcher, RemoveNoPathsForOneId) { - watcher.addEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4})); + watcher.updateIdPaths( + {{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}}); EXPECT_CALL(mockQFileSytemWatcher, removePaths(_)) .Times(0); - watcher.removeIds({id1}); + watcher.removeIds({id3}); } TEST_F(ClangPathWatcher, RemovePathForOneId) { - watcher.addEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3})); + watcher.updateIdPaths( + {{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}}); - EXPECT_CALL(mockQFileSytemWatcher, removePaths(QStringList{path2QString})); + EXPECT_CALL(mockQFileSytemWatcher, removePaths(ElementsAre(directoryPath2))); - watcher.removeIds({id1}); + watcher.removeIds({id2}); +} + +TEST_F(ClangPathWatcher, RemoveNoPathSecondTime) +{ + watcher.updateIdPaths( + {{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}}); + watcher.removeIds({id2}); + + EXPECT_CALL(mockQFileSytemWatcher, removePaths(_)).Times(0); + + watcher.removeIds({id2}); } TEST_F(ClangPathWatcher, RemoveAllPathsForThreeId) { - watcher.addEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4, watcherEntry5})); + watcher.updateIdPaths( + {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}}); - EXPECT_CALL(mockQFileSytemWatcher, removePaths(QStringList{path1QString, path2QString})); + EXPECT_CALL(mockQFileSytemWatcher, removePaths(ElementsAre(directoryPath, directoryPath2))); watcher.removeIds({id1, id2, id3}); } TEST_F(ClangPathWatcher, RemoveOnePathForTwoId) { - watcher.addEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4, watcherEntry5})); + watcher.updateIdPaths( + {{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}, {id3, {pathIds[3]}}}); - EXPECT_CALL(mockQFileSytemWatcher, removePaths(QStringList{path1QString})); + EXPECT_CALL(mockQFileSytemWatcher, removePaths(ElementsAre(directoryPath))); watcher.removeIds({id1, id2}); } @@ -313,71 +346,51 @@ TEST_F(ClangPathWatcher, RemoveUnusedEntries) ASSERT_THAT(watcher.watchedEntries(), ElementsAre(watcherEntry1, watcherEntry4, watcherEntry5)); } -TEST_F(ClangPathWatcher, EmptyVectorNotifyFileChange) -{ - watcher.addEntries({watcherEntry3}); - - EXPECT_CALL(notifier, pathsWithIdsChanged(IsEmpty())); - - mockQFileSytemWatcher.fileChanged(path1QString); -} - -TEST_F(ClangPathWatcher, NotifyFileChange) -{ - watcher.addEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4, watcherEntry5})); - - EXPECT_CALL(notifier, pathsWithIdsChanged(ElementsAre(id1, id2))); - - mockQFileSytemWatcher.fileChanged(path1QString); -} - TEST_F(ClangPathWatcher, TwoNotifyFileChanges) { - watcher.addEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4, watcherEntry5})); + watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2]}}, + {id2, {pathIds[0], pathIds[1], pathIds[3]}}, + {id3, {pathIds[4]}}}); + ON_CALL(mockFileSystem, lastModified(Eq(pathIds[0]))).WillByDefault(Return(2)); + ON_CALL(mockFileSystem, lastModified(Eq(pathIds[1]))).WillByDefault(Return(2)); + ON_CALL(mockFileSystem, lastModified(Eq(pathIds[3]))).WillByDefault(Return(2)); - EXPECT_CALL(notifier, pathsWithIdsChanged(ElementsAre(id1, id2, id3))); + EXPECT_CALL(notifier, pathsWithIdsChanged(ElementsAre(id1, id2))); - mockQFileSytemWatcher.fileChanged(path2QString); - mockQFileSytemWatcher.fileChanged(path1QString); + mockQFileSytemWatcher.directoryChanged(directoryPath); + mockQFileSytemWatcher.directoryChanged(directoryPath2); } TEST_F(ClangPathWatcher, NotifyForPathChanges) { - watcher.addEntries({watcherEntry1}); + watcher.updateIdPaths( + {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}}); + ON_CALL(mockFileSystem, lastModified(Eq(pathIds[0]))).WillByDefault(Return(2)); + ON_CALL(mockFileSystem, lastModified(Eq(pathIds[3]))).WillByDefault(Return(2)); EXPECT_CALL(notifier, pathsChanged(ElementsAre(pathIds[0]))); - mockQFileSytemWatcher.fileChanged(path1QString); + mockQFileSytemWatcher.directoryChanged(directoryPath); } TEST_F(ClangPathWatcher, NoNotifyForUnwatchedPathChanges) { - watcher.addEntries({watcherEntry3}); + watcher.updateIdPaths({{id1, {pathIds[3]}}, {id2, {pathIds[3]}}}); EXPECT_CALL(notifier, pathsChanged(IsEmpty())); - mockQFileSytemWatcher.fileChanged(path1QString); + mockQFileSytemWatcher.directoryChanged(directoryPath); } TEST_F(ClangPathWatcher, NoDuplicatePathChanges) { - watcher.addEntries({watcherEntry1}); + watcher.updateIdPaths( + {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}}); + ON_CALL(mockFileSystem, lastModified(Eq(pathIds[0]))).WillByDefault(Return(2)); EXPECT_CALL(notifier, pathsChanged(ElementsAre(pathIds[0]))); - mockQFileSytemWatcher.fileChanged(path1QString); - mockQFileSytemWatcher.fileChanged(path1QString); -} - -void ClangPathWatcher::SetUp() -{ - ON_CALL(filePathCache, filePathId(Eq(path1))) - .WillByDefault(Return(pathIds[0])); - ON_CALL(filePathCache, filePathId(Eq(path2))) - .WillByDefault(Return(pathIds[1])); - ON_CALL(filePathCache, filePath(pathIds[0])) - .WillByDefault(Return(FilePath{path1})); - ON_CALL(filePathCache, filePath(Eq(pathIds[1]))) - .WillByDefault(Return(FilePath{path2})); -} + mockQFileSytemWatcher.directoryChanged(directoryPath); + mockQFileSytemWatcher.directoryChanged(directoryPath); } +} // namespace diff --git a/tests/unit/unittest/directorypathcompressor-test.cpp b/tests/unit/unittest/directorypathcompressor-test.cpp new file mode 100644 index 0000000000..50853e8e1c --- /dev/null +++ b/tests/unit/unittest/directorypathcompressor-test.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "googletest.h" + +#include "mockfilesystem.h" +#include "mocktimer.h" + +#include <directorypathcompressor.h> + +namespace { + +using testing::ElementsAre; +using testing::Invoke; +using testing::IsEmpty; +using testing::NiceMock; + +using ClangBackEnd::DirectoryPathId; +using ClangBackEnd::DirectoryPathIds; + +class DirectoryPathCompressor : public testing::Test +{ +protected: + void SetUp() + { + compressor.setCallback(mockCompressorCallback.AsStdFunction()); + } + +protected: + NiceMock<MockFunction<void(const DirectoryPathIds &directoryPathIds)>> mockCompressorCallback; + ClangBackEnd::DirectoryPathCompressor<NiceMock<MockTimer>> compressor; + NiceMock<MockTimer> &mockTimer = compressor.timer(); + DirectoryPathId directoryPathId1{1}; + DirectoryPathId directoryPathId2{2}; +}; + +TEST_F(DirectoryPathCompressor, AddFilePath) +{ + compressor.addDirectoryPathId(directoryPathId1); + + ASSERT_THAT(compressor.takeDirectoryPathIds(), ElementsAre(directoryPathId1)); +} + +TEST_F(DirectoryPathCompressor, NoFilePathsAferTakenThem) +{ + compressor.addDirectoryPathId(directoryPathId1); + + compressor.takeDirectoryPathIds(); + + ASSERT_THAT(compressor.takeDirectoryPathIds(), IsEmpty()); +} + +TEST_F(DirectoryPathCompressor, CallRestartTimerAfterAddingPath) +{ + EXPECT_CALL(mockTimer, start(20)); + + compressor.addDirectoryPathId(directoryPathId1); +} + +TEST_F(DirectoryPathCompressor, CallTimeOutAfterAddingPath) +{ + EXPECT_CALL(mockCompressorCallback, Call(ElementsAre(directoryPathId1, directoryPathId2))); + + compressor.addDirectoryPathId(directoryPathId1); + compressor.addDirectoryPathId(directoryPathId2); +} + +TEST_F(DirectoryPathCompressor, RemoveDuplicates) +{ + EXPECT_CALL(mockCompressorCallback, Call(ElementsAre(directoryPathId1, directoryPathId2))); + + compressor.addDirectoryPathId(directoryPathId1); + compressor.addDirectoryPathId(directoryPathId2); + compressor.addDirectoryPathId(directoryPathId1); +} + +} diff --git a/tests/unit/unittest/filepathcache-test.cpp b/tests/unit/unittest/filepathcache-test.cpp index 43b5b026bb..478e5f0215 100644 --- a/tests/unit/unittest/filepathcache-test.cpp +++ b/tests/unit/unittest/filepathcache-test.cpp @@ -31,6 +31,7 @@ namespace { +using ClangBackEnd::DirectoryPathId; using ClangBackEnd::FilePathId; using Cache = ClangBackEnd::FilePathCache<NiceMock<MockFilePathStorage>>; using ClangBackEnd::FilePathId; @@ -166,4 +167,153 @@ TEST_F(FilePathCache, DuplicateFilePathsAreEqual) ASSERT_THAT(filePath2Id, Eq(filePath1Id)); } +TEST_F(FilePathCache, DirectoryPathIdCallsFetchDirectoryId) +{ + EXPECT_CALL(mockStorage, fetchDirectoryId(Eq("/path/to"))); + + cache.directoryPathId(Utils::SmallString("/path/to")); +} + +TEST_F(FilePathCache, SecondDirectoryPathIdCallsNotFetchDirectoryId) +{ + cache.directoryPathId(Utils::SmallString("/path/to")); + + EXPECT_CALL(mockStorage, fetchDirectoryId(Eq("/path/to"))).Times(0); + + cache.directoryPathId(Utils::SmallString("/path/to")); +} + +TEST_F(FilePathCache, DirectoryPathIdWithTrailingSlash) +{ + EXPECT_CALL(mockStorage, fetchDirectoryId(Eq("/path/to"))); + + cache.directoryPathId(Utils::SmallString("/path/to/")); +} + +TEST_F(FilePathCache, DirectoryPathId) +{ + auto id = cache.directoryPathId(Utils::SmallString("/path/to")); + + ASSERT_THAT(id, Eq(DirectoryPathId{5})); +} + +TEST_F(FilePathCache, DirectoryPathIdIsAlreadyInCache) +{ + auto firstId = cache.directoryPathId(Utils::SmallString("/path/to")); + + auto secondId = cache.directoryPathId(Utils::SmallString("/path/to")); + + ASSERT_THAT(secondId, firstId); +} + +TEST_F(FilePathCache, DirectoryPathIdIsAlreadyInCacheWithTrailingSlash) +{ + auto firstId = cache.directoryPathId(Utils::SmallString("/path/to/")); + + auto secondId = cache.directoryPathId(Utils::SmallString("/path/to/")); + + ASSERT_THAT(secondId, firstId); +} + +TEST_F(FilePathCache, DirectoryPathIdIsAlreadyInCacheWithAndWithoutTrailingSlash) +{ + auto firstId = cache.directoryPathId(Utils::SmallString("/path/to/")); + + auto secondId = cache.directoryPathId(Utils::SmallString("/path/to")); + + ASSERT_THAT(secondId, firstId); +} + +TEST_F(FilePathCache, DirectoryPathIdIsAlreadyInCacheWithoutAndWithTrailingSlash) +{ + auto firstId = cache.directoryPathId(Utils::SmallString("/path/to")); + + auto secondId = cache.directoryPathId(Utils::SmallString("/path/to/")); + + ASSERT_THAT(secondId, firstId); +} + +TEST_F(FilePathCache, ThrowForGettingADirectoryPathWithAnInvalidId) +{ + DirectoryPathId directoryPathId; + + ASSERT_THROW(cache.directoryPath(directoryPathId), + ClangBackEnd::NoDirectoryPathForInvalidDirectoryPathId); +} + +TEST_F(FilePathCache, GetADirectoryPath) +{ + DirectoryPathId directoryPathId{5}; + + auto directoryPath = cache.directoryPath(directoryPathId); + + ASSERT_THAT(directoryPath, Eq(Utils::SmallStringView{"/path/to"})); +} + +TEST_F(FilePathCache, GetADirectoryPathWithCachedDirectoryPathId) +{ + DirectoryPathId directoryPathId{5}; + cache.directoryPath(directoryPathId); + + auto directoryPath = cache.directoryPath(directoryPathId); + + ASSERT_THAT(directoryPath, Eq(Utils::SmallStringView{"/path/to"})); +} + +TEST_F(FilePathCache, DirectoryPathCallsFetchDirectoryPath) +{ + EXPECT_CALL(mockStorage, fetchDirectoryPath(Eq(DirectoryPathId{5}))); + + cache.directoryPath(5); +} + +TEST_F(FilePathCache, SecondDirectoryPathCallsNotFetchDirectoryPath) +{ + cache.directoryPath(5); + + EXPECT_CALL(mockStorage, fetchDirectoryPath(_)).Times(0); + + cache.directoryPath(5); +} + +TEST_F(FilePathCache, ThrowForGettingADirectoryPathIdWithAnInvalidFilePathId) +{ + FilePathId filePathId; + + ASSERT_THROW(cache.directoryPathId(filePathId), ClangBackEnd::NoFilePathForInvalidFilePathId); +} + +TEST_F(FilePathCache, FetchDirectoryPathIdByFilePathId) +{ + auto directoryId = cache.directoryPathId(42); + + ASSERT_THAT(directoryId, Eq(5)); +} + +TEST_F(FilePathCache, FetchDirectoryPathIdByFilePathIdCached) +{ + cache.directoryPathId(42); + + auto directoryId = cache.directoryPathId(42); + + ASSERT_THAT(directoryId, Eq(5)); +} + +TEST_F(FilePathCache, FetchFilePathAfterFetchingDirectoryIdByFilePathId) +{ + cache.directoryPathId(42); + + auto filePath = cache.filePath(42); + + ASSERT_THAT(filePath, Eq("/path/to/file.cpp")); +} + +TEST_F(FilePathCache, FetchDirectoryPathIdAfterFetchingFilePathByFilePathId) +{ + cache.filePath(42); + + auto directoryId = cache.directoryPathId(42); + + ASSERT_THAT(directoryId, Eq(5)); } +} // namespace diff --git a/tests/unit/unittest/filepathstorage-test.cpp b/tests/unit/unittest/filepathstorage-test.cpp index 37f325daf0..fb60e32512 100644 --- a/tests/unit/unittest/filepathstorage-test.cpp +++ b/tests/unit/unittest/filepathstorage-test.cpp @@ -46,8 +46,8 @@ protected: void SetUp() { ON_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, - valueReturnInt32(_)) - .WillByDefault(Return(Utils::optional<int>())); + valueReturnInt32(A<Utils::SmallStringView>())) + .WillByDefault(Return(Utils::optional<int>())); ON_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, valueReturnInt32(Utils::SmallStringView(""))) .WillByDefault(Return(Utils::optional<int>(0))); @@ -77,9 +77,12 @@ protected: ON_CALL(selectSourceNameAndDirectoryIdFromSourcesBySourceId, valueReturnSourceNameAndDirectoryId(42)) .WillByDefault(Return(Utils::optional<ClangBackEnd::Sources::SourceNameAndDirectoryId>({"file.cpp", 5}))); + ON_CALL(selectDirectoryIdFromSourcesBySourceId, valueReturnInt32(TypedEq<int>(42))) + .WillByDefault(Return(Utils::optional<int>(5))); - EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, valueReturnInt32(_)) - .Times(AnyNumber()); + EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, + valueReturnInt32(A<Utils::SmallStringView>())) + .Times(AnyNumber()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(_, _)) .Times(AnyNumber()); EXPECT_CALL(insertIntoDirectories, write(An<Utils::SmallStringView>())) @@ -107,6 +110,7 @@ protected: MockSqliteWriteStatement &insertIntoDirectories = factory.insertIntoDirectories; MockSqliteWriteStatement &insertIntoSources = factory.insertIntoSources; MockSqliteReadStatement &selectAllSources = factory.selectAllSources; + MockSqliteReadStatement &selectDirectoryIdFromSourcesBySourceId = factory.selectDirectoryIdFromSourcesBySourceId; Storage storage{factory}; }; @@ -229,7 +233,7 @@ TEST_F(FilePathStorage, CallSelectForFetchingDirectoryIdForKnownPath) EXPECT_CALL(mockDatabase, deferredBegin()); EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, - valueReturnInt32(Eq("/path/to"))); + valueReturnInt32(TypedEq<Utils::SmallStringView>("/path/to"))); EXPECT_CALL(mockDatabase, commit()); storage.fetchDirectoryId("/path/to"); @@ -267,7 +271,7 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingDirectoryIdForUnknownPath) EXPECT_CALL(mockDatabase, deferredBegin()); EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, - valueReturnInt32(Eq("/some/not/known/path"))); + valueReturnInt32(TypedEq<Utils::SmallStringView>("/some/not/known/path"))); EXPECT_CALL(insertIntoDirectories, write(TypedEq<Utils::SmallStringView>("/some/not/known/path"))); EXPECT_CALL(mockDatabase, commit()); @@ -296,7 +300,7 @@ TEST_F(FilePathStorage, RestartFetchDirectoryIDIfTheStatementIsBusyInBeginBecaus EXPECT_CALL(mockDatabase, rollback()).Times(0); EXPECT_CALL(mockDatabase, deferredBegin()); EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, - valueReturnInt32(Eq("/other/unknow/path"))); + valueReturnInt32(TypedEq<Utils::SmallStringView>("/other/unknow/path"))); EXPECT_CALL(insertIntoDirectories, write(TypedEq<Utils::SmallStringView>("/other/unknow/path"))); EXPECT_CALL(mockDatabase, commit()); @@ -310,13 +314,13 @@ TEST_F(FilePathStorage, EXPECT_CALL(mockDatabase, deferredBegin()); EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, - valueReturnInt32(Eq("/other/unknow/path"))); + valueReturnInt32(TypedEq<Utils::SmallStringView>("/other/unknow/path"))); EXPECT_CALL(insertIntoDirectories, write(TypedEq<Utils::SmallStringView>("/other/unknow/path"))) .WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); EXPECT_CALL(mockDatabase, rollback()); EXPECT_CALL(mockDatabase, deferredBegin()); EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, - valueReturnInt32(Eq("/other/unknow/path"))); + valueReturnInt32(TypedEq<Utils::SmallStringView>("/other/unknow/path"))); EXPECT_CALL(insertIntoDirectories, write(TypedEq<Utils::SmallStringView>("/other/unknow/path"))); EXPECT_CALL(mockDatabase, commit()); @@ -329,13 +333,13 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingDirectoryIdTwoTimesIfTheInd EXPECT_CALL(mockDatabase,deferredBegin()); EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, - valueReturnInt32(Eq("/other/unknow/path"))); + valueReturnInt32(TypedEq<Utils::SmallStringView>("/other/unknow/path"))); EXPECT_CALL(insertIntoDirectories, write(TypedEq<Utils::SmallStringView>("/other/unknow/path"))) .WillOnce(Throw(Sqlite::ConstraintPreventsModification("busy"))); EXPECT_CALL(mockDatabase, rollback()); EXPECT_CALL(mockDatabase,deferredBegin()); EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, - valueReturnInt32(Eq("/other/unknow/path"))); + valueReturnInt32(TypedEq<Utils::SmallStringView>("/other/unknow/path"))); EXPECT_CALL(mockDatabase, commit()); storage.fetchDirectoryId("/other/unknow/path"); @@ -368,7 +372,6 @@ TEST_F(FilePathStorage, 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, @@ -545,4 +548,59 @@ TEST_F(FilePathStorage, RestartFetchAllSourcesIfBeginIsBusy) storage.fetchAllSources(); } +TEST_F(FilePathStorage, FetchDirectoryIdForUnknownFileID) +{ + ASSERT_THROW(storage.fetchDirectoryId(1111), ClangBackEnd::SourceNameIdDoesNotExists); +} + +TEST_F(FilePathStorage, FetchDirectoryId) +{ + auto directoryId = storage.fetchDirectoryId(42); + + ASSERT_THAT(directoryId, 5); +} + +TEST_F(FilePathStorage, FetchDirectoryIdCalls) +{ + InSequence s; + + EXPECT_CALL(mockDatabase, lock()); + EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(selectDirectoryIdFromSourcesBySourceId, valueReturnInt32(TypedEq<int>(42))); + EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(mockDatabase, unlock()); + + storage.fetchDirectoryId(42); } + +TEST_F(FilePathStorage, FetchDirectoryIdCallsDatabaseIsBusy) +{ + InSequence s; + + EXPECT_CALL(mockDatabase, lock()); + EXPECT_CALL(mockDatabase, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(mockDatabase, rollback()).Times(0); + EXPECT_CALL(mockDatabase, unlock()); + EXPECT_CALL(mockDatabase, lock()); + EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(selectDirectoryIdFromSourcesBySourceId, valueReturnInt32(TypedEq<int>(42))); + EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(mockDatabase, unlock()); + + storage.fetchDirectoryId(42); +} + +TEST_F(FilePathStorage, FetchDirectoryIdCallsThrows) +{ + InSequence s; + + EXPECT_CALL(mockDatabase, lock()); + EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(selectDirectoryIdFromSourcesBySourceId, valueReturnInt32(TypedEq<int>(41))); + EXPECT_CALL(mockDatabase, rollback()); + EXPECT_CALL(mockDatabase, unlock()); + + ASSERT_ANY_THROW(storage.fetchDirectoryId(41)); +} + +} // namespace diff --git a/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp b/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp index ac902fa700..40af2d99c3 100644 --- a/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp +++ b/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp @@ -61,7 +61,13 @@ TEST_F(FilePathStorageSqliteStatementFactory, SelectSourceIdFromSourcesByDirecto Eq("SELECT sourceId FROM sources WHERE directoryId = ? AND sourceName = ?")); } -TEST_F(FilePathStorageSqliteStatementFactory, SelectSourceNameFromSourcesByDirectoryIdAndSourceId) +TEST_F(FilePathStorageSqliteStatementFactory, SelectSourceNameAndDirectoryIdFromSourcesByAndSourceId) +{ + ASSERT_THAT(factory.selectSourceNameAndDirectoryIdFromSourcesBySourceId.sqlStatement, + Eq("SELECT sourceName, directoryId FROM sources WHERE sourceId = ?")); +} + +TEST_F(FilePathStorageSqliteStatementFactory, SelectSourceNameAndDirectoryIdBySourceId) { ASSERT_THAT(factory.selectSourceNameAndDirectoryIdFromSourcesBySourceId.sqlStatement, Eq("SELECT sourceName, directoryId FROM sources WHERE sourceId = ?")); diff --git a/tests/unit/unittest/filestatuscache-test.cpp b/tests/unit/unittest/filestatuscache-test.cpp index db13bc28a7..07ba02655b 100644 --- a/tests/unit/unittest/filestatuscache-test.cpp +++ b/tests/unit/unittest/filestatuscache-test.cpp @@ -24,6 +24,7 @@ ****************************************************************************/ #include "googletest.h" +#include "mockfilesystem.h" #include <filepathcaching.h> #include <filestatuscache.h> @@ -37,31 +38,33 @@ namespace { using ClangBackEnd::FilePathId; +using ClangBackEnd::FilePathIds; class FileStatusCache : public testing::Test { protected: - FilePathId filePathId(Utils::SmallStringView path) const + FileStatusCache() { - return filePathCache.filePathId(ClangBackEnd::FilePathView(path)); - } - - void touchFile(FilePathId filePathId) - { - std::ofstream ostream(std::string(filePathCache.filePath(filePathId)), std::ios::binary); - ostream.write("\n", 1); - ostream.close(); + ON_CALL(fileSystem, lastModified(Eq(header))).WillByDefault(Return(headerLastModifiedTime)); + ON_CALL(fileSystem, lastModified(Eq(source))).WillByDefault(Return(sourceLastModifiedTime)); + ON_CALL(fileSystem, lastModified(Eq(header2))).WillByDefault(Return(header2LastModifiedTime)); + ON_CALL(fileSystem, lastModified(Eq(source2))).WillByDefault(Return(source2LastModifiedTime)); } protected: - Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; - ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database}; - ClangBackEnd::FilePathCaching filePathCache{database}; - ClangBackEnd::FileStatusCache cache{filePathCache}; - FilePathId header{filePathId(TESTDATA_DIR "/filestatuscache_header.h")}; - FilePathId source{filePathId(TESTDATA_DIR "/filestatuscache_header.cpp")}; - long long headerLastModifiedTime = QFileInfo(TESTDATA_DIR "/filestatuscache_header.h").lastModified().toSecsSinceEpoch(); - long long sourceLastModifiedTime = QFileInfo(TESTDATA_DIR "/filestatuscache_header.cpp").lastModified().toSecsSinceEpoch(); + NiceMock<MockFileSystem> fileSystem; + ClangBackEnd::FileStatusCache cache{fileSystem}; + FilePathId header{1}; + FilePathId source{2}; + FilePathId header2{3}; + FilePathId source2{4}; + FilePathIds entries{header, source, header2, source2}; + long long headerLastModifiedTime = 100; + long long headerLastModifiedTime2 = 110; + long long header2LastModifiedTime = 300; + long long header2LastModifiedTime2 = 310; + long long sourceLastModifiedTime = 200; + long long source2LastModifiedTime = 400; }; TEST_F(FileStatusCache, CreateEntry) @@ -134,18 +137,24 @@ TEST_F(FileStatusCache, AskNewEntryReverseOrderAddedForLastModifiedTime) TEST_F(FileStatusCache, UpdateFile) { - auto oldLastModified = cache.lastModifiedTime(header); - touchFile(header); + EXPECT_CALL(fileSystem, lastModified(Eq(header))) + .Times(2) + .WillOnce(Return(headerLastModifiedTime)) + .WillOnce(Return(headerLastModifiedTime2)); + cache.lastModifiedTime(header); cache.update(header); - ASSERT_THAT(cache.lastModifiedTime(header), Gt(oldLastModified)); + ASSERT_THAT(cache.lastModifiedTime(header), headerLastModifiedTime2); } TEST_F(FileStatusCache, UpdateFileDoesNotChangeEntryCount) { + EXPECT_CALL(fileSystem, lastModified(Eq(header))) + .Times(2) + .WillOnce(Return(headerLastModifiedTime)) + .WillOnce(Return(headerLastModifiedTime2)); cache.lastModifiedTime(header); - touchFile(header); cache.update(header); @@ -154,11 +163,136 @@ TEST_F(FileStatusCache, UpdateFileDoesNotChangeEntryCount) TEST_F(FileStatusCache, UpdateFileForNonExistingEntry) { - touchFile(header); - cache.update(header); ASSERT_THAT(cache, SizeIs(0)); } +TEST_F(FileStatusCache, UpdateFiles) +{ + EXPECT_CALL(fileSystem, lastModified(Eq(header))) + .Times(2) + .WillOnce(Return(headerLastModifiedTime)) + .WillOnce(Return(headerLastModifiedTime2)); + EXPECT_CALL(fileSystem, lastModified(Eq(header2))) + .Times(2) + .WillOnce(Return(header2LastModifiedTime)) + .WillOnce(Return(header2LastModifiedTime2)); + cache.lastModifiedTime(header); + cache.lastModifiedTime(header2); + + cache.update(entries); + + ASSERT_THAT(cache.lastModifiedTime(header), headerLastModifiedTime2); + ASSERT_THAT(cache.lastModifiedTime(header2), header2LastModifiedTime2); } + +TEST_F(FileStatusCache, UpdateFilesDoesNotChangeEntryCount) +{ + EXPECT_CALL(fileSystem, lastModified(Eq(header))) + .Times(2) + .WillOnce(Return(headerLastModifiedTime)) + .WillOnce(Return(headerLastModifiedTime2)); + EXPECT_CALL(fileSystem, lastModified(Eq(header2))) + .Times(2) + .WillOnce(Return(header2LastModifiedTime)) + .WillOnce(Return(header2LastModifiedTime2)); + cache.lastModifiedTime(header); + cache.lastModifiedTime(header2); + + cache.update(entries); + + ASSERT_THAT(cache, SizeIs(2)); +} + +TEST_F(FileStatusCache, UpdateFilesForNonExistingEntry) +{ + cache.update(entries); + + ASSERT_THAT(cache, SizeIs(0)); +} + +TEST_F(FileStatusCache, NewModifiedEntries) +{ + auto modifiedIds = cache.modified(entries); + + ASSERT_THAT(modifiedIds, entries); +} + +TEST_F(FileStatusCache, NoNewModifiedEntries) +{ + cache.modified(entries); + + auto modifiedIds = cache.modified(entries); + + ASSERT_THAT(modifiedIds, IsEmpty()); +} + +TEST_F(FileStatusCache, SomeNewModifiedEntries) +{ + cache.modified({source, header2}); + + auto modifiedIds = cache.modified(entries); + + ASSERT_THAT(modifiedIds, ElementsAre(header, source2)); +} + +TEST_F(FileStatusCache, SomeAlreadyExistingModifiedEntries) +{ + EXPECT_CALL(fileSystem, lastModified(Eq(header))) + .Times(2) + .WillOnce(Return(headerLastModifiedTime)) + .WillOnce(Return(headerLastModifiedTime2)); + EXPECT_CALL(fileSystem, lastModified(Eq(header2))) + .Times(2) + .WillOnce(Return(header2LastModifiedTime)) + .WillOnce(Return(header2LastModifiedTime2)); + EXPECT_CALL(fileSystem, lastModified(Eq(source))).Times(2).WillRepeatedly(Return(sourceLastModifiedTime)); + EXPECT_CALL(fileSystem, lastModified(Eq(source2))) + .Times(2) + .WillRepeatedly(Return(source2LastModifiedTime)); + cache.modified(entries); + + auto modifiedIds = cache.modified(entries); + + ASSERT_THAT(modifiedIds, ElementsAre(header, header2)); +} + +TEST_F(FileStatusCache, SomeAlreadyExistingAndSomeNewModifiedEntries) +{ + EXPECT_CALL(fileSystem, lastModified(Eq(header))).WillRepeatedly(Return(headerLastModifiedTime)); + EXPECT_CALL(fileSystem, lastModified(Eq(header2))) + .Times(2) + .WillOnce(Return(header2LastModifiedTime)) + .WillOnce(Return(header2LastModifiedTime2)); + EXPECT_CALL(fileSystem, lastModified(Eq(source))).Times(2).WillRepeatedly(Return(sourceLastModifiedTime)); + EXPECT_CALL(fileSystem, lastModified(Eq(source2))).WillRepeatedly(Return(source2LastModifiedTime)); + cache.modified({source, header2}); + + auto modifiedIds = cache.modified(entries); + + ASSERT_THAT(modifiedIds, ElementsAre(header, header2, source2)); +} + +TEST_F(FileStatusCache, TimeIsUpdatedForSomeAlreadyExistingModifiedEntries) +{ + EXPECT_CALL(fileSystem, lastModified(Eq(header))) + .Times(2) + .WillOnce(Return(headerLastModifiedTime)) + .WillOnce(Return(headerLastModifiedTime2)); + EXPECT_CALL(fileSystem, lastModified(Eq(header2))) + .Times(2) + .WillOnce(Return(header2LastModifiedTime)) + .WillOnce(Return(header2LastModifiedTime2)); + EXPECT_CALL(fileSystem, lastModified(Eq(source))).Times(2).WillRepeatedly(Return(sourceLastModifiedTime)); + EXPECT_CALL(fileSystem, lastModified(Eq(source2))) + .Times(2) + .WillRepeatedly(Return(source2LastModifiedTime)); + cache.modified(entries); + + cache.modified(entries); + + ASSERT_THAT(cache.lastModifiedTime(header), headerLastModifiedTime2); +} + +} // namespace diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 7ac4a676e3..0ab962dfa5 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -361,7 +361,7 @@ std::ostream &operator<<(std::ostream &out, const WatcherEntry &entry) { out << "(" << entry.id << ", " - << entry.pathId + << entry.filePathId << ")"; return out; diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index 897a9f2a28..b874fc90e4 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -49,7 +49,7 @@ std::ostream &operator<<(std::ostream &out, const CompileCommand &command); } // namespace clang namespace Core { -class LocatorFilterEntry; +struct LocatorFilterEntry; std::ostream &operator<<(std::ostream &out, const LocatorFilterEntry &entry); diff --git a/tests/unit/unittest/mockbuilddependenciesstorage.h b/tests/unit/unittest/mockbuilddependenciesstorage.h index a4d34e481d..dd2850d88c 100644 --- a/tests/unit/unittest/mockbuilddependenciesstorage.h +++ b/tests/unit/unittest/mockbuilddependenciesstorage.h @@ -51,7 +51,7 @@ public: ClangBackEnd::ProjectPartId(Utils::SmallStringView projectPartName)); MOCK_METHOD2(updatePchCreationTimeStamp, void(long long pchCreationTimeStamp, ClangBackEnd::ProjectPartId projectPartId)); - MOCK_CONST_METHOD1(fetchSources, + MOCK_CONST_METHOD1(fetchPchSources, ClangBackEnd::FilePathIds(ClangBackEnd::ProjectPartId projectPartId)); }; diff --git a/tests/unit/unittest/mockfilepathcaching.h b/tests/unit/unittest/mockfilepathcaching.h index 1b22e910ee..ca7960513e 100644 --- a/tests/unit/unittest/mockfilepathcaching.h +++ b/tests/unit/unittest/mockfilepathcaching.h @@ -36,5 +36,11 @@ public: ClangBackEnd::FilePathId (ClangBackEnd::FilePathView filePath)); MOCK_CONST_METHOD1(filePath, ClangBackEnd::FilePath (ClangBackEnd::FilePathId filePathId)); + MOCK_CONST_METHOD1(directoryPathId, + ClangBackEnd::DirectoryPathId(Utils::SmallStringView directoryPath)); + MOCK_CONST_METHOD1(directoryPath, + Utils::PathString(ClangBackEnd::DirectoryPathId directoryPathId)); + MOCK_CONST_METHOD1(directoryPathId, + ClangBackEnd::DirectoryPathId(ClangBackEnd::FilePathId filePathId)); }; diff --git a/tests/unit/unittest/mockfilesystem.h b/tests/unit/unittest/mockfilesystem.h new file mode 100644 index 0000000000..688edbcae5 --- /dev/null +++ b/tests/unit/unittest/mockfilesystem.h @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "googletest.h" + +#include <filesysteminterface.h> + +class MockFileSystem : public ClangBackEnd::FileSystemInterface +{ +public: + MOCK_CONST_METHOD1(directoryEntries, ClangBackEnd::FilePathIds(const QString &directoryPath)); + MOCK_CONST_METHOD1(lastModified, long long(ClangBackEnd::FilePathId filePathId)); +}; diff --git a/tests/unit/unittest/mockmodifiedtimechecker.h b/tests/unit/unittest/mockmodifiedtimechecker.h index bf101988b1..1fa3dd497c 100644 --- a/tests/unit/unittest/mockmodifiedtimechecker.h +++ b/tests/unit/unittest/mockmodifiedtimechecker.h @@ -35,6 +35,7 @@ class MockSourceEntriesModifiedTimeChecker public: MOCK_CONST_METHOD1(isUpToDate, bool (const ClangBackEnd::SourceEntries &sourceEntries)); + MOCK_METHOD1(pathsChanged, void(const ClangBackEnd::FilePathIds &filePathIds)); }; class MockSourceTimeStampsModifiedTimeChecker @@ -42,4 +43,5 @@ class MockSourceTimeStampsModifiedTimeChecker { public: MOCK_CONST_METHOD1(isUpToDate, bool(const ClangBackEnd::SourceTimeStamps &sourceTimeStamps)); + MOCK_METHOD1(pathsChanged, void(const ClangBackEnd::FilePathIds &filePathIds)); }; diff --git a/tests/unit/unittest/mockqfilesystemwatcher.h b/tests/unit/unittest/mockqfilesystemwatcher.h index 1bb90b2c37..00f4c600b4 100644 --- a/tests/unit/unittest/mockqfilesystemwatcher.h +++ b/tests/unit/unittest/mockqfilesystemwatcher.h @@ -41,4 +41,5 @@ public: signals: void fileChanged(const QString &); + void directoryChanged(const QString &); }; diff --git a/tests/unit/unittest/mocksqlitereadstatement.cpp b/tests/unit/unittest/mocksqlitereadstatement.cpp index b0df1ab75d..1e800e2be1 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.cpp +++ b/tests/unit/unittest/mocksqlitereadstatement.cpp @@ -137,6 +137,12 @@ MockSqliteReadStatement::value<int>(const int &directoryId, const Utils::SmallSt return valueReturnInt32(directoryId, text); } +template<> +Utils::optional<int> MockSqliteReadStatement::value<int>(const int &value) +{ + return valueReturnInt32(value); +} + template <> Utils::optional<long long> MockSqliteReadStatement::value<long long>(const int &sourceId) diff --git a/tests/unit/unittest/mocksqlitereadstatement.h b/tests/unit/unittest/mocksqlitereadstatement.h index d952c90dec..191c38accd 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.h +++ b/tests/unit/unittest/mocksqlitereadstatement.h @@ -92,11 +92,11 @@ public: MOCK_METHOD1(valueReturnInt32, Utils::optional<int>(Utils::SmallStringView)); - MOCK_METHOD2(valueReturnInt32, - Utils::optional<int>(int, Utils::SmallStringView)); + MOCK_METHOD2(valueReturnInt32, Utils::optional<int>(int, Utils::SmallStringView)); - MOCK_METHOD1(valueReturnInt64, - Utils::optional<long long>(int)); + MOCK_METHOD1(valueReturnInt32, Utils::optional<int>(int)); + + MOCK_METHOD1(valueReturnInt64, Utils::optional<long long>(int)); MOCK_METHOD1(valueReturnPathString, Utils::optional<Utils::PathString>(int)); @@ -244,6 +244,9 @@ template <> Utils::optional<int> MockSqliteReadStatement::value<int>(const int&, const Utils::SmallStringView&); +template<> +Utils::optional<int> MockSqliteReadStatement::value<int>(const int &); + template <> Utils::optional<long long> MockSqliteReadStatement::value<long long>(const ClangBackEnd::FilePathId&); diff --git a/tests/unit/unittest/modifiedtimechecker-test.cpp b/tests/unit/unittest/modifiedtimechecker-test.cpp index ff0c3c66d8..0e18228ac3 100644 --- a/tests/unit/unittest/modifiedtimechecker-test.cpp +++ b/tests/unit/unittest/modifiedtimechecker-test.cpp @@ -24,6 +24,7 @@ ****************************************************************************/ #include "googletest.h" +#include "mockfilesystem.h" #include <filepathcaching.h> #include <modifiedtimechecker.h> @@ -39,29 +40,24 @@ using ClangBackEnd::FilePathView; class ModifiedTimeChecker : public testing::Test { protected: - - ClangBackEnd::FilePathId id(const Utils::SmallStringView &path) const - { - return filePathCache.filePathId(ClangBackEnd::FilePathView{path}); - } - - ModifiedTimeChecker() { - ON_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path1")))).WillByDefault(Return(50)); - ON_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path2")))).WillByDefault(Return(30)); + ON_CALL(mockFileSystem, lastModified(Eq(1))).WillByDefault(Return(50)); + ON_CALL(mockFileSystem, lastModified(Eq(2))).WillByDefault(Return(30)); + ON_CALL(mockFileSystem, lastModified(Eq(3))).WillByDefault(Return(50)); + ON_CALL(mockFileSystem, lastModified(Eq(4))).WillByDefault(Return(30)); } - NiceMock<MockFunction<ClangBackEnd::TimeStamp(ClangBackEnd::FilePathView filePath)>> getModifiedTimeCallback; - Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; - ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database}; - ClangBackEnd::FilePathCaching filePathCache{database}; - decltype(getModifiedTimeCallback.AsStdFunction()) callback = getModifiedTimeCallback - .AsStdFunction(); - ClangBackEnd::ModifiedTimeChecker<> checker{callback, filePathCache}; - SourceEntries upToDateEntries = {{id("/path1"), SourceType::UserInclude, 100}, - {id("/path2"), SourceType::SystemInclude, 30}}; - SourceEntries notUpToDateEntries = {{id("/path1"), SourceType::UserInclude, 50}, - {id("/path2"), SourceType::SystemInclude, 20}}; + + NiceMock<MockFileSystem> mockFileSystem; + ClangBackEnd::ModifiedTimeChecker<> checker{mockFileSystem}; + SourceEntries upToDateEntries = {{1, SourceType::UserInclude, 100}, + {2, SourceType::SystemInclude, 30}, + {3, SourceType::UserInclude, 100}, + {4, SourceType::SystemInclude, 30}}; + SourceEntries notUpToDateEntries = {{1, SourceType::UserInclude, 50}, + {2, SourceType::SystemInclude, 20}, + {3, SourceType::UserInclude, 100}, + {4, SourceType::SystemInclude, 30}}; }; TEST_F(ModifiedTimeChecker, IsUpToDate) @@ -71,6 +67,15 @@ TEST_F(ModifiedTimeChecker, IsUpToDate) ASSERT_TRUE(isUpToDate); } +TEST_F(ModifiedTimeChecker, IsUpToDateSecondRun) +{ + checker.isUpToDate(upToDateEntries); + + auto isUpToDate = checker.isUpToDate(upToDateEntries); + + ASSERT_TRUE(isUpToDate); +} + TEST_F(ModifiedTimeChecker, IsNotUpToDateIfSourceEntriesAreEmpty) { auto isUpToDate = checker.isUpToDate({}); @@ -80,7 +85,16 @@ TEST_F(ModifiedTimeChecker, IsNotUpToDateIfSourceEntriesAreEmpty) TEST_F(ModifiedTimeChecker, IsNotUpToDate) { - auto isUpToDate = checker.isUpToDate({}); + auto isUpToDate = checker.isUpToDate(notUpToDateEntries); + + ASSERT_FALSE(isUpToDate); +} + +TEST_F(ModifiedTimeChecker, IsNotUpToDateSecondRun) +{ + checker.isUpToDate(notUpToDateEntries); + + auto isUpToDate = checker.isUpToDate(notUpToDateEntries); ASSERT_FALSE(isUpToDate); } @@ -89,21 +103,80 @@ TEST_F(ModifiedTimeChecker, PathChangesUpdatesTimeStamps) { checker.isUpToDate(upToDateEntries); - EXPECT_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path1")))); - EXPECT_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path2")))); + EXPECT_CALL(mockFileSystem, lastModified(Eq(2))); + EXPECT_CALL(mockFileSystem, lastModified(Eq(3))); - checker.pathsChanged({id(FilePathView("/path1")), id(FilePathView("/path2")), id(FilePathView("/path3"))}); + checker.pathsChanged({2, 3}); } TEST_F(ModifiedTimeChecker, IsNotUpToDateAnyMoreAfterUpdating) { checker.isUpToDate(upToDateEntries); - ON_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path1")))).WillByDefault(Return(120)); - ON_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path2")))).WillByDefault(Return(30)); + ON_CALL(mockFileSystem, lastModified(Eq(1))).WillByDefault(Return(120)); + ON_CALL(mockFileSystem, lastModified(Eq(2))).WillByDefault(Return(30)); - checker.pathsChanged({id(FilePathView("/path1")), id(FilePathView("/path2")), id(FilePathView("/path3"))}); + checker.pathsChanged({1, 2, 3}); ASSERT_FALSE(checker.isUpToDate(upToDateEntries)); } +TEST_F(ModifiedTimeChecker, Reset) +{ + checker.isUpToDate(upToDateEntries); + + checker.reset({2, 3}); + + ASSERT_FALSE(checker.isUpToDate(upToDateEntries)); +} + +TEST_F(ModifiedTimeChecker, UpdateNonResetedId) +{ + checker.isUpToDate(upToDateEntries); + + checker.reset({2, 3}); + + ASSERT_TRUE(checker.isUpToDate({upToDateEntries[0]})); +} + +TEST_F(ModifiedTimeChecker, ResetTwoTimes) +{ + checker.isUpToDate(upToDateEntries); + checker.reset({2, 3}); + + checker.reset({2, 3}); + + ASSERT_FALSE(checker.isUpToDate(upToDateEntries)); + ASSERT_TRUE(checker.isUpToDate(upToDateEntries)); +} + +TEST_F(ModifiedTimeChecker, ResetSecondUpdate) +{ + checker.isUpToDate(upToDateEntries); + checker.reset({2, 3}); + checker.isUpToDate(upToDateEntries); + + auto isUpToDate = checker.isUpToDate(upToDateEntries); + + ASSERT_TRUE(isUpToDate); +} + +TEST_F(ModifiedTimeChecker, ResetPartialUpdate) +{ + checker.isUpToDate(upToDateEntries); + checker.reset({2, 3}); + checker.isUpToDate({upToDateEntries[1]}); + + ASSERT_FALSE(checker.isUpToDate({upToDateEntries[2]})); +} + +TEST_F(ModifiedTimeChecker, ResetMoreIds) +{ + checker.isUpToDate(upToDateEntries); + checker.reset({2, 3}); + + checker.reset({1, 5}); + + ASSERT_FALSE(checker.isUpToDate({upToDateEntries[2]})); +} + } // namespace diff --git a/tests/unit/unittest/pchcreator-test.cpp b/tests/unit/unittest/pchcreator-test.cpp index 0cf84a983d..04e198eec7 100644 --- a/tests/unit/unittest/pchcreator-test.cpp +++ b/tests/unit/unittest/pchcreator-test.cpp @@ -226,16 +226,21 @@ TEST_F(PchCreatorVerySlowTest, SourcesAreWatchedAfterSucess) creator.doInMainThreadAfterFinished(); } -TEST_F(PchCreatorVerySlowTest, SourcesAreNotWatchedAfterFail) +TEST_F(PchCreatorVerySlowTest, SourcesAreWatchedAfterFail) { pchTask1.systemIncludeSearchPaths = {}; pchTask1.projectIncludeSearchPaths = {}; creator.generatePch(std::move(pchTask1)); EXPECT_CALL(mockClangPathWatcher, - updateIdPaths( - ElementsAre(AllOf(Field(&ClangBackEnd::IdPaths::id, 1), - Field(&ClangBackEnd::IdPaths::filePathIds, IsEmpty()))))); + updateIdPaths(ElementsAre(AllOf( + Field(&ClangBackEnd::IdPaths::id, 1), + 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(); } @@ -337,9 +342,14 @@ TEST_F(PchCreatorSlowTest, NoIncludesInTheMainThreadCalls) Field(&ClangBackEnd::PrecompiledHeadersUpdatedMessage::projectPartIds, ElementsAre(Eq(creator.projectPartPch().projectPartId))))); EXPECT_CALL(mockClangPathWatcher, - updateIdPaths( - ElementsAre(AllOf(Field(&ClangBackEnd::IdPaths::id, 1), - Field(&ClangBackEnd::IdPaths::filePathIds, IsEmpty()))))); + updateIdPaths(ElementsAre(AllOf( + Field(&ClangBackEnd::IdPaths::id, 1), + 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"))))))); EXPECT_CALL(mockBuildDependenciesStorage, updatePchCreationTimeStamp(Gt(0), Eq(1))); creator.doInMainThreadAfterFinished(); diff --git a/tests/unit/unittest/pchtaskgenerator-test.cpp b/tests/unit/unittest/pchtaskgenerator-test.cpp index 8f5f0754af..cb9df32235 100644 --- a/tests/unit/unittest/pchtaskgenerator-test.cpp +++ b/tests/unit/unittest/pchtaskgenerator-test.cpp @@ -117,7 +117,7 @@ TEST_F(PchTaskGenerator, AddProjectParts) &PchTaskSet::project, AllOf(Field(&PchTask::projectPartIds, ElementsAre(ProjectPartId{1})), Field(&PchTask::includes, ElementsAre(3)), - Field(&PchTask::sources, ElementsAre(1, 2, 3, 4, 5)), + Field(&PchTask::sources, ElementsAre(1, 3, 4, 5)), Field(&PchTask::compilerMacros, ElementsAre(CompilerMacro{"YI", "1", 1}, CompilerMacro{"SAN", "3", 3})), Field(&PchTask::systemIncludeSearchPaths, diff --git a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp index 7177060311..3af0fc8cfe 100644 --- a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp +++ b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp @@ -107,7 +107,10 @@ TEST_F(RefactoringDatabaseInitializer, AddProjectPartsFilesTable) "sourceId INTEGER, sourceType INTEGER, pchCreationTimeStamp INTEGER, " "hasMissingIncludes INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsFiles_sourceId_projectPartId ON projectPartsFiles(sourceId, projectPartId)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsFiles_projectPartId ON projectPartsFiles(projectPartId)"))); + EXPECT_CALL(mockDatabase, + execute(Eq( + "CREATE INDEX IF NOT EXISTS index_projectPartsFiles_projectPartId_sourceType " + "ON projectPartsFiles(projectPartId, sourceType)"))); initializer.createProjectPartsFilesTable(); } @@ -247,9 +250,10 @@ TEST_F(RefactoringDatabaseInitializer, CreateInTheContructor) execute( Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsFiles_sourceId_projectPartId " "ON projectPartsFiles(sourceId, projectPartId)"))); - EXPECT_CALL(mockDatabase, - execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsFiles_projectPartId ON " - "projectPartsFiles(projectPartId)"))); + EXPECT_CALL( + mockDatabase, + execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsFiles_projectPartId_sourceType ON " + "projectPartsFiles(projectPartId, sourceType)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS usedMacros(usedMacroId INTEGER PRIMARY KEY, " "sourceId INTEGER, macroName TEXT)"))); diff --git a/tests/unit/unittest/symbolindexer-test.cpp b/tests/unit/unittest/symbolindexer-test.cpp index 2db11dc5fb..16e0fc81b0 100644 --- a/tests/unit/unittest/symbolindexer-test.cpp +++ b/tests/unit/unittest/symbolindexer-test.cpp @@ -28,6 +28,7 @@ #include "mockbuilddependenciesstorage.h" #include "mockclangpathwatcher.h" #include "mockfilepathcaching.h" +#include "mockfilesystem.h" #include "mockmodifiedtimechecker.h" #include "mockprecompiledheaderstorage.h" #include "mockprojectpartsstorage.h" @@ -149,13 +150,6 @@ protected: data.reset(); } - void touchFile(FilePathId filePathId) - { - std::ofstream ostream(std::string(filePathCache.filePath(filePathId)), std::ios::binary); - ostream.write("\n", 1); - ostream.close(); - } - FilePathId filePathId(Utils::SmallStringView path) const { return filePathCache.filePathId(ClangBackEnd::FilePathView(path)); @@ -249,7 +243,8 @@ protected: NiceMock<MockPrecompiledHeaderStorage> mockPrecompiledHeaderStorage; NiceMock<MockProjectPartsStorage> mockProjectPartsStorage; NiceMock<MockClangPathWatcher> mockPathWatcher; - ClangBackEnd::FileStatusCache fileStatusCache{filePathCache}; + NiceMock<MockFileSystem> mockFileSystem; + ClangBackEnd::FileStatusCache fileStatusCache{mockFileSystem}; ClangBackEnd::GeneratedFiles generatedFiles; Manager collectorManger{generatedFiles}; NiceMock<MockFunction<void(int, int)>> mockSetProgressCallback; @@ -928,7 +923,7 @@ TEST_F(SymbolIndexer, SourcesAreWatched) InSequence s; FilePathIds sourcePathIds{4, 6, 8}; - EXPECT_CALL(mockBuildDependenciesStorage, fetchSources(projectPart1.projectPartId)) + EXPECT_CALL(mockBuildDependenciesStorage, fetchPchSources(projectPart1.projectPartId)) .WillOnce(Return(sourcePathIds)); EXPECT_CALL(mockPathWatcher, updateIdPaths(ElementsAre(AllOf(Field(&IdPaths::id, projectPart1.projectPartId), @@ -1664,13 +1659,21 @@ TEST_F(SymbolIndexer, DISABLED_DontReparseInUpdateProjectPartsIfDefinesAreTheSam TEST_F(SymbolIndexer, PathsChangedUpdatesFileStatusCache) { auto sourceId = filePathId(TESTDATA_DIR "/symbolindexer_pathChanged.cpp"); - auto oldLastModified = fileStatusCache.lastModifiedTime(sourceId); - touchFile(sourceId); + ON_CALL(mockFileSystem, lastModified(Eq(sourceId))).WillByDefault(Return(65)); ON_CALL(mockSymbolStorage, fetchDependentSourceIds(_)).WillByDefault(Return(FilePathIds{sourceId})); indexer.pathsChanged({sourceId}); - ASSERT_THAT(fileStatusCache.lastModifiedTime(sourceId), Gt(oldLastModified)); + ASSERT_THAT(fileStatusCache.lastModifiedTime(sourceId), 65); +} + +TEST_F(SymbolIndexer, PathsChangedCallsModifiedTimeChecker) +{ + auto sourceId = filePathId(TESTDATA_DIR "/symbolindexer_pathChanged.cpp"); + + EXPECT_CALL(mockModifiedTimeChecker, pathsChanged(ElementsAre(sourceId))); + + indexer.pathsChanged({sourceId}); } TEST_F(SymbolIndexer, GetUpdatableFilePathIdsIfCompilerMacrosAreDifferent) @@ -1706,6 +1709,7 @@ TEST_F(SymbolIndexer, GetNoUpdatableFilePathIdsIfArtefactsAreTheSame) TEST_F(SymbolIndexer, OutdatedFilesPassUpdatableFilePathIds) { + ON_CALL(mockFileSystem, lastModified(Eq(main1PathId))).WillByDefault(Return(65)); indexer.pathsChanged({main1PathId}); ON_CALL(mockProjectPartsStorage, fetchProjectPartArtefact(A<ProjectPartId>())) .WillByDefault(Return(artefact)); diff --git a/tests/unit/unittest/symbolscollector-test.cpp b/tests/unit/unittest/symbolscollector-test.cpp index f0080a5d2c..a766b70fa4 100644 --- a/tests/unit/unittest/symbolscollector-test.cpp +++ b/tests/unit/unittest/symbolscollector-test.cpp @@ -53,17 +53,18 @@ using testing::Value; using testing::_; using ClangBackEnd::FilePath; -using ClangBackEnd::FilePathId; using ClangBackEnd::FilePathCaching; -using ClangBackEnd::V2::FileContainers; +using ClangBackEnd::FilePathId; +using ClangBackEnd::FileStatus; using ClangBackEnd::SourceDependency; using ClangBackEnd::SourceLocationEntry; +using ClangBackEnd::SourceLocationKind; using ClangBackEnd::SymbolEntry; +using ClangBackEnd::SymbolIndex; using ClangBackEnd::SymbolKind; using ClangBackEnd::SymbolTag; -using ClangBackEnd::SourceLocationKind; -using ClangBackEnd::SymbolIndex; using ClangBackEnd::UsedMacro; +using ClangBackEnd::V2::FileContainers; using Sqlite::Database; @@ -130,6 +131,9 @@ MATCHER_P(HasSymbolTag, symbolTag, class SymbolsCollector : public testing::Test { protected: + SymbolsCollector() { setFilePathCache(&filePathCache); } + ~SymbolsCollector() { setFilePathCache({}); } + FilePathId filePathId(Utils::SmallStringView filePath) const { return filePathCache.filePathId(ClangBackEnd::FilePathView{filePath}); @@ -664,4 +668,15 @@ TEST_F(SymbolsCollector, CollectReturnsFalseIfThereIsNoError) ASSERT_TRUE(success); } + +TEST_F(SymbolsCollector, ClearInputFilesAfterCollectingSymbols) +{ + collector.setFile(filePathId(TESTDATA_DIR "/symbolscollector/main2.cpp"), {"cc"}); + collector.collectSymbols(); + collector.setFile(filePathId(TESTDATA_DIR "/symbolscollector/main.cpp"), {"cc"}); + + collector.collectSymbols(); + + ASSERT_TRUE(collector.isClean()); +} } // namespace diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 5ea9ba2fef..2989331ebe 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -36,7 +36,7 @@ CONFIG(release, debug|release):QMAKE_LFLAGS += -Wl,--strip-debug } gcc:!clang: QMAKE_CXXFLAGS += -Wno-noexcept-type -msvc: QMAKE_CXXFLAGS += /bigobj +msvc: QMAKE_CXXFLAGS += /bigobj /wd4267 /wd4141 /wd4146 # create fake CppTools.json for the mime type definitions dependencyList = "\"Dependencies\" : []" @@ -46,7 +46,6 @@ QMAKE_SUBSTITUTES += cpptoolsjson DEFINES += CPPTOOLS_JSON=\"R\\\"xxx($${cpptoolsjson.output})xxx\\\"\" SOURCES += \ - changedfilepathcompressor-test.cpp \ clangindexingsettingsmanager-test.cpp \ clangpathwatcher-test.cpp \ clangqueryexamplehighlightmarker-test.cpp \ @@ -56,6 +55,7 @@ SOURCES += \ cppprojectfilecategorizer-test.cpp \ cppprojectinfogenerator-test.cpp \ cppprojectpartchooser-test.cpp \ + directorypathcompressor-test.cpp \ fakeprocess.cpp \ filepath-test.cpp \ filepathview-test.cpp \ @@ -177,7 +177,7 @@ SOURCES += \ translationunitupdater-test.cpp \ unsavedfiles-test.cpp \ unsavedfile-test.cpp \ - utf8positionfromlinecolumn-test.cpp \ + utf8positionfromlinecolumn-test.cpp } !isEmpty(LIBTOOLING_LIBS) { @@ -228,6 +228,7 @@ HEADERS += \ mockclangcodemodelserver.h \ mockclangpathwatcher.h \ mockclangpathwatchernotifier.h \ + mockfilesystem.h \ mockpchcreator.h \ mockpchmanagerclient.h \ mockpchmanagernotifier.h \ diff --git a/tests/unit/unittest/usedmacrofilter-test.cpp b/tests/unit/unittest/usedmacrofilter-test.cpp index 788a443eee..85e1bb59b5 100644 --- a/tests/unit/unittest/usedmacrofilter-test.cpp +++ b/tests/unit/unittest/usedmacrofilter-test.cpp @@ -98,12 +98,7 @@ TEST_F(UsedMacroFilter, Sources) ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.sources, - ElementsAre(FilePathId{1}, - FilePathId{2}, - FilePathId{3}, - FilePathId{4}, - FilePathId{5}, - FilePathId{6})); + ElementsAre(FilePathId{2}, FilePathId{3}, FilePathId{4}, FilePathId{5})); } TEST_F(UsedMacroFilter, SystemUsedMacros) |