diff --git a/doc/qtcreator/images/qtcreator-edit-cmake-configuration-self-built-qt.webp b/doc/qtcreator/images/qtcreator-edit-cmake-configuration-self-built-qt.webp new file mode 100644 index 00000000000..820461039e9 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-edit-cmake-configuration-self-built-qt.webp differ diff --git a/doc/qtcreator/images/qtcreator-projects-cpp-code-model.webp b/doc/qtcreator/images/qtcreator-projects-cpp-code-model.webp new file mode 100644 index 00000000000..259d8092f30 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-projects-cpp-code-model.webp differ diff --git a/doc/qtcreator/src/baremetal/creator-baremetal-dev.qdoc b/doc/qtcreator/src/baremetal/creator-baremetal-dev.qdoc index 3df5faba46d..70ded6fc366 100644 --- a/doc/qtcreator/src/baremetal/creator-baremetal-dev.qdoc +++ b/doc/qtcreator/src/baremetal/creator-baremetal-dev.qdoc @@ -23,7 +23,9 @@ applications on them. \note If you use qmake to build the project and the device does not have - Qt libraries, you need a fake Qt installation. + Qt libraries, you need a Qt installation that meets the requirements in + \l{Self-built Qt versions}. In addition, the \c mkspecs directory needs + to be complete enough to parse .pro files. The following toolchains are supported for building applications: diff --git a/doc/qtcreator/src/docker/creator-docker.qdoc b/doc/qtcreator/src/docker/creator-docker.qdoc index 9524dcd5ec8..4f1167b359a 100644 --- a/doc/qtcreator/src/docker/creator-docker.qdoc +++ b/doc/qtcreator/src/docker/creator-docker.qdoc @@ -25,6 +25,8 @@ You are advised to use CMake to build applications in the Docker container. + \note Enable the Docker plugin to use it. + To pull images from Docker hub or other registries, use the \l{https://docs.docker.com/engine/reference/commandline/pull/}{docker pull} command. @@ -64,7 +66,8 @@ Go to \preferences > \uicontrol Kits to check that the automatically generated kits point to the appropriate kit items. - \sa {Docker}{How To: Develop for Docker}, {Manage Kits}{How To: Manage Kits} + \sa {Enable and disable plugins}, {Docker}{How To: Develop for Docker}, + {Manage Kits}{How To: Manage Kits} */ /*! @@ -75,6 +78,8 @@ \title Set preferences for Docker devices + \note Enable the Docker plugin to use it. + To set preferences for Docker devices: \list 1 @@ -165,7 +170,8 @@ \uicontrol {List Auto-Detected Kit Items}. To remove them, select \uicontrol {Remove Auto-Detected Kit Items}. - \sa {Docker}{How To: Develop for Docker}, {Manage Kits}{How To: Manage Kits} + \sa {Enable and disable plugins}, {Docker}{How To: Develop for Docker}, + {Manage Kits}{How To: Manage Kits} */ /*! @@ -176,6 +182,8 @@ \title Build for and run on Docker devices + \note Enable the Docker plugin to use it. + To specify build settings for Docker images: \list 1 @@ -188,5 +196,6 @@ Select \uicontrol Run to specify run settings. Usually, you can use the default settings. - \sa {Docker}{How To: Develop for Docker}, {Manage Kits}{How To: Manage Kits} + \sa {Enable and disable plugins}, {Docker}{How To: Develop for Docker}, + {Manage Kits}{How To: Manage Kits} */ diff --git a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc index bdf06e24eb4..d8bba6edf62 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc @@ -124,8 +124,34 @@ The document outline in the \l{Outline} view is backed by clangd's document symbol support, which makes the results more reliable than before. - \sa {Code Model}, {Clangd}, {Specify clangd settings}, - {Specify Clang tools settings}, {Use compilation databases} + \sa {Configure C++ code model}, {Specify clangd settings}, + {Specify Clang tools settings}, {Use compilation databases}, + {Code Model}, {Clangd} +*/ + +/*! + \page creator-how-to-cpp-code-model.html + \previouspage creator-how-tos.html + + \ingroup creator-how-to-configure-editors + \ingroup creator-how-to-projects-configure + + \title Configure C++ code model + + The code model offers services such as code completion, syntactic and + semantic highlighting, and diagnostics. + + To configure the C++ code model for a project: + + \list 1 + \li Go to \uicontrol Projects > \uicontrol {Project Settings} > + \uicontrol {C++ Code Model}. + \image qtcreator-projects-cpp-code-model.webp {C++ Code Model settings} + \li Clear \uicontrol {Use global settings}. + \li Set \uicontrol {C++ Code Model} settings for the project. + \endlist + + \sa {Code Model} */ /*! @@ -138,40 +164,43 @@ \brief Sets global preferences for the code model. - The Clang code model offers services such as code completion, syntactic and + The code model offers services such as code completion, syntactic and semantic highlighting, and diagnostics. - To configure the Clang code model globally: + To configure the C++ code model globally, go to \preferences > + \uicontrol C++ > \uicontrol {Code Model}. - \list 1 + \image qtcreator-preferences-code-model.webp {C++ Code Model preferences} - \li Select \preferences > \uicontrol C++ > - \uicontrol {Code Model}. - - \image qtcreator-preferences-code-model.webp {C++ Code Model preferences} - - \li To instruct the code model to interpret ambiguous header files as C - language files if you develop mainly using C, select the - \uicontrol {Interpret ambiguous headers as C headers} check box. - - \li To process precompiled headers, deselect the - \uicontrol {Ignore precompiled headers} check box. - - \li To use the built-in preprocessor to show the - pre-processed source file in the editor, select - \uicontrol {Use built-in preprocessor to show pre-processed files}. + The following table summarizes the preferences. + \table + \header + \li Setting + \li Value + \row + \li \uicontrol {Interpret ambiguous headers as C headers} + \li Instructs the code model to interpret ambiguous header files as C + language files. Select this checkbox if you develop mainly using C. + \row + \li \uicontrol {Ignore precompiled headers} + \li Clear this checkbox to process precompiled headers. + \row + \li \uicontrol {Use built-in preprocessor to show pre-processed files} + \li Uses the built-in preprocessor to show the + pre-processed source file in the editor. + \row + \li \uicontrol {Do not index files greater than} \li To avoid out-of-memory crashes caused by indexing huge source files that are typically auto-generated by scripts or code, the size of - files to index is limited to 5MB by default. To adjust the limit, - edit the value for the \uicontrol {Do not index files greater than} - check box. To index all files, deselect the check box. + files to index is limited to 5MB by default. - \li To ignore files that match wildcard patterns, select the - \uicontrol {Ignore files} check box and enter each wildcard pattern - on a separate line in the field. - - \endlist + To index all files, clear the checkbox. + \row + \li \uicontrol {Ignore files} + \li To ignore files that match wildcard patterns, enter each wildcard + pattern on a separate line in the field. + \endtable \section1 Inspect preprocessed C++ code @@ -186,7 +215,8 @@ this action also expands all \c {"#include "} statements to their actual contents. - \sa {Specify clangd settings}, {Clang Code Model}, {Clangd} + \sa {Configure C++ code model}, {Specify clangd settings}, + {Clang Code Model}, {Clangd} */ /*! diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-qt-versions.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-qt-versions.qdoc index 0b06e1d84c1..48958f8846e 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-qt-versions.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-qt-versions.qdoc @@ -108,28 +108,45 @@ To verify the installation of a particular Qt version, \QC calls \c {qmake -query} and checks that the directories referenced in the - output exist. When \QC complains about the installation of a self-built Qt - version, try running \c {make install} in the build directory to actually - install Qt into the configured location. If you installed Qt using the Qt - Installer, run \QMT to check for updates or to reinstall - the Qt version. + output exist. If you installed Qt using \QOI, run + \QMT to check for updates or to reinstall the Qt version. - \section1 Minimum requirements - If your build of Qt is incomplete but you still want to use qmake as build - system, you need to ensure the following minimum requirements to use that - setup with \QC. + \section2 Self-built Qt versions - \list 1 + To build projects with a self-built Qt version, add it as described in + \l{Set up new Qt versions}. + + Your Qt has to meet the following minimum requirements: + + \list \li qmake is an executable that understands the \c -query command-line argument. \li The \c bin and \c include directories have to exist. \QC fetches these directories by running \c{qmake -query}. - \li The \c mkspecs directory should be complete enough to parse .pro - files. \endlist - If your Qt version has no \c libQtCore.so, \QC cannot detect the ABI. + Add a kit for the Qt version and configure it for CMake. - \sa {kits-tab}{Kits} + \QC issues warnings if: + + \list + \li \c libQtCore.so is missing, so \QC cannot detect the ABI. + \li \c toolchain.cmake is missing. For example, you built Qt with the + \c -static option for an x86 platform. + \endlist + + Try the following: + + \list + \li Run \c {make install} in the build directory to install Qt into the + configured location. + \li Set the value of the \c CMAKE_PREFIX_PATH variable in \preferences > + \uicontrol Kits > \uicontrol Kits > \uicontrol {CMake Configuration} + to the location where you installed Qt. + \endlist + + \image qtcreator-edit-cmake-configuration-self-built-qt.webp {Setting the path to a self-built Qt} + + \sa {Manage Kits}{How To: Manage Kits}, {kits-tab}{Kits} */ diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc index df0b2b0f7a7..3f8e93f1421 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc @@ -85,6 +85,7 @@ \li \l{Specify clangd settings}{Clangd} \li \l{Specify Clang tools settings}{Clang Tools} \li \l{Set Copilot preferences}{Copilot} + \li \l{Configure C++ code model}{C++ Code Model} \li \l{Specify code style}{C++ Code Style} \li \l{Set C++ file naming preferences}{C++ File Naming} \li \l{Specify dependencies}{Dependencies} diff --git a/qbs/imports/QtcDocumentation.qbs b/qbs/imports/QtcDocumentation.qbs index 3017114c8c4..c5ddf497206 100644 --- a/qbs/imports/QtcDocumentation.qbs +++ b/qbs/imports/QtcDocumentation.qbs @@ -12,6 +12,7 @@ Product { property string versionTag: qtc.qtcreator_version.replace(/\.|-/g, "") Qt.core.qdocEnvironment: [ + "GENERATED_ATTRIBUTIONS_DIR=" + product.buildDirectory, "IDE_DISPLAY_NAME=" + qtc.ide_display_name, "IDE_CASED_ID=" + qtc.ide_cased_id, "IDE_ID=" + qtc.ide_id, diff --git a/share/qtcreator/debugger/cdbbridge.py b/share/qtcreator/debugger/cdbbridge.py index c16467915a0..ce88c903a77 100644 --- a/share/qtcreator/debugger/cdbbridge.py +++ b/share/qtcreator/debugger/cdbbridge.py @@ -76,7 +76,9 @@ class Dumper(DumperBase): self.outputLock = threading.Lock() self.isCdb = True - #FIXME + #FIXME + def register_known_qt_types(self): + DumperBase.register_known_qt_types(self) typeid = self.typeid_for_string('@QVariantMap') del self.type_code_cache[typeid] del self.type_target_cache[typeid] diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index c2580880f55..eb45d918be4 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -172,8 +172,6 @@ class DumperBase(): self.qtCustomEventFunc = 0 self.qtCustomEventPltFunc = 0 self.qtPropertyFunc = 0 - self.qtversion = None - self.qtns = None self.passExceptions = False self.isTesting = False self.qtLoaded = False @@ -189,6 +187,11 @@ class DumperBase(): self.dumpermodules = [] + # These are sticky for the session + self.qtversion = None + self.qtversionAtLeast6 = None + self.qtnamespace = None + self.init_type_cache() try: @@ -211,7 +214,7 @@ class DumperBase(): self.currentPrintsAddress = True self.currentChildType = None self.currentChildNumChild = None - self.register_known_types() + self.register_known_simple_types() def setVariableFetchingOptions(self, args): self.last_args = args @@ -233,9 +236,16 @@ class DumperBase(): self.useTimeStamps = int(args.get('timestamps', '0')) self.partialVariable = args.get('partialvar', '') self.uninitialized = args.get('uninitialized', []) - self.qtversion = args.get('qtversion', 0x060602) - self.qtnamespace = args.get('qtnamespace', '') + self.uninitialized = list(map(lambda x: self.hexdecode(x), self.uninitialized)) + + if self.qtversion is None: + self.qtversion = args.get('qtversion', None) + if self.qtversion == 0: + self.qtversion = None + if self.qtnamespace is None: + self.qtnamespace = args.get('qtnamespace', None) + #self.warn('NAMESPACE: "%s"' % self.qtNamespace()) #self.warn('EXPANDED INAMES: %s' % self.expandedINames) #self.warn('WATCHERS: %s' % self.watchers) @@ -256,11 +266,50 @@ class DumperBase(): args['partialvar'] = '' self.fetchVariables(args) + def extractQtVersion(self): + # can be overridden in bridges + pass + def qtVersion(self): - return self.qtversion + if self.qtversion: + return self.qtversion + + #self.warn("ACCESSING UNKNOWN QT VERSION") + self.qtversion = self.extractQtVersion() + if self.qtversion: + return self.qtversion + + #self.warn("EXTRACTING QT VERSION FAILED. GUESSING NOW.") + if self.qtversionAtLeast6 is None or self.qtversionAtLeast6 is True: + return 0x060602 + return 0x050f00 + + def qtVersionAtLeast(self, version): + # A hack to cover most of the changes from Qt 5 to 6 + if version == 0x60000 and self.qtversionAtLeast6 is not None: + return self.qtversionAtLeast6 + if version == 0x50000: # FIXME: This drops unknown 4.x for now + return True + return self.qtVersion() >= version + + def qtVersionPing(self, typeid, size_for_qt5=-1): + # To be called from places where the type size is sufficient + # to distinguish Qt 5.x and 6.x + if size_for_qt5 == -1: + size_for_qt5 = self.ptrSize() + test_size = self.type_size(typeid) + self.setQtVersionAtLeast6(test_size > size_for_qt5) + + def setQtVersionAtLeast6(self, is6): + if self.qtversionAtLeast6 is None: + #self.warn("SETTING Qt VERSION AT LEAST 6 TO %s" % is6) + self.qtversionAtLeast6 = is6 + self.register_known_qt_types() + #else: + # self.warn("QT VERSION ALREADY KNOWN") def qtNamespace(self): - return self.qtnamespace + return '' if self.qtnamespace is None else self.qtnamespace def resetPerStepCaches(self): self.perStepCache = {} @@ -494,8 +543,13 @@ class DumperBase(): def register_struct(self, name, p5=0, p6=0, s=0, qobject_based=False): # p5 = n -> n * ptrsize for Qt 5 # p6 = n -> n * ptrsize for Qt 6 - #if self.qtVersion() >= 0x060000: # FIXME: Qt 5, ptrSize() - size = 8 * p6 + s + if self.qtversionAtLeast6 is None: + self.warn("TOO EARLY TO GUESS QT VERSION") + size = 8 * p6 + s + elif self.qtversionAtLeast6 is True: + size = 8 * p6 + s + else: + size = 8 * p5 + s typeid = self.typeid_for_string(name) self.type_code_cache[typeid] = TypeCode.Struct self.type_size_cache[typeid] = size @@ -503,7 +557,7 @@ class DumperBase(): self.type_alignment_cache[typeid] = 8 return typeid - def register_known_types(self): + def register_known_simple_types(self): typeid = 0 self.typeid_cache[''] = typeid self.type_code_cache[typeid] = TypeCode.Void @@ -563,6 +617,8 @@ class DumperBase(): self.register_enum('@Qt::ItemDataRole', 4) + def register_known_qt_types(self): + #self.warn("REGISTERING KNOWN QT TYPES NOW") self.register_struct('@QObject', p5=2, p6=2, qobject_based=True) self.register_struct('@QObjectPrivate', p5=10, p6=10) # FIXME: Not exact @@ -680,9 +736,6 @@ class DumperBase(): # Hex decoding operating on str, return str. @staticmethod def hexdecode(s, encoding='utf8'): - if sys.version_info[0] == 2: - # For python2 we need an extra str() call to return str instead of unicode - return str(s.decode('hex').decode(encoding)) return bytes.fromhex(s).decode(encoding) # Hex encoding operating on str or bytes, return str. @@ -690,10 +743,6 @@ class DumperBase(): def hexencode(s): if s is None: s = '' - if sys.version_info[0] == 2: - if isinstance(s, buffer): - return bytes(s).encode('hex') - return s.encode('hex') if isinstance(s, str): s = s.encode('utf8') return hexencode_(s) @@ -711,9 +760,9 @@ class DumperBase(): return limit def vectorData(self, value): - if self.qtVersion() >= 0x060000: + if self.qtVersionAtLeast(0x060000): data, length, alloc = self.qArrayData(value) - elif self.qtVersion() >= 0x050000: + elif self.qtVersionAtLeast(0x050000): vector_data_ptr = self.extractPointer(value) if self.ptrSize() == 4: (ref, length, alloc, offset) = self.split('IIIp', vector_data_ptr) @@ -729,7 +778,7 @@ class DumperBase(): return data, length def qArrayData(self, value): - if self.qtVersion() >= 0x60000: + if self.qtVersionAtLeast(0x60000): dd, data, length = self.split('ppp', value) if dd: _, _, alloc = self.split('iip', dd) @@ -740,7 +789,7 @@ class DumperBase(): def qArrayDataHelper(self, array_data_ptr): # array_data_ptr is what is e.g. stored in a QByteArray's d_ptr. - if self.qtVersion() >= 0x050000: + if self.qtVersionAtLeast(0x050000): # QTypedArray: # - QtPrivate::RefCount ref # - int length @@ -753,7 +802,7 @@ class DumperBase(): data = data & 0xffffffff else: data = data & 0xffffffffffffffff - elif self.qtVersion() >= 0x040000: + elif self.qtVersionAtLeast(0x040000): # Data: # - QBasicAtomicInt ref; # - int alloc, length; @@ -1597,7 +1646,7 @@ class DumperBase(): intSize = 4 ptrSize = self.ptrSize() - if self.qtVersion() >= 0x060000: + if self.qtVersionAtLeast(0x060000): # Size of QObjectData: 9 pointer + 2 int # - vtable # - QObject *q_ptr; @@ -1618,7 +1667,7 @@ class DumperBase(): # - QList > eventFilters; # - QString objectName objectNameAddress = extra + 12 * ptrSize - elif self.qtVersion() >= 0x050000: + elif self.qtVersionAtLeast(0x050000): # Size of QObjectData: 5 pointer + 2 int # - vtable # - QObject *q_ptr; @@ -1811,7 +1860,7 @@ class DumperBase(): # a Q_OBJECT SMO has a non-null superdata (unless it's QObject itself), # a Q_GADGET SMO has a null superdata (hopefully) if result and not isQObjectProper: - if self.qtVersion() >= 0x60000 and self.isWindowsTarget(): + if self.qtVersionAtLeast(0x60000) and self.isWindowsTarget(): (direct, indirect) = self.split('pp', result) # since Qt 6 there is an additional indirect super data getter on windows if direct == 0 and indirect == 0: @@ -1895,14 +1944,14 @@ class DumperBase(): return result def listData(self, value, check=True): - if self.qtVersion() >= 0x60000: + if self.qtVersionAtLeast(0x60000): dd, data, size = self.split('ppi', value) return data, size base = self.extractPointer(value) (ref, alloc, begin, end) = self.split('IIII', base) array = base + 16 - if self.qtVersion() < 0x50000: + if not self.qtVersionAtLeast(0x50000): array += self.ptrSize() size = end - begin @@ -1941,7 +1990,7 @@ class DumperBase(): def metaString(self, metaObjectPtr, index, revision): ptrSize = self.ptrSize() stringdataOffset = ptrSize - if self.isWindowsTarget() and self.qtVersion() >= 0x060000: + if self.isWindowsTarget() and self.qtVersionAtLeast(0x060000): stringdataOffset += ptrSize # indirect super data member stringdata = self.extract_pointer_at_address(int(metaObjectPtr) + stringdataOffset) @@ -1970,19 +2019,19 @@ class DumperBase(): self.putField('sortgroup', sortorder) def putQMetaStuff(self, value, origType): - if self.qtVersion() >= 0x060000: + if self.qtVersionAtLeast(0x060000): metaObjectPtr, handle = value.split('pp') else: metaObjectPtr, handle = value.split('pI') if metaObjectPtr != 0: - if self.qtVersion() >= 0x060000: + if self.qtVersionAtLeast(0x060000): if handle == 0: self.putEmptyValue() return revision = 9 name, alias, flags, keyCount, data = self.split('IIIII', handle) index = name - elif self.qtVersion() >= 0x050000: + elif self.qtVersionAtLeast(0x050000): revision = 7 dataPtr = self.extract_pointer_at_address(metaObjectPtr + 2 * self.ptrSize()) index = self.extractInt(dataPtr + 4 * handle) @@ -2024,7 +2073,7 @@ class DumperBase(): def extractDataPtr(someMetaObjectPtr): # dataPtr = metaObjectPtr['d']['data'] - if self.qtVersion() >= 0x60000 and self.isWindowsTarget(): + if self.qtVersionAtLeast(0x60000) and self.isWindowsTarget(): offset = 3 else: offset = 2 @@ -2054,13 +2103,13 @@ class DumperBase(): extraData = 0 if qobjectPtr: dd = self.extract_pointer_at_address(qobjectPtr + ptrSize) - if self.qtVersion() >= 0x60000: + if self.qtVersionAtLeast(0x60000): (dvtablePtr, qptr, parent, children, bindingStorageData, bindingStatus, flags, postedEvents, dynMetaObjectPtr, # Up to here QObjectData. extraData, threadDataPtr, connectionListsPtr, sendersPtr, currentSenderPtr) \ = self.split('pp{@QObject*}{@QList<@QObject *>}ppIIp' + 'ppppp', dd) - elif self.qtVersion() >= 0x50000: + elif self.qtVersionAtLeast(0x50000): (dvtablePtr, qptr, parent, children, flags, postedEvents, dynMetaObjectPtr, # Up to here QObjectData. extraData, threadDataPtr, connectionListsPtr, @@ -2186,7 +2235,7 @@ typename)) with Children(self): # Static properties. for i in range(propertyCount): - if self.qtVersion() >= 0x60000: + if self.qtVersionAtLeast(0x60000): t = self.split('IIIII', dataPtr + properties * 4 + 20 * i) else: t = self.split('III', dataPtr + properties * 4 + 12 * i) @@ -2239,18 +2288,18 @@ typename)) data += inner_size variant_typeid = self.cheap_typeid_from_name('@QVariant') - if self.qtVersion() >= 0x60000: + if self.qtVersionAtLeast(0x60000): values = vectorGenerator(extraData + 3 * ptrSize, variant_typeid) - elif self.qtVersion() >= 0x50600: + elif self.qtVersionAtLeast(0x50600): values = vectorGenerator(extraData + 2 * ptrSize, variant_typeid) - elif self.qtVersion() >= 0x50000: + elif self.qtVersionAtLeast(0x50000): values = list5Generator(extraData + 2 * ptrSize, variant_typeid) else: variantptr_typeid = self.cheap_typeid_from_name('@QVariant') values = list5Generator(extraData + 2 * ptrSize, variantptr_typeid) bytearray_typeid = self.cheap_typeid_from_name('@QByteArray') - if self.qtVersion() >= 0x60000: + if self.qtVersionAtLeast(0x60000): names = list6Generator(extraData, bytearray_typeid) else: names = list5Generator(extraData + ptrSize, bytearray_typeid) @@ -2671,10 +2720,7 @@ typename)) try: if funcname.startswith('qdump__'): typename = funcname[7:] - if sys.version_info > (3,): - spec = inspect.getfullargspec(function) - else: - spec = inspect.getargspec(function) + spec = inspect.getfullargspec(function) if len(spec.args) == 2: self.qqDumpers[typename] = function elif len(spec.args) == 3 and len(spec.defaults) == 1: @@ -2721,11 +2767,8 @@ typename)) def reloadDumpers(self, args): for mod in self.dumpermodules: m = sys.modules[mod] - if sys.version_info[0] >= 3: - import importlib - importlib.reload(m) - else: - reload(m) + import importlib + importlib.reload(m) self.setupDumpers(args) def loadDumpers(self, args): @@ -3427,9 +3470,9 @@ typename)) ): return True if strippedName == 'QStringList': - return self.dumper.qtVersion() >= 0x050000 + return self.dumper.qtVersionAtLeast(0x050000) if strippedName == 'QList': - return self.dumper.qtVersion() >= 0x050600 + return self.dumper.qtVersionAtLeast(0x050600) return False class Field: @@ -3550,7 +3593,7 @@ typename)) if typename.startswith('QList<') or typename.startswith('QVector<'): typeid = self.typeid_for_string(typename) if typeid: - size = 3 * self.ptrSize() if self.qtVersion() >= 0x060000 else self.ptrSize() + size = 3 * self.ptrSize() if self.qtVersionAtLeast(0x060000) else self.ptrSize() self.type_code_cache[typeid] = TypeCode.Struct self.type_size_cache[typeid] = size return typeid diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index 5e2957b1812..ee25520bced 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -874,6 +874,36 @@ class Dumper(DumperBase): except: return '0x%x' % address + def qtVersionString(self): + try: + return str(gdb.lookup_symbol('qVersion')[0].value()()) + except: + pass + try: + ns = self.qtNamespace() + return str(gdb.parse_and_eval("((const char*(*)())'%sqVersion')()" % ns)) + except: + pass + return None + + def extractQtVersion(self): + try: + # Only available with Qt 5.3+ + return int(str(gdb.parse_and_eval('((void**)&qtHookData)[2]')), 16) + except: + pass + + try: + version = self.qtVersionString() + (major, minor, patch) = version[version.find('"') + 1:version.rfind('"')].split('.') + qtversion = 0x10000 * int(major) + 0x100 * int(minor) + int(patch) + self.qtVersion = lambda: qtversion + return qtversion + except: + # Use fallback until we have a better answer. + return None + + def createSpecialBreakpoints(self, args): self.specialBreakpoints = [] diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index 7cd3bef77e0..3f7ec792a61 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -18,11 +18,7 @@ sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.curre # Simplify development of this module by reloading deps if 'dumper' in sys.modules: - if sys.version_info[0] >= 3: - if sys.version_info[1] > 3: - from importlib import reload - else: - def reload(m): print('Unsupported Python version - not reloading %s' % str(m)) + from importlib import reload reload(sys.modules['dumper']) from dumper import DumperBase, SubItem, Children, TopLevelItem @@ -34,16 +30,10 @@ from dumper import DumperBase, SubItem, Children, TopLevelItem ####################################################################### qqWatchpointOffset = 10000 -_c_str_trans = None - -if sys.version_info[0] >= 3: - _c_str_trans = str.maketrans({"\n": "\\n", '"':'\\"', "\\":"\\\\"}) +_c_str_trans = str.maketrans({"\n": "\\n", '"':'\\"', "\\":"\\\\"}) def toCString(s): - if _c_str_trans is not None: - return str(s).translate(_c_str_trans) - else: - return str(s).replace('\\', '\\\\').replace('\n', '\\n').replace('"', '\\"') + return str(s).translate(_c_str_trans) def fileNameAsString(file): return toCString(file) if file.IsValid() else '' @@ -783,6 +773,54 @@ class Dumper(DumperBase): self.fetchInternalFunctions = lambda: None + def extractQtVersion(self): + for func in self.target.FindFunctions('qVersion'): + name = func.GetSymbol().GetName() + if name == None: + continue + if name.endswith('()'): + name = name[:-2] + if name.count(':') > 2: + continue + + #qtNamespace = name[:name.find('qVersion')] + #self.qtNamespace = lambda: qtNamespace + + options = lldb.SBExpressionOptions() + res = self.target.EvaluateExpression(name + '()', options) + + if not res.IsValid() or not res.GetType().IsPointerType(): + exp = '((const char*())%s)()' % name + res = self.target.EvaluateExpression(exp, options) + + if not res.IsValid() or not res.GetType().IsPointerType(): + exp = '((const char*())_Z8qVersionv)()' + res = self.target.EvaluateExpression(exp, options) + + if not res.IsValid() or not res.GetType().IsPointerType(): + continue + + version = str(res) + if version.count('.') != 2: + continue + + version.replace("'", '"') # Both seem possible + version = version[version.find('"') + 1:version.rfind('"')] + + (major, minor, patch) = version.split('.') + qtVersion = 0x10000 * int(major) + 0x100 * int(minor) + int(patch) + return qtVersion + + try: + versionValue = self.target.EvaluateExpression('qtHookData[2]').GetNonSyntheticValue() + if versionValue.IsValid(): + return versionValue.unsigned + except: + pass + + return None + + def handleCommand(self, command): result = lldb.SBCommandReturnObject() self.debugger.GetCommandInterpreter().HandleCommand(command, result) @@ -2312,9 +2350,6 @@ class SummaryProvider(LogMixin): if encoding in text_encodings: try: decodedValue = Dumper.hexdecode(summaryValue, encoding) - # LLDB expects UTF-8 for python 2 - if sys.version_info[0] < 3: - return "\"%s\"" % (decodedValue.encode('utf8')) return '"' + decodedValue + '"' except: return "" % (summaryValue, encoding, sys.exc_info()[1]) diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index af99534c9b4..1b38223c2e1 100644 --- a/share/qtcreator/debugger/qttypes.py +++ b/share/qtcreator/debugger/qttypes.py @@ -33,7 +33,8 @@ def qedit__QByteArray(d, value, data): def qdump__QByteArray(d, value): - if d.qtVersion() >= 0x60000: + d.qtVersionPing(value.typeid) + if d.qtVersionAtLeast(0x060000): dd, data, length = value.split('ppi') if dd: _, _, alloc = d.split('iii', dd) @@ -76,7 +77,8 @@ def qdump__QByteArray(d, value): def qdump__QBitArray(d, value): - if d.qtVersion() >= 0x60000: + d.qtVersionPing(value.typeid) + if d.qtVersionAtLeast(0x060000): _, data, basize = value.split('ppi') else: data, basize, _ = d.qArrayData(value['d']) @@ -232,13 +234,13 @@ def qdump__QStandardItem(d, value): #d.createType('@QStandardItem*') vtable, dptr = value.split('pp') - if d.qtVersion() >= 0x060000: + if d.qtVersionAtLeast(0x060000): model, parent, values, children, rows, cols, item = \ d.split('pp{@QList<@QStandardItemData>}{@QList<@QStandardItem *>}IIp', dptr) else: # There used to be a virtual destructor that got removed in # 88b6abcebf29b455438 on Apr 18 17:01:22 2017 - if d.qtVersion() < 0x050900 and not d.isMsvcTarget(): + if not d.qtVersionAtLeast(0x050900) and not d.isMsvcTarget(): dptr += d.ptrSize(); model, parent, values, children, rows, cols, item = \ d.split('pp{@QVector<@QStandardItemData>}{@QVector<@QStandardItem *>}IIp', dptr) @@ -266,7 +268,7 @@ def qdump__QDate(d, value): d.enumExpression('DateFormat', 'TextDate')) d.putCallItem('(ISO)', '@QString', value, 'toString', d.enumExpression('DateFormat', 'ISODate')) - if d.qtVersion() < 0x060000: + if not d.qtVersionAtLeast(0x060000): d.putCallItem('(SystemLocale)', '@QString', value, 'toString', d.enumExpression('DateFormat', 'SystemLocaleDate')) d.putCallItem('(Locale)', '@QString', value, 'toString', @@ -286,7 +288,7 @@ def qdump__QTime(d, value): d.enumExpression('DateFormat', 'TextDate')) d.putCallItem('(ISO)', '@QString', value, 'toString', d.enumExpression('DateFormat', 'ISODate')) - if d.canCallLocale() and d.qtVersion() < 0x060000: + if d.canCallLocale() and not d.qtVersionAtLeast(0x060000): d.putCallItem('(SystemLocale)', '@QString', value, 'toString', d.enumExpression('DateFormat', 'SystemLocaleDate')) d.putCallItem('(Locale)', '@QString', value, 'toString', @@ -305,13 +307,12 @@ def qdump__QTimeZone(d, value): def qdump__QDateTime(d, value): - qtVersion = d.qtVersion() isValid = False # This relies on the Qt4/Qt5 internal structure layout: # {sharedref(4), ... base = d.extractPointer(value) is32bit = d.ptrSize() == 4 - if qtVersion >= 0x050200: + if d.qtVersionAtLeast(0x050200): tiVersion = d.qtTypeInfoVersion() #DumperBase.warn('TI VERSION: %s' % tiVersion) if tiVersion is None: @@ -384,9 +385,9 @@ def qdump__QDateTime(d, value): # - [QTime time;] # - - uint mds; # - Spec spec; - dateSize = 8 if qtVersion >= 0x050000 else 4 # Qt5: qint64, Qt4 uint + dateSize = 8 if qtVersionAtLeast(0x050000) else 4 # Qt5: qint64, Qt4 uint # 4 byte padding after 4 byte QAtomicInt if we are on 64 bit and QDate is 64 bit - refPlusPadding = 8 if qtVersion >= 0x050000 and d.ptrSize() == 8 else 4 + refPlusPadding = 8 if qtVersionAtLeast(0x050000) and d.ptrSize() == 8 else 4 dateBase = base + refPlusPadding timeBase = dateBase + dateSize mds = d.extractInt(timeBase) @@ -410,7 +411,7 @@ def qdump__QDateTime(d, value): d.enumExpression('DateFormat', 'ISODate')) d.putCallItem('toUTC', '@QDateTime', value, 'toTimeSpec', d.enumExpression('TimeSpec', 'UTC')) - if d.qtVersion() < 0x060000: + if not d.qtVersionAtLeast(0x060000): d.putCallItem('(SystemLocale)', '@QString', value, 'toString', d.enumExpression('DateFormat', 'SystemLocaleDate')) d.putCallItem('(Locale)', '@QString', value, 'toString', @@ -756,7 +757,6 @@ def qdump__QFile(d, value): def qdump__QFileInfo(d, value): privAddress = d.extractPointer(value) #bit32 = d.ptrSize() == 4 - #qt5 = d.qtVersion() >= 0x050000 #try: # d.putStringValue(value['d_ptr']['d'].dereference()['fileNames'][3]) #except: @@ -876,7 +876,7 @@ def qdump__QVariantHash(d, value): def qdumpHelper_QHash(d, value, keyType, valueType): - if d.qtVersion() >= 0x60000: + if d.qtVersionAtLeast(0x060000): qdumpHelper_QHash_6(d, value, keyType, valueType) else: qdumpHelper_QHash_5(d, value, keyType, valueType) @@ -918,7 +918,7 @@ def qdumpHelper_QHash_5(d, value, keyType, valueType): d.putItemCount(size) if d.isExpanded(): - isShort = d.qtVersion() < 0x050000 and keyType.name == 'int' + isShort = not d.qtVersionAtLeast(0x050000) and keyType.name == 'int' with Children(d, size): node = hashDataFirstNode() for i in d.childRange(): @@ -994,7 +994,7 @@ def qHashIteratorHelper(d, value): if d.isExpanded(): with Children(d): node = d.extractPointer(value) - isShort = d.qtVersion() < 0x050000 and keyType.name == 'int' + isShort = not d.qtVersionAtLeast(0x050000) and keyType.name == 'int' if isShort: typeCode = 'P{%s}@{%s}' % (keyType.name, valueType.name) (pnext, key, padding2, val) = d.split(typeCode, node) @@ -1015,9 +1015,8 @@ def qdump__QHash__iterator(d, value): def qdump__QHostAddress(d, value): dd = d.extractPointer(value) - qtVersion = d.qtVersion() tiVersion = d.qtTypeInfoVersion() - #DumperBase.warn('QT: %x, TI: %s' % (qtVersion, tiVersion)) + #DumperBase.warn('QT: %x, TI: %s' % (d.qtVersion(), tiVersion)) mayNeedParse = True if tiVersion is not None: if tiVersion >= 16: @@ -1032,14 +1031,14 @@ def qdump__QHostAddress(d, value): else: (ipString, scopeId, a4, pad, a6, protocol, isParsed) \ = d.split('{@QString}{@QString}{@quint32}I16sI{bool}', dd) - elif qtVersion >= 0x050600: # 5.6.0 at f3aabb42 + elif qtVersionAtLeast(0x050600): # 5.6.0 at f3aabb42 if d.ptrSize() == 8 or d.isWindowsTarget(): (ipString, scopeId, a4, pad, a6, protocol, isParsed) \ = d.split('{@QString}{@QString}{@quint32}I16sI{bool}', dd) else: (ipString, scopeId, a4, a6, protocol, isParsed) \ = d.split('{@QString}{@QString}{@quint32}16sI{bool}', dd) - elif qtVersion >= 0x050000: # 5.2.0 at 62feb088 + elif qtVersionAtLeast(0x050000): # 5.2.0 at 62feb088 (ipString, scopeId, a4, a6, protocol, isParsed) \ = d.split('{@QString}{@QString}{@quint32}16sI{bool}', dd) else: # 4.8.7 at b05d05f @@ -1104,7 +1103,8 @@ def qdumpHelper_QList(d, value, inner_typish): data, size = d.listData(value, check=True) d.putItemCount(size) - if d.qtVersion() >= 0x60000: + d.qtVersionPing(value.typeid) + if d.qtVersionAtLeast(0x060000): d.putPlotData(data, size, innerType) return @@ -1145,9 +1145,9 @@ def qform__QImage(): def qdump__QImage(d, value): - if d.qtVersion() >= 0x060000: + if d.qtVersionAtLeast(0x060000): vtbl, painters, image_data = value.split('ppp') - elif d.qtVersion() >= 0x050000: + elif d.qtVersionAtLeast(0x050000): vtbl, painters, reserved, image_data = value.split('pppp') else: vtbl, painters, image_data = value.split('ppp') @@ -1161,12 +1161,12 @@ def qdump__QImage(d, value): d.putExpandable() if d.isExpanded(): - if d.qtVersion() < 0x060000: - (ref, width, height, depth, nbytes, pad, devicePixelRatio, colorTable, - bits, iformat) = d.split('iiiii@dppi', image_data) - else: + if d.qtVersionAtLeast(0x060000): (ref, width, height, depth, nbytes, pad, devicePixelRatio, _, _, _, bits, iformat) = d.split('iiiii@dppppi', image_data) + else: + (ref, width, height, depth, nbytes, pad, devicePixelRatio, colorTable, + bits, iformat) = d.split('iiiii@dppi', image_data) with Children(d): d.putIntItem('width', width) d.putIntItem('height', height) @@ -1222,8 +1222,7 @@ def qdump__QLocale(d, value): # index = int(value['d']['d']['m_data']...) #d.check(index >= 0) #d.check(index <= qqLocalesCount) - qtVersion = d.qtVersion() - if qtVersion < 0x50000: + if not d.qtVersionAtLeast(0x50000): d.putStringValue(d.call('const char *', value, 'name')) d.putPlainChildren(value) return @@ -1240,7 +1239,7 @@ def qdump__QLocale(d, value): prefix = ns + 'QLocale::' try: - if qtVersion >= 0x060700: + if qtVersionAtLeast(0x060700): res = d.call('const char *', value, 'name', prefix + 'TagSeparator::Underscore') else: res = d.call('const char *', value, 'name') @@ -1347,9 +1346,9 @@ def qdump__QMap(d, value): def qdumpHelper_QMap(d, value, keyType, valueType): - if d.qtVersion() >= 0x60000: + if d.qtVersionAtLeast(0x060000): qdumpHelper_Qt6_QMap(d, value, keyType, valueType) - elif d.qtVersion() >= 0x50000: + elif d.qtVersionAtLeast(0x50000): qdumpHelper_Qt5_QMap(d, value, keyType, valueType) else: qdumpHelper_Qt4_QMap(d, value, keyType, valueType) @@ -1369,7 +1368,7 @@ def qdumpHelper_Qt6_QMultiMap(d, value, keyType, valueType): d.putBetterType('@QMultiMap<%s, %s>' % (keyType.name, valueType.name)) def qdump__QMultiMap(d, value): - if d.qtVersion() >= 0x60000: + if d.qtVersionAtLeast(0x060000): qdumpHelper_Qt6_QMultiMap(d, value, value.type[0], value.type[1]) else: qdump__QMap(d, value) @@ -1449,9 +1448,9 @@ def qdump__QProcEnvKey(d, value): def qdump__QPixmap(d, value): - if d.qtVersion() >= 0x060000: + if d.qtVersionAtLeast(0x060000): vtbl, painters, data = value.split('ppp') - elif d.qtVersion() >= 0x050000: + elif d.qtVersionAtLeast(0x050000): vtbl, painters, reserved, data = s = d.split('pppp', value) else: vtbl, painters, data = value.split('ppp') @@ -1518,15 +1517,15 @@ def qdump__QRegion(d, value): if d_ptr == 0: d.putSpecialValue('empty') else: - if d.qtVersion() >= 0x060000: + if d.qtVersionAtLeast(0x060000): ref, _, rgn = d.split('i@p', d_ptr) numRects, innerArea, rects, extents, innerRect = \ d.split('ii{@QList<@QRect>}{@QRect}{@QRect}', rgn) - elif d.qtVersion() >= 0x050400: # Padding removed in ee324e4ed + elif d.qtVersionAtLeast(0x050400): # Padding removed in ee324e4ed ref, _, rgn = d.split('i@p', d_ptr) numRects, innerArea, rects, extents, innerRect = \ d.split('ii{@QVector<@QRect>}{@QRect}{@QRect}', rgn) - elif d.qtVersion() >= 0x050000: + elif d.qtVersionAtLeast(0x050000): ref, _, rgn = d.split('i@p', d_ptr) numRects, _, rects, extents, innerRect, innerArea = \ d.split('i@{@QVector<@QRect>}{@QRect}{@QRect}i', rgn) @@ -1564,7 +1563,7 @@ def qdump__QScopedPointer(d, value): def qdump__QSet(d, value): - if d.qtVersion() >= 0x060000: + if d.qtVersionAtLeast(0x060000): qdumpHelper_QSet6(d, value) else: qdumpHelper_QSet45(d, value) @@ -1637,7 +1636,7 @@ def qdumpHelper_QSet45(d, value): d.putItemCount(length) if d.isExpanded(): keyType = value.type[0] - isShort = d.qtVersion() < 0x050000 and keyType.name == 'int' + isShort = not d.qtVersionAtLeast(0x050000) and keyType.name == 'int' with Children(d, length, childType=keyType): node = hashDataFirstNode() for i in d.childRange(): @@ -1714,7 +1713,7 @@ def qform__QStack(): def qdump__QStack(d, value): - if d.qtVersion() >= 0x60000: + if d.qtVersionAtLeast(0x060000): qdump__QList(d, value) else: qdump__QVector(d, value) @@ -1734,7 +1733,7 @@ def qdump__QPolygon(d, value): def qdump__QGraphicsPolygonItem(d, value): (vtbl, dptr) = value.split('pp') - if d.qtVersion() >= 0x060000: + if d.qtVersionAtLeast(0x060000): if d.ptrSize() == 8: offset = 424 # sizeof(QGraphicsPolygonItemPrivate), the base else: @@ -1764,6 +1763,7 @@ def qform__QString(): def qdump__QString(d, value): + d.qtVersionPing(value.typeid) d.putStringValue(value) data, length, _ = d.stringData(value) displayFormat = d.currentItemFormat() @@ -1924,7 +1924,7 @@ def qdump__QUrl(d, value): d.putValue('') return - if d.qtVersion() < 0x050000: + if not d.qtVersionAtLeast(0x050000): d.call('void', value, 'port') # Warm up internal cache. d.call('void', value, 'path') st = '{@QString}' @@ -2154,7 +2154,8 @@ qdumpHelper_QVariants_F = [ def qdump__QVariant(d, value): - if d.qtVersion() >= 0x060000: + d.qtVersionPing(value.typeid, 2 * d.ptrSize()) + if d.qtVersionAtLeast(0x060000): qdumpHelper__QVariant6(d, value) else: qdumpHelper__QVariant45(d, value) @@ -2208,12 +2209,12 @@ def qdumpHelper__QVariant45(d, value): return None # Extended Core type (Qt 5) - if variantType >= 31 and variantType <= 38 and d.qtVersion() >= 0x050000: + if variantType >= 31 and variantType <= 38 and d.qtVersionAtLeast(0x050000): qdumpHelper_QVariants_D[variantType - 31](d, value) return None # Extended Core type (Qt 4) - if variantType >= 128 and variantType <= 135 and d.qtVersion() < 0x050000: + if variantType >= 128 and variantType <= 135 and not d.qtVersionAtLeast(0x050000): if variantType == 128: d.putBetterType('@QVariant (void *)') d.putValue('0x%x' % value.extractPointer()) @@ -2234,7 +2235,7 @@ def qdumpHelper__QVariant45(d, value): innert = qdumpHelper_QVariants_B[variantType - 7] elif variantType <= 74: innert = qdumpHelper_QVariants_E[variantType - 64] - elif d.qtVersion() < 0x050000: + elif not d.qtVersionAtLeast(0x050000): innert = qdumpHelper_QVariants_F[variantType - 76] else: innert = qdumpHelper_QVariants_F[variantType - 75] @@ -2308,7 +2309,8 @@ def qform__QVector(): def qdump__QVector(d, value): - if d.qtVersion() >= 0x060000: + d.qtVersionPing(value.typeid) + if d.qtVersionAtLeast(0x060000): data, length = d.listData(value) d.putItemCount(length) d.putPlotData(data, length, value.type.target()[0]) @@ -2330,7 +2332,7 @@ if False: def qdump__QVarLengthArray(d, value): - if d.qtVersion() >= 0x060000: + if d.qtVersionAtLeast(0x060000): cap, length, data = value.split('QQp') else: cap, length, data = value.split('iip') @@ -2366,7 +2368,7 @@ def qdump_QWeakPointerHelper(d, value, isWeak, innerType=None): d.putValue('') return - if d.qtVersion() >= 0x050000: + if d.qtVersionAtLeast(0x050000): (weakref, strongref) = d.split('ii', d_ptr) else: (vptr, weakref, strongref) = d.split('pii', d_ptr) @@ -2872,7 +2874,7 @@ def qdump__QJSValue(d, value): if d.ptrSize() == 4: qdump_32__QJSValue(d, value) else: - if d.qtVersion() >= 0x60000: + if d.qtVersionAtLeast(0x060000): qdump_64__QJSValue_6(d, value) else: qdump_64__QJSValue_5(d, value) @@ -2906,7 +2908,7 @@ def qdump_64__QJSValue_6(d, value): if dd == 0: d.putValue('(undefined)') d.putType(value.type.name + ' (undefined)') - if d.qtVersion() < 0x60500: + if not d.qtVersionAtLeast(0x60500): typ = dd >> 47 if typ == 5: d.putValue('(null)') @@ -3326,7 +3328,7 @@ def qdumpHelper_QJsonObject(d, data, obj): def qdump__QJsonValue(d, value): (data, dd, t) = value.split('QpI') - if d.qtVersion() >= 0x050f00: + if d.qtVersionAtLeast(0x050f00): value = d.createProxyValue((data, dd, t, False), 'QCborValue_proxy') d.putItem(value) return @@ -3361,13 +3363,13 @@ def qdump__QJsonValue(d, value): def qdump__QJsonArray(d, value): - if d.qtVersion() >= 0x060000: + if d.qtVersionAtLeast(0x060000): dptr = d.extractPointer(value) if not dptr: d.putItemCount(0) else: qdumpHelper_QCbor_array(d, dptr, False) - elif d.qtVersion() >= 0x050f00: + elif d.qtVersionAtLeast(0x050f00): _, container_ptr = value.split('pp') qdumpHelper_QCbor_array(d, container_ptr, False) else: @@ -3375,13 +3377,13 @@ def qdump__QJsonArray(d, value): def qdump__QJsonObject(d, value): - if d.qtVersion() >= 0x060000: + if d.qtVersionAtLeast(0x060000): dptr = d.extractPointer(value) if not dptr: d.putItemCount(0) else: qdumpHelper_QCbor_map(d, dptr, False) - elif d.qtVersion() >= 0x050f00: + elif d.qtVersionAtLeast(0x050f00): _, container_ptr = value.split('pp') qdumpHelper_QCbor_map(d, container_ptr, False) else: @@ -3456,15 +3458,15 @@ def qdump__qfloat16(d, value): def qdumpHelper_QCbor_string(d, container_ptr, element_index, is_bytes): # d.split('i@{@QByteArray::size_type}pp', container_ptr) doesn't work with CDB, # so be explicit: - data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersion() >= 0x060000 else 8) - elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersion() >= 0x060000 else d.ptrSize()) + data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else 8) + elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else d.ptrSize()) elements_data_ptr, elements_size = d.vectorData(elements_pos) element_at_n_addr = elements_data_ptr + element_index * 16 # sizeof(QtCbor::Element) == 16 element_value, _, element_flags = d.split('qII', element_at_n_addr) enc = 'latin1' if is_bytes or (element_flags & 8) else 'utf16' bytedata, _, _ = d.qArrayData(data_pos) bytedata += element_value - if d.qtVersion() >= 0x060000: + if d.qtVersionAtLeast(0x060000): bytedata_len = d.extractInt64(bytedata) bytedata_data = bytedata + 8 else: @@ -3493,8 +3495,8 @@ def qdumpHelper_QCbor_array(d, container_ptr, is_cbor): return # d.split('i@{@QByteArray::size_type}pp', container_ptr) doesn't work with CDB, # so be explicit: - data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersion() >= 0x060000 else 8) - elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersion() >= 0x060000 else d.ptrSize()) + data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else 8) + elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else d.ptrSize()) elements_data_ptr, elements_size = d.vectorData(elements_pos) d.putItemCount(elements_size) if d.isExpanded(): @@ -3515,8 +3517,8 @@ def qdumpHelper_QCbor_map(d, container_ptr, is_cbor): return # d.split('i@{@QByteArray::size_type}pp', container_ptr) doesn't work with CDB, # so be explicit: - data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersion() >= 0x060000 else 8) - elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersion() >= 0x060000 else d.ptrSize()) + data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else 8) + elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else d.ptrSize()) elements_data_ptr, elements_size = d.vectorData(elements_pos) elements_size = int(elements_size / 2) d.putItemCount(elements_size) diff --git a/src/libs/extensionsystem/pluginspec.cpp b/src/libs/extensionsystem/pluginspec.cpp index 18c8d11e78f..f7d72b80420 100644 --- a/src/libs/extensionsystem/pluginspec.cpp +++ b/src/libs/extensionsystem/pluginspec.cpp @@ -844,11 +844,9 @@ Utils::expected_str PluginSpecPrivate::readMetaData(const QJsonObject &dat value = metaData.value(QLatin1String(PLUGIN_DISABLED_BY_DEFAULT)); if (!value.isUndefined() && !value.isBool()) return reportError(msgValueIsNotABool(PLUGIN_DISABLED_BY_DEFAULT)); - enabledByDefault = !value.toBool(false); + enabledByDefault = !value.toBool(experimental || deprecated); qCDebug(pluginLog) << "enabledByDefault =" << enabledByDefault; - if (experimental || deprecated) - enabledByDefault = false; enabledBySettings = enabledByDefault; value = metaData.value(QLatin1String(PLUGIN_SOFTLOADABLE)); diff --git a/src/libs/languageserverprotocol/languagefeatures.cpp b/src/libs/languageserverprotocol/languagefeatures.cpp index 30e2b6bd84a..0c76a3b1c03 100644 --- a/src/libs/languageserverprotocol/languagefeatures.cpp +++ b/src/libs/languageserverprotocol/languagefeatures.cpp @@ -261,6 +261,12 @@ DocumentHighlightsResult::DocumentHighlightsResult(const QJsonValue &value) } } +template<> +MarkedString fromJsonValue(const QJsonValue &value) +{ + return MarkedString(value); +} + MarkedString::MarkedString(const QJsonValue &value) { if (value.isObject()) diff --git a/src/libs/languageserverprotocol/languagefeatures.h b/src/libs/languageserverprotocol/languagefeatures.h index e5ca9df31d6..6a60ec3612f 100644 --- a/src/libs/languageserverprotocol/languagefeatures.h +++ b/src/libs/languageserverprotocol/languagefeatures.h @@ -52,6 +52,9 @@ public: operator QJsonValue() const; }; +template<> +LANGUAGESERVERPROTOCOL_EXPORT MarkedString fromJsonValue(const QJsonValue &value); + class LANGUAGESERVERPROTOCOL_EXPORT HoverContent : public std::variant, MarkupContent> { diff --git a/src/libs/languageserverprotocol/lsputils.h b/src/libs/languageserverprotocol/lsputils.h index 32e2bfa6b7e..a5178f813fd 100644 --- a/src/libs/languageserverprotocol/lsputils.h +++ b/src/libs/languageserverprotocol/lsputils.h @@ -68,7 +68,7 @@ public: if (value.isArray()) { QList values; values.reserve(value.toArray().count()); - for (auto arrayValue : value.toArray()) + for (const auto &arrayValue : value.toArray()) values << fromJsonValue(arrayValue); *this = values; } else { diff --git a/src/libs/solutions/tasking/barrier.cpp b/src/libs/solutions/tasking/barrier.cpp index 650aae3403b..126d4f3b8a5 100644 --- a/src/libs/solutions/tasking/barrier.cpp +++ b/src/libs/solutions/tasking/barrier.cpp @@ -24,7 +24,7 @@ void Barrier::start() { QT_ASSERT(!isRunning(), return); m_current = 0; - m_result = {}; + m_result.reset(); } void Barrier::advance() diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 2c7a5a8dedb..d923eb31d0e 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1450,6 +1450,11 @@ ExecutableItem ExecutableItem::withTimeout(milliseconds timeout, static QString currentTime() { return QTime::currentTime().toString(Qt::ISODateWithMs); } +static QString logHeader(const QString &logName) +{ + return QString::fromLatin1("TASK TREE LOG [%1] \"%2\"").arg(currentTime(), logName); +}; + /*! Attaches a custom debug printout to a copy of \c this ExecutableItem, issued on task startup and after the task is finished, and returns the coupled item. @@ -1463,9 +1468,6 @@ static QString currentTime() { return QTime::currentTime().toString(Qt::ISODateW */ ExecutableItem ExecutableItem::withLog(const QString &logName) const { - const auto header = [logName] { - return QString::fromLatin1("TASK TREE LOG [%1] \"%2\"").arg(currentTime(), logName); - }; struct LogStorage { time_point start; @@ -1474,21 +1476,22 @@ ExecutableItem ExecutableItem::withLog(const QString &logName) const const Storage storage; return Group { storage, - onGroupSetup([storage, header] { + onGroupSetup([storage, logName] { storage->start = system_clock::now(); storage->asyncCount = activeTaskTree()->asyncCount(); - qDebug().noquote() << header() << "started."; + qDebug().noquote().nospace() << logHeader(logName) << " started."; }), *this, - onGroupDone([storage, header](DoneWith result) { + onGroupDone([storage, logName](DoneWith result) { const auto elapsed = duration_cast(system_clock::now() - storage->start); const int asyncCountDiff = activeTaskTree()->asyncCount() - storage->asyncCount; QT_CHECK(asyncCountDiff >= 0); const QMetaEnum doneWithEnum = QMetaEnum::fromType(); const QString syncType = asyncCountDiff ? QString::fromLatin1("asynchronously") : QString::fromLatin1("synchronously"); - qDebug().noquote().nospace() << header() << " finished " << syncType << " with " - << doneWithEnum.valueToKey(int(result)) << " within " << elapsed.count() << "ms."; + qDebug().noquote().nospace() << logHeader(logName) << " finished " << syncType + << " with " << doneWithEnum.valueToKey(int(result)) + << " within " << elapsed.count() << "ms."; }) }; } @@ -3383,7 +3386,7 @@ TimeoutTaskAdapter::~TimeoutTaskAdapter() void TimeoutTaskAdapter::start() { m_timerId = scheduleTimeout(*task(), this, [this] { - m_timerId = {}; + m_timerId.reset(); emit done(DoneResult::Success); }); } diff --git a/src/libs/utils/codegeneration.cpp b/src/libs/utils/codegeneration.cpp index 8842023a239..ad3b8bad18f 100644 --- a/src/libs/utils/codegeneration.cpp +++ b/src/libs/utils/codegeneration.cpp @@ -29,23 +29,6 @@ QTCREATOR_UTILS_EXPORT QString fileNameToCppIdentifier(const QString &s) return rc; } -QTCREATOR_UTILS_EXPORT QString headerGuard(const QString &file) -{ - return headerGuard(file, QStringList()); -} - -QTCREATOR_UTILS_EXPORT QString headerGuard(const QString &file, const QStringList &namespaceList) -{ - const QChar underscore = QLatin1Char('_'); - QString rc; - for (int i = 0; i < namespaceList.count(); i++) - rc += namespaceList.at(i).toUpper() + underscore; - - const QFileInfo fi(file); - rc += fileNameToCppIdentifier(fi.fileName()).toUpper(); - return rc; -} - QTCREATOR_UTILS_EXPORT void writeIncludeFileDirective(const QString &file, bool globalInclude, QTextStream &str) diff --git a/src/libs/utils/codegeneration.h b/src/libs/utils/codegeneration.h index 9ea0bb28c7e..e1c297eb92c 100644 --- a/src/libs/utils/codegeneration.h +++ b/src/libs/utils/codegeneration.h @@ -17,9 +17,6 @@ namespace Utils { // or replacing them by an underscore). QTCREATOR_UTILS_EXPORT QString fileNameToCppIdentifier(const QString &s); -QTCREATOR_UTILS_EXPORT QString headerGuard(const QString &file); -QTCREATOR_UTILS_EXPORT QString headerGuard(const QString &file, const QStringList &namespaceList); - QTCREATOR_UTILS_EXPORT void writeIncludeFileDirective(const QString &file, bool globalInclude, diff --git a/src/plugins/appstatisticsmonitor/AppStatisticsMonitor.json.in b/src/plugins/appstatisticsmonitor/AppStatisticsMonitor.json.in index 920b3ec31bb..757acf5052f 100644 --- a/src/plugins/appstatisticsmonitor/AppStatisticsMonitor.json.in +++ b/src/plugins/appstatisticsmonitor/AppStatisticsMonitor.json.in @@ -3,6 +3,7 @@ "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", "Experimental" : true, + "DisabledByDefault" : ${APPSTATISTICSMONITOR_DISABLEDBYDEFAULT}, "Vendor" : "The Qt Company Ltd", "Copyright" : "(C) ${IDE_COPYRIGHT_YEAR} The Qt Company Ltd", "License" : [ "Commercial Usage", diff --git a/src/plugins/appstatisticsmonitor/CMakeLists.txt b/src/plugins/appstatisticsmonitor/CMakeLists.txt index 92ae05962c9..1e00a0afab3 100644 --- a/src/plugins/appstatisticsmonitor/CMakeLists.txt +++ b/src/plugins/appstatisticsmonitor/CMakeLists.txt @@ -13,6 +13,8 @@ set(CMAKE_CXX_EXTENSIONS OFF) find_package(Qt6 COMPONENTS Charts QUIET) +set(APPSTATISTICSMONITOR_DISABLEDBYDEFAULT "true") + if (NOT QT_CREATOR_API_DEFINED) # standalone build set(DESTINATION DESTINATION .) @@ -21,6 +23,8 @@ if (NOT QT_CREATOR_API_DEFINED) qtc_handle_compiler_cache_support() find_package(QtCreator COMPONENTS Core ProjectExplorer Utils REQUIRED) + + set(APPSTATISTICSMONITOR_DISABLEDBYDEFAULT "false") endif() diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 80dd5103c14..644db7f5433 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -51,6 +51,8 @@ using namespace Utils; namespace Axivion::Internal { +void showIssuesFromDashboard(const QString &kind); // impl at bottom + class DashboardWidget : public QScrollArea { public: @@ -147,14 +149,24 @@ void DashboardWidget::updateUi() } return prefix; }; - auto addValuesWidgets = [this, &toolTip](const QString &issueKind, qint64 total, qint64 added, qint64 removed, int row) { + auto linked = [](const QString &text, const QString &href, bool link) { + return link ? QString("%2").arg(href).arg(text) + : text; + }; + auto addValuesWidgets = [this, &toolTip, &linked](const QString &issueKind, qint64 total, + qint64 added, qint64 removed, int row, bool link) { const QString currentToolTip = toolTip(issueKind); QLabel *label = new QLabel(issueKind, this); label->setToolTip(currentToolTip); m_gridLayout->addWidget(label, row, 0); - label = new QLabel(QString::number(total), this); + label = new QLabel(linked(QString::number(total), issueKind, link), this); label->setToolTip(currentToolTip); label->setAlignment(Qt::AlignRight); + if (link) { + connect(label, &QLabel::linkActivated, this, [](const QString &issueKind) { + showIssuesFromDashboard(issueKind); + }); + } m_gridLayout->addWidget(label, row, 1); label = new QLabel(this); label->setPixmap(trendIcon(added, removed)); @@ -190,12 +202,12 @@ void DashboardWidget::updateUi() allAdded += added; qint64 removed = extract_value(counts, QStringLiteral("Removed")); allRemoved += removed; - addValuesWidgets(issueCount.first, total, added, removed, row); + addValuesWidgets(issueCount.first, total, added, removed, row, true); ++row; } } } - addValuesWidgets(Tr::tr("Total:"), allTotal, allAdded, allRemoved, row); + addValuesWidgets(Tr::tr("Total:"), allTotal, allAdded, allRemoved, row, false); } struct LinkWithColumns @@ -263,7 +275,7 @@ class IssuesWidget : public QScrollArea { public: explicit IssuesWidget(QWidget *parent = nullptr); - void updateUi(); + void updateUi(const QString &kind); const std::optional currentTableInfo() const { return m_currentTableInfo; } IssueListSearch searchFromUi() const; @@ -378,7 +390,7 @@ IssuesWidget::IssuesWidget(QWidget *parent) setWidgetResizable(true); } -void IssuesWidget::updateUi() +void IssuesWidget::updateUi(const QString &kind) { setFiltersEnabled(false); const std::optional projectInfo = Internal::projectInfo(); @@ -392,11 +404,30 @@ void IssuesWidget::updateUi() setFiltersEnabled(true); // avoid refetching existing data - if (!m_currentPrefix.isEmpty() || m_issuesModel->rowCount()) + if (kind.isEmpty() && (!m_currentPrefix.isEmpty() || m_issuesModel->rowCount())) return; - if (info.issueKinds.size()) - m_currentPrefix = info.issueKinds.front().prefix; + if (!kind.isEmpty()) { + const int index + = Utils::indexOf( info.issueKinds, [kind](const Dto::IssueKindInfoDto &dto) { + return dto.prefix == kind; }); + if (index != -1) { + m_currentPrefix = kind; + auto kindButton = m_typesButtonGroup->button(index + 1); + if (QTC_GUARD(kindButton)) + kindButton->setChecked(true); + // reset filters - if kind is not empty we get triggered from dashboard overview + if (!m_userNames.isEmpty()) + m_ownerFilter->setCurrentIndex(0); + m_pathGlobFilter->clear(); + if (m_versionDates.size() > 1) { + m_versionStart->setCurrentIndex(m_versionDates.count() - 1); + m_versionEnd->setCurrentIndex(0); + } + } + } + if (m_currentPrefix.isEmpty()) + m_currentPrefix = info.issueKinds.size() ? info.issueKinds.front().prefix : QString{}; fetchTable(); } @@ -767,12 +798,7 @@ public: m_showIssues->setIcon(Icons::ZOOM_TOOLBAR.icon()); m_showIssues->setToolTip(Tr::tr("Search for issues")); m_showIssues->setCheckable(true); - connect(m_showIssues, &QToolButton::clicked, this, [this] { - QTC_ASSERT(m_outputWidget, return); - m_outputWidget->setCurrentIndex(1); - if (auto issues = static_cast(m_outputWidget->widget(1))) - issues->updateUi(); - }); + connect(m_showIssues, &QToolButton::clicked, this, [this] { handleShowIssues({}); }); auto *butonGroup = new QButtonGroup(this); butonGroup->addButton(m_showDashboard); butonGroup->addButton(m_showIssues); @@ -814,6 +840,14 @@ public: void goToNext() final {} void goToPrev() final {} + void handleShowIssues(const QString &kind) + { + QTC_ASSERT(m_outputWidget, return); + m_outputWidget->setCurrentIndex(1); + if (auto issues = static_cast(m_outputWidget->widget(1))) + issues->updateUi(kind); + } + void updateDashboard() { if (auto dashboard = static_cast(m_outputWidget->widget(0))) { @@ -897,4 +931,10 @@ static bool issueListContextMenuEvent(const ItemViewEvent &ev) return theAxivionOutputPane->handleContextMenu(issue, ev); } +void showIssuesFromDashboard(const QString &kind) +{ + QTC_ASSERT(theAxivionOutputPane, return); + theAxivionOutputPane->handleShowIssues(kind); +} + } // Axivion::Internal diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index 21b5ea6fbdc..20ba1328cb5 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -474,11 +474,10 @@ ClangTool::ClangTool(const QString &name, Id id, ClangToolType type) // Expand/Collapse action = new QAction(this); - action->setDisabled(true); action->setCheckable(true); action->setIcon(Utils::Icons::EXPAND_ALL_TOOLBAR.icon()); - action->setToolTip(Tr::tr("Expand All")); - connect(action, &QAction::toggled, this, [this](bool checked){ + m_expandCollapse = action; + const auto handleCollapseExpandToggled = [this](bool checked){ if (checked) { m_expandCollapse->setToolTip(Tr::tr("Collapse All")); m_diagnosticView->expandAll(); @@ -486,8 +485,9 @@ ClangTool::ClangTool(const QString &name, Id id, ClangToolType type) m_expandCollapse->setToolTip(Tr::tr("Expand All")); m_diagnosticView->collapseAll(); } - }); - m_expandCollapse = action; + }; + connect(action, &QAction::toggled, this, handleCollapseExpandToggled); + handleCollapseExpandToggled(action->isChecked()); // Filter button action = m_showFilter = new QAction(this); @@ -1242,8 +1242,32 @@ QSet ClangTool::diagnostics() const void ClangTool::onNewDiagnosticsAvailable(const Diagnostics &diagnostics, bool generateMarks) { - QTC_ASSERT(m_diagnosticModel, return); + const int oldLevel1RowCount = m_diagnosticModel->rowCount(); + const auto getOldLastLevel1Index = [&] { + return m_diagnosticModel->index(oldLevel1RowCount - 1, 0); + }; + const auto getLevel2RowCountForOldLastLevel1Index = [&] { + return oldLevel1RowCount == 0 ? -1 : m_diagnosticModel->rowCount(getOldLastLevel1Index()); + }; + const int oldLevel2RowCount = getLevel2RowCountForOldLastLevel1Index(); m_diagnosticModel->addDiagnostics(diagnostics, generateMarks); + if (!m_expandCollapse->isChecked()) + return; + + // Now expand newly added items, both in existing file nodes and in newly added ones. + // We assume diagnostics arrive "in order", i.e. things are only ever added at the end + // (in the source model). + const int newLevel2RowCount = getLevel2RowCountForOldLastLevel1Index(); + for (int i = oldLevel2RowCount; i < newLevel2RowCount; ++i) { + m_diagnosticView->expand(m_diagnosticFilterModel->mapFromSource( + m_diagnosticModel + ->index(i, 0, m_diagnosticFilterModel->mapFromSource(getOldLastLevel1Index())))); + } + const int newLevel1RowCount = m_diagnosticFilterModel->rowCount(); + for (int i = oldLevel1RowCount; i < newLevel1RowCount; ++i) { + m_diagnosticView->expandRecursively( + m_diagnosticFilterModel->mapFromSource(m_diagnosticModel->index(i, 0))); + } } void ClangTool::updateForCurrentState() @@ -1273,7 +1297,6 @@ void ClangTool::updateForCurrentState() m_goBack->setEnabled(issuesVisible > 0); m_goNext->setEnabled(issuesVisible > 0); m_clear->setEnabled(!isRunning); - m_expandCollapse->setEnabled(issuesVisible); m_loadExported->setEnabled(!isRunning); m_showFilter->setEnabled(issuesFound > 1); diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp index c91d9e9cfa7..08858a0498e 100644 --- a/src/plugins/clangtools/clangtoolrunner.cpp +++ b/src/plugins/clangtools/clangtoolrunner.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 696ce44c1e2..fed2112822e 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -1184,30 +1183,6 @@ static CommandLine defaultInitialCMakeCommand( } } - // GCC compiler and linker specific flags - for (Toolchain *tc : ToolchainKitAspect::toolChains(k)) { - if (auto *gccTc = tc->asGccToolchain()) { - const QStringList compilerFlags = gccTc->platformCodeGenFlags(); - - QLatin1String languageFlagsInit; - if (gccTc->language() == ProjectExplorer::Constants::C_LANGUAGE_ID) - languageFlagsInit = QLatin1String(CMAKE_C_FLAGS_INIT); - else if (gccTc->language() == ProjectExplorer::Constants::CXX_LANGUAGE_ID) - languageFlagsInit = QLatin1String(CMAKE_CXX_FLAGS_INIT); - - if (!languageFlagsInit.isEmpty() && !compilerFlags.isEmpty()) - cmd.addArg("-D" + languageFlagsInit + ":STRING=" + compilerFlags.join(" ")); - - const QStringList linkerFlags = gccTc->platformLinkerFlags(); - if (!linkerFlags.isEmpty()) { - const QString joinedLinkerFlags = linkerFlags.join(" "); - cmd.addArg("-DCMAKE_EXE_LINKER_FLAGS_INIT:STRING=" + joinedLinkerFlags); - cmd.addArg("-DCMAKE_MODULE_LINKER_FLAGS_INIT:STRING=" + joinedLinkerFlags); - cmd.addArg("-DCMAKE_SHARED_LINKER_FLAGS_INIT:STRING=" + joinedLinkerFlags); - } - } - } - cmd.addArgs(CMakeConfigurationKitAspect::toArgumentsList(k)); cmd.addArgs(CMakeConfigurationKitAspect::additionalConfiguration(k), CommandLine::Raw); @@ -1356,7 +1331,7 @@ static void addCMakeConfigurePresetToInitialArguments(QStringList &initialArgume if (argFilePath != presetFilePath) arg = presetItem.toArgument(); - } else if (argItem.key == CMAKE_CXX_FLAGS_INIT) { + } else if (argItem.key == CMAKE_C_FLAGS_INIT || argItem.key == CMAKE_CXX_FLAGS_INIT) { // Append the preset value with at the initial parameters value (e.g. QML Debugging) if (argItem.expandedValue(k) != QString::fromUtf8(presetItem.value)) { argItem.value.append(" "); diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index 63122a538b3..bd8d7331711 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -227,7 +227,7 @@ void CppEditorPlugin::initialize() void CppEditorPlugin::extensionsInitialized() { setupCppQuickFixProjectPanel(); - setupCppFileSettings(); + setupCppFileSettings(*this); setupCppCodeModelProjectSettingsPanel(); if (CppModelManager::isClangCodeModelActive()) { diff --git a/src/plugins/cppeditor/cppfilesettingspage.cpp b/src/plugins/cppeditor/cppfilesettingspage.cpp index 3579e0b5f21..a5c01b400b1 100644 --- a/src/plugins/cppeditor/cppfilesettingspage.cpp +++ b/src/plugins/cppeditor/cppfilesettingspage.cpp @@ -6,15 +6,19 @@ #include "cppeditortr.h" #include "cppheadersource.h" +#include + #include #include #include #include +#include #include #include #include +#include #include #include #include @@ -29,10 +33,30 @@ #include #include +#ifdef WITH_TESTS +#include +#endif + using namespace ProjectExplorer; using namespace Utils; namespace CppEditor::Internal { +namespace { +class HeaderGuardExpander : public MacroExpander +{ +public: + HeaderGuardExpander(const FilePath &filePath) : m_filePath(filePath) + { + setDisplayName(Tr::tr("Header file variables")); + registerFileVariables("Header", Tr::tr("Header file"), [this] { + return m_filePath; + }); + } + +private: + const FilePath m_filePath; +}; +} // namespace const char projectSettingsKeyC[] = "CppEditorFileNames"; const char useGlobalKeyC[] = "UseGlobal"; @@ -44,6 +68,7 @@ const char headerSearchPathsKeyC[] = "HeaderSearchPaths"; const char sourceSearchPathsKeyC[] = "SourceSearchPaths"; const char headerPragmaOnceC[] = "HeaderPragmaOnce"; const char licenseTemplatePathKeyC[] = "LicenseTemplate"; +const char headerGuardTemplateKeyC[] = "HeaderGuardTemplate"; const char *licenseTemplateTemplate = QT_TRANSLATE_NOOP("QtC::CppEditor", "/**************************************************************************\n" @@ -67,6 +92,7 @@ void CppFileSettings::toSettings(QtcSettings *s) const s->setValueWithDefault(headerPragmaOnceC, headerPragmaOnce, def.headerPragmaOnce); s->setValueWithDefault(licenseTemplatePathKeyC, licenseTemplatePath.toSettings(), def.licenseTemplatePath.toSettings()); + s->setValueWithDefault(headerGuardTemplateKeyC, headerGuardTemplate, def.headerGuardTemplate); s->endGroup(); } @@ -84,6 +110,7 @@ void CppFileSettings::fromSettings(QtcSettings *s) headerPragmaOnce = s->value(headerPragmaOnceC, def.headerPragmaOnce).toBool(); licenseTemplatePath = FilePath::fromSettings(s->value(licenseTemplatePathKeyC, def.licenseTemplatePath.toSettings())); + headerGuardTemplate = s->value(headerGuardTemplateKeyC, def.headerGuardTemplate).toString(); s->endGroup(); } @@ -124,6 +151,7 @@ bool CppFileSettings::equals(const CppFileSettings &rhs) const && sourceSuffix == rhs.sourceSuffix && headerSearchPaths == rhs.headerSearchPaths && sourceSearchPaths == rhs.sourceSearchPaths + && headerGuardTemplate == rhs.headerGuardTemplate && licenseTemplatePath == rhs.licenseTemplatePath; } @@ -237,6 +265,11 @@ QString CppFileSettings::licenseTemplate() const return license; } +QString CppFileSettings::headerGuard(const Utils::FilePath &headerFilePath) const +{ + return HeaderGuardExpander(headerFilePath).expand(headerGuardTemplate); +} + // ------------------ CppFileSettingsWidget class CppFileSettingsWidget final : public Core::IOptionsPageWidget @@ -269,6 +302,8 @@ private: QLineEdit *m_sourcePrefixesEdit = nullptr; QCheckBox *m_lowerCaseFileNamesCheckBox = nullptr; PathChooser *m_licenseTemplatePathChooser = nullptr; + StringAspect m_headerGuardAspect; + HeaderGuardExpander m_headerGuardExpander{{}}; }; CppFileSettingsWidget::CppFileSettingsWidget(CppFileSettings *settings) @@ -276,7 +311,7 @@ CppFileSettingsWidget::CppFileSettingsWidget(CppFileSettings *settings) , m_headerSuffixComboBox(new QComboBox) , m_headerSearchPathsEdit(new QLineEdit) , m_headerPrefixesEdit(new QLineEdit) - , m_headerPragmaOnceCheckBox(new QCheckBox(Tr::tr("Use \"#pragma once\" instead of \"#ifndef\" guards"))) + , m_headerPragmaOnceCheckBox(new QCheckBox(Tr::tr("Use \"#pragma once\" instead"))) , m_sourceSuffixComboBox(new QComboBox) , m_sourceSearchPathsEdit(new QLineEdit) , m_sourcePrefixesEdit(new QLineEdit) @@ -301,6 +336,8 @@ CppFileSettingsWidget::CppFileSettingsWidget(CppFileSettings *settings) m_sourcePrefixesEdit->setToolTip(Tr::tr("Comma-separated list of source prefixes.\n" "\n" "These prefixes are used in addition to current file name on Switch Header/Source.")); + m_headerGuardAspect.setDisplayStyle(Utils::StringAspect::LineEditDisplay); + m_headerGuardAspect.setMacroExpander(&m_headerGuardExpander); using namespace Layouting; @@ -311,8 +348,8 @@ CppFileSettingsWidget::CppFileSettingsWidget(CppFileSettings *settings) Tr::tr("&Suffix:"), m_headerSuffixComboBox, st, br, Tr::tr("S&earch paths:"), m_headerSearchPathsEdit, br, Tr::tr("&Prefixes:"), m_headerPrefixesEdit, br, - Tr::tr("Include guards"), m_headerPragmaOnceCheckBox - } + Tr::tr("Include guard template:"), m_headerPragmaOnceCheckBox, m_headerGuardAspect + }, }, Group { title(Tr::tr("Sources")), @@ -361,12 +398,21 @@ CppFileSettingsWidget::CppFileSettingsWidget(CppFileSettings *settings) this, &CppFileSettingsWidget::userChange); connect(m_sourcePrefixesEdit, &QLineEdit::textEdited, this, &CppFileSettingsWidget::userChange); - connect(m_headerPragmaOnceCheckBox, &QCheckBox::stateChanged, - this, &CppFileSettingsWidget::userChange); connect(m_lowerCaseFileNamesCheckBox, &QCheckBox::stateChanged, this, &CppFileSettingsWidget::userChange); connect(m_licenseTemplatePathChooser, &PathChooser::textChanged, this, &CppFileSettingsWidget::userChange); + const auto updateHeaderGuardAspectState = [this] { + m_headerGuardAspect.setEnabled(!m_headerPragmaOnceCheckBox->isChecked()); + }; + connect(m_headerPragmaOnceCheckBox, &QCheckBox::stateChanged, + this, [this, updateHeaderGuardAspectState] { + updateHeaderGuardAspectState(); + emit userChange(); + }); + connect(&m_headerGuardAspect, &StringAspect::changed, + this, &CppFileSettingsWidget::userChange); + updateHeaderGuardAspectState(); } FilePath CppFileSettingsWidget::licenseTemplatePath() const @@ -417,6 +463,7 @@ void CppFileSettingsWidget::setSettings(const CppFileSettings &s) m_headerSearchPathsEdit->setText(s.headerSearchPaths.join(comma)); m_sourceSearchPathsEdit->setText(s.sourceSearchPaths.join(comma)); setLicenseTemplatePath(s.licenseTemplatePath); + m_headerGuardAspect.setValue(s.headerGuardTemplate); } CppFileSettings CppFileSettingsWidget::currentSettings() const @@ -431,6 +478,7 @@ CppFileSettings CppFileSettingsWidget::currentSettings() const rc.headerSearchPaths = trimmedPaths(m_headerSearchPathsEdit->text()); rc.sourceSearchPaths = trimmedPaths(m_sourceSearchPathsEdit->text()); rc.licenseTemplatePath = licenseTemplatePath(); + rc.headerGuardTemplate = m_headerGuardAspect.value(); return rc; } @@ -536,6 +584,8 @@ void CppFileSettingsForProject::loadSettings() m_customSettings.lowerCaseFiles).toBool(); m_customSettings.headerPragmaOnce = data.value(headerPragmaOnceC, m_customSettings.headerPragmaOnce).toBool(); + m_customSettings.headerGuardTemplate + = data.value(headerGuardTemplateKeyC, m_customSettings.headerGuardTemplate).toString(); m_customSettings.licenseTemplatePath = FilePath::fromSettings(data.value(licenseTemplatePathKeyC, m_customSettings.licenseTemplatePath.toSettings())); @@ -560,6 +610,7 @@ void CppFileSettingsForProject::saveSettings() data.insert(sourceSearchPathsKeyC, m_customSettings.sourceSearchPaths); data.insert(Constants::LOWERCASE_CPPFILES_KEY, m_customSettings.lowerCaseFiles); data.insert(headerPragmaOnceC, m_customSettings.headerPragmaOnce); + data.insert(headerGuardTemplateKeyC, m_customSettings.headerGuardTemplate); data.insert(licenseTemplatePathKeyC, m_customSettings.licenseTemplatePath.toSettings()); m_project->setNamedSettings(projectSettingsKeyC, data); } @@ -631,16 +682,6 @@ public: } }; -void setupCppFileSettings() -{ - static CppFileSettingsProjectPanelFactory theCppFileSettingsProjectPanelFactory; - - static CppFileSettingsPage theCppFileSettingsPage; - - globalCppFileSettings().fromSettings(Core::ICore::settings()); - globalCppFileSettings().addMimeInitializer(); -} - CppFileSettings &globalCppFileSettings() { // This is the global instance. There could be more. @@ -653,6 +694,59 @@ CppFileSettings cppFileSettingsForProject(ProjectExplorer::Project *project) return CppFileSettingsForProject(project).settings(); } +#ifdef WITH_TESTS +namespace { +class CppFileSettingsTest : public QObject +{ + Q_OBJECT + +private slots: + void testHeaderGuard_data() + { + QTest::addColumn("guardTemplate"); + QTest::addColumn("headerFile"); + QTest::addColumn("expectedGuard"); + + QTest::newRow("default template, .h") + << QString() << QString("/tmp/header.h") << QString("HEADER_H"); + QTest::newRow("default template, .hpp") + << QString() << QString("/tmp/header.hpp") << QString("HEADER_HPP"); + QTest::newRow("default template, two extensions") + << QString() << QString("/tmp/header.in.h") << QString("HEADER_IN_H"); + QTest::newRow("non-default template") + << QString("%{JS: '%{Header:FilePath}'.toUpperCase().replace(/[.]/, '_').replace(/[/]/g, '_')}") + << QString("/tmp/header.h") << QString("_TMP_HEADER_H"); + } + + void testHeaderGuard() + { + QFETCH(QString, guardTemplate); + QFETCH(QString, headerFile); + QFETCH(QString, expectedGuard); + + CppFileSettings settings; + if (!guardTemplate.isEmpty()) + settings.headerGuardTemplate = guardTemplate; + QCOMPARE(settings.headerGuard(FilePath::fromUserInput(headerFile)), expectedGuard); + } +}; +} // namespace +#endif // WITH_TESTS + +void setupCppFileSettings(ExtensionSystem::IPlugin &plugin) +{ + static CppFileSettingsProjectPanelFactory theCppFileSettingsProjectPanelFactory; + + static CppFileSettingsPage theCppFileSettingsPage; + + globalCppFileSettings().fromSettings(Core::ICore::settings()); + globalCppFileSettings().addMimeInitializer(); + +#ifdef WITH_TESTS + plugin.addTestCreator([] { return new CppFileSettingsTest; }); +#endif +} + } // namespace CppEditor::Internal #include diff --git a/src/plugins/cppeditor/cppfilesettingspage.h b/src/plugins/cppeditor/cppfilesettingspage.h index 5915b5383cf..044ac6fb450 100644 --- a/src/plugins/cppeditor/cppfilesettingspage.h +++ b/src/plugins/cppeditor/cppfilesettingspage.h @@ -9,6 +9,7 @@ #include +namespace ExtensionSystem { class IPlugin; } namespace ProjectExplorer { class Project; } namespace CppEditor::Internal { @@ -28,6 +29,7 @@ public: QDir::toNativeSeparators("../Src"), ".."}; Utils::FilePath licenseTemplatePath; + QString headerGuardTemplate = "%{JS: '%{Header:FileName}'.toUpperCase().replace(/[.]/g, '_')}"; bool headerPragmaOnce = false; bool lowerCaseFiles = Constants::LOWERCASE_CPPFILES_DEFAULT; @@ -39,6 +41,9 @@ public: // Convenience to return a license template completely formatted. QString licenseTemplate() const; + // Expanded headerGuardTemplate. + QString headerGuard(const Utils::FilePath &headerFilePath) const; + bool equals(const CppFileSettings &rhs) const; bool operator==(const CppFileSettings &s) const { return equals(s); } bool operator!=(const CppFileSettings &s) const { return !equals(s); } @@ -48,6 +53,6 @@ CppFileSettings &globalCppFileSettings(); CppFileSettings cppFileSettingsForProject(ProjectExplorer::Project *project); -void setupCppFileSettings(); +void setupCppFileSettings(ExtensionSystem::IPlugin &plugin); } // namespace CppEditor::Internal diff --git a/src/plugins/cppeditor/cpptoolsjsextension.cpp b/src/plugins/cppeditor/cpptoolsjsextension.cpp index c03a38ede2b..c3ed6e6286e 100644 --- a/src/plugins/cppeditor/cpptoolsjsextension.cpp +++ b/src/plugins/cppeditor/cpptoolsjsextension.cpp @@ -42,7 +42,7 @@ static QString fileName(const QString &path, const QString &extension) QString CppToolsJsExtension::headerGuard(const QString &in) const { - return Utils::headerGuard(in); + return fileSettings().headerGuard(Utils::FilePath::fromString(in)); } QString CppToolsJsExtension::licenseTemplate() const diff --git a/src/plugins/cppeditor/cpptoolsreuse.cpp b/src/plugins/cppeditor/cpptoolsreuse.cpp index 6e0802b4bbe..7be177c2c1b 100644 --- a/src/plugins/cppeditor/cpptoolsreuse.cpp +++ b/src/plugins/cppeditor/cpptoolsreuse.cpp @@ -358,6 +358,11 @@ CppCompletionAssistProcessor *getCppCompletionAssistProcessor() return new Internal::InternalCppCompletionAssistProcessor(); } +QString deriveHeaderGuard(const Utils::FilePath &filePath, ProjectExplorer::Project *project) +{ + return Internal::cppFileSettingsForProject(project).headerGuard(filePath); +} + bool fileSizeExceedsLimit(const FilePath &filePath, int sizeLimitInMb) { if (sizeLimitInMb <= 0) diff --git a/src/plugins/cppeditor/cpptoolsreuse.h b/src/plugins/cppeditor/cpptoolsreuse.h index 8b1da79113d..71aabab08df 100644 --- a/src/plugins/cppeditor/cpptoolsreuse.h +++ b/src/plugins/cppeditor/cpptoolsreuse.h @@ -6,7 +6,6 @@ #include "cppeditor_global.h" #include "clangdiagnosticconfig.h" -#include "compileroptionsbuilder.h" #include "projectpart.h" #include @@ -65,6 +64,9 @@ quickFixOperations(const TextEditor::AssistInterface *interface); CppCompletionAssistProcessor CPPEDITOR_EXPORT *getCppCompletionAssistProcessor(); +QString CPPEDITOR_EXPORT +deriveHeaderGuard(const Utils::FilePath &filePath, ProjectExplorer::Project *project); + enum class CacheUsage { ReadWrite, ReadOnly }; Utils::FilePath CPPEDITOR_EXPORT correspondingHeaderOrSource( diff --git a/src/plugins/cppeditor/quickfixes/moveclasstoownfile.cpp b/src/plugins/cppeditor/quickfixes/moveclasstoownfile.cpp index 4b83faaf2d4..ada2027971e 100644 --- a/src/plugins/cppeditor/quickfixes/moveclasstoownfile.cpp +++ b/src/plugins/cppeditor/quickfixes/moveclasstoownfile.cpp @@ -388,7 +388,7 @@ private: = Utils::transform(state->namespacePath, [&](const Namespace *ns) { return ov.prettyName(ns->name()); }); - const QString headerGuard = Utils::headerGuard(headerFileName); + const QString headerGuard = fileSettings.headerGuard(headerFilePath); if (fileSettings.headerPragmaOnce) { headerContent.append("#pragma once\n"); } else { diff --git a/src/plugins/debugger/console/console.cpp b/src/plugins/debugger/console/console.cpp index b1ee0dac83e..d7f3cb23343 100644 --- a/src/plugins/debugger/console/console.cpp +++ b/src/plugins/debugger/console/console.cpp @@ -27,6 +27,8 @@ const char SHOW_LOG[] = "showLog"; const char SHOW_WARNING[] = "showWarning"; const char SHOW_ERROR[] = "showError"; +using namespace Utils; + namespace Debugger::Internal { ///////////////////////////////////////////////////////////////////// @@ -90,8 +92,8 @@ Console::Console() m_showDebug.setLabelText(Tr::tr("Show debug, log, and info messages.")); m_showDebug.setToolTip(Tr::tr("Show debug, log, and info messages.")); m_showDebug.setValue(true); - m_showDebug.action()->setIcon(Utils::Icons::INFO_TOOLBAR.icon()); - connect(&m_showDebug, &Utils::BoolAspect::changed, + m_showDebug.setIcon(Icons::INFO_TOOLBAR.icon()); + connect(&m_showDebug, &BoolAspect::changed, proxyModel, [this, proxyModel] { proxyModel->setShowLogs(m_showDebug()); }); m_showDebugButton->setDefaultAction(m_showDebug.action()); @@ -102,8 +104,8 @@ Console::Console() m_showWarning.setLabelText(Tr::tr("Show warning messages.")); m_showWarning.setToolTip(Tr::tr("Show warning messages.")); m_showWarning.setValue(true); - m_showWarning.action()->setIcon(Utils::Icons::WARNING_TOOLBAR.icon()); - connect(m_showWarning.action(), &QAction::toggled, + m_showWarning.setIcon(Icons::WARNING_TOOLBAR.icon()); + connect(&m_showWarning, &BoolAspect::changed, proxyModel, [this, proxyModel] { proxyModel->setShowWarnings(m_showWarning()); }); m_showWarningButton->setDefaultAction(m_showWarning.action()); @@ -114,8 +116,8 @@ Console::Console() m_showError.setLabelText(Tr::tr("Show error messages.")); m_showError.setToolTip(Tr::tr("Show error messages.")); m_showError.setValue(true); - m_showError.action()->setIcon(Utils::Icons::CRITICAL_TOOLBAR.icon()); - connect(m_showError.action(), &QAction::toggled, + m_showError.setIcon(Icons::CRITICAL_TOOLBAR.icon()); + connect(&m_showError, &BoolAspect::changed, proxyModel, [this, proxyModel] { proxyModel->setShowErrors(m_showError()); }); m_showErrorButton->setDefaultAction(m_showError.action()); diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index b5e8a3cba8d..6b264911cc4 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -125,9 +125,6 @@ public: // Used by Valgrind QStringList expectedSignals; - // For QNX debugging - bool useCtrlCStub = false; - // Used by Android to avoid false positives on warnOnRelease bool skipExecutableValidation = false; bool useTargetAsync = false; diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp index c5b1bc7f6b6..dff784341a7 100644 --- a/src/plugins/debugger/debuggeritem.cpp +++ b/src/plugins/debugger/debuggeritem.cpp @@ -440,8 +440,11 @@ static DebuggerItem::MatchLevel matchSingle(const Abi &debuggerAbi, const Abi &t return matchOnMultiarch; } - if (debuggerAbi.wordWidth() == 64 && targetAbi.wordWidth() == 32) - return DebuggerItem::MatchesSomewhat; + if (debuggerAbi.wordWidth() == 64 && targetAbi.wordWidth() == 32) { + return HostOsInfo::isWindowsHost() && engineType == CdbEngineType + ? DebuggerItem::MatchesPerfectly + : DebuggerItem::MatchesSomewhat; + } if (debuggerAbi.wordWidth() != 0 && debuggerAbi.wordWidth() != targetAbi.wordWidth()) return matchOnMultiarch; diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index 4d9d663d0d0..23dcee4ee6a 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -783,6 +783,12 @@ void DebuggerItemModel::readDebuggers(const FilePath &fileName, bool isSystem) .arg(item.command().toUserOutput(), item.id().toString(), fileName.toUserOutput()); continue; } + if (item.engineType() == CdbEngineType + && Abi::abisOfBinary(item.command()).value(0).wordWidth() == 32) { + qWarning() << QString("32 bit CDB \"%1\" (%2) read from \"%3\" dropped since it is not supported anymore.") + .arg(item.command().toUserOutput(), item.id().toString(), fileName.toUserOutput()); + continue; + } // FIXME: During startup, devices are not yet available, so we cannot check if the file still exists. if (!item.command().needsDevice() && !item.command().isExecutableFile()) { qWarning() << QString("DebuggerItem \"%1\" (%2) read from \"%3\" dropped since the command is not executable.") diff --git a/src/plugins/debugger/debuggerkitaspect.cpp b/src/plugins/debugger/debuggerkitaspect.cpp index 10559a70840..15a3e8827c1 100644 --- a/src/plugins/debugger/debuggerkitaspect.cpp +++ b/src/plugins/debugger/debuggerkitaspect.cpp @@ -388,6 +388,15 @@ public: k->setValue(DebuggerKitAspect::id(), bestLevel != DebuggerItem::DoesNotMatch ? bestItem.id() : QVariant()); } + void fix(Kit *k) override + { + const QVariant id = k->value(DebuggerKitAspect::id()); + if (Utils::anyOf(DebuggerItemManager::debuggers(), Utils::equal(&DebuggerItem::id, id))) + return; + k->removeKeySilently(DebuggerKitAspect::id()); + setup(k); + } + KitAspect *createKitAspect(Kit *k) const override { return new Internal::DebuggerKitAspectImpl(k, this); diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 5688ff191ad..2f980f7fdc4 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -276,11 +276,6 @@ void DebuggerRunTool::setSkipExecutableValidation(bool on) m_runParameters.skipExecutableValidation = on; } -void DebuggerRunTool::setUseCtrlCStub(bool on) -{ - m_runParameters.useCtrlCStub = on; -} - void DebuggerRunTool::setBreakOnMain(bool on) { m_runParameters.breakOnMain = on; diff --git a/src/plugins/debugger/debuggerruncontrol.h b/src/plugins/debugger/debuggerruncontrol.h index 39fb7e9507f..bfd53299a1b 100644 --- a/src/plugins/debugger/debuggerruncontrol.h +++ b/src/plugins/debugger/debuggerruncontrol.h @@ -100,7 +100,6 @@ protected: void setRemoteChannel(const QUrl &url); void setUseTargetAsync(bool on); void setSkipExecutableValidation(bool on); - void setUseCtrlCStub(bool on); void setIosPlatform(const QString &platform); void setDeviceSymbolsRoot(const QString &deviceSymbolsRoot); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 1079fb24eaf..ab173cc0eab 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -124,6 +124,7 @@ const char notCompatibleMessage[] = "is not compatible with target architecture" GdbEngine::GdbEngine() { m_gdbProc.setProcessMode(ProcessMode::Writer); + m_gdbProc.setUseCtrlCStub(true); setObjectName("GdbEngine"); setDebuggerName("GDB"); @@ -673,26 +674,7 @@ void GdbEngine::interruptInferior() } else { showStatusMessage(Tr::tr("Stop requested..."), 5000); showMessage("TRYING TO INTERRUPT INFERIOR"); - if (HostOsInfo::isWindowsHost() && !m_isQnxGdb) { - IDevice::ConstPtr dev = device(); - QTC_ASSERT(dev, notifyInferiorStopFailed(); return); - DeviceProcessSignalOperation::Ptr signalOperation = dev->signalOperation(); - QTC_ASSERT(signalOperation, notifyInferiorStopFailed(); return); - connect(signalOperation.get(), &DeviceProcessSignalOperation::finished, - this, [this, signalOperation](const QString &error) { - if (error.isEmpty()) { - showMessage("Interrupted " + QString::number(inferiorPid())); - notifyInferiorStopOk(); - } else { - showMessage(error, LogError); - notifyInferiorStopFailed(); - } - }); - signalOperation->setDebuggerCommand(runParameters().debugger.command.executable()); - signalOperation->interruptProcess(inferiorPid()); - } else { - interruptInferior2(); - } + interruptInferior2(); } } @@ -1265,9 +1247,11 @@ void GdbEngine::handleStopResponse(const GdbMi &data) handleStop1(data); } -static QString stopSignal(const Abi &abi) +static QStringList stopSignals(const Abi &abi) { - return QLatin1String(abi.os() == Abi::WindowsOS ? "SIGTRAP" : "SIGINT"); + static QStringList winSignals = { "SIGTRAP", "SIGINT" }; + static QStringList unixSignals = { "SIGINT" }; + return abi.os() == Abi::WindowsOS ? winSignals : unixSignals; } void GdbEngine::handleStop1(const GdbMi &data) @@ -1416,7 +1400,7 @@ void GdbEngine::handleStop2(const GdbMi &data) QString meaning = data["signal-meaning"].data(); // Ignore these as they are showing up regularly when // stopping debugging. - if (name == stopSignal(rp.toolChainAbi) || rp.expectedSignals.contains(name)) { + if (stopSignals(rp.toolChainAbi).contains(name) || rp.expectedSignals.contains(name)) { showMessage(name + " CONSIDERED HARMLESS. CONTINUING."); } else if (m_isQnxGdb && name == "0" && meaning == "Signal 0") { showMessage("SIGNAL 0 CONSIDERED BOGUS."); @@ -3817,9 +3801,6 @@ void GdbEngine::setupEngine() CHECK_STATE(EngineSetupRequested); showMessage("TRYING TO START ADAPTER"); - if (isRemoteEngine()) - m_gdbProc.setUseCtrlCStub(runParameters().useCtrlCStub); // This is only set for QNX - const DebuggerRunParameters &rp = runParameters(); CommandLine gdbCommand = rp.debugger.command; @@ -4314,7 +4295,6 @@ void GdbEngine::interruptLocalInferior(qint64 pid) showMessage("TRYING TO INTERRUPT INFERIOR BEFORE PID WAS OBTAINED", LogError); return; } - QString errorMessage; if (runParameters().runAsRoot) { Environment env = Environment::systemEnvironment(); RunControl::provideAskPassEntry(env); @@ -4323,11 +4303,8 @@ void GdbEngine::interruptLocalInferior(qint64 pid) proc.setEnvironment(env); proc.start(); proc.waitForFinished(); - } else if (interruptProcess(pid, GdbEngineType, &errorMessage)) { - showMessage("Interrupted " + QString::number(pid)); } else { - showMessage(errorMessage, LogError); - notifyInferiorStopFailed(); + m_gdbProc.interrupt(); } } diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index e0bfa126f5a..657447f17e0 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -143,7 +143,7 @@ void PdbEngine::handlePdbStarted() void PdbEngine::interruptInferior() { QString error; - interruptProcess(m_proc.processId(), GdbEngineType, &error); + interruptProcess(m_proc.processId(), &error); } void PdbEngine::executeStepIn(bool) diff --git a/src/plugins/debugger/procinterrupt.cpp b/src/plugins/debugger/procinterrupt.cpp index 113fbeefc4f..0f104f3bfc0 100644 --- a/src/plugins/debugger/procinterrupt.cpp +++ b/src/plugins/debugger/procinterrupt.cpp @@ -23,128 +23,23 @@ static inline QString msgCannotInterrupt(qint64 pid, const QString &why) # define PROCESS_SUSPEND_RESUME (0x0800) #endif // PROCESS_SUSPEND_RESUME -static BOOL isWow64Process(HANDLE hproc) -{ - using LPFN_ISWOW64PROCESS = BOOL (WINAPI*)(HANDLE, PBOOL); - - BOOL ret = false; - - static LPFN_ISWOW64PROCESS fnIsWow64Process = NULL; - if (!fnIsWow64Process) { - if (HMODULE hModule = GetModuleHandle(L"kernel32.dll")) - fnIsWow64Process = reinterpret_cast(GetProcAddress(hModule, "IsWow64Process")); - } - - if (!fnIsWow64Process) { - qWarning("Cannot retrieve symbol 'IsWow64Process'."); - return false; - } - - if (!fnIsWow64Process(hproc, &ret)) { - qWarning("IsWow64Process() failed for %p: %s", - hproc, qPrintable(Utils::winErrorMessage(GetLastError()))); - return false; - } - return ret; -} - // Open the process and break into it -bool Debugger::Internal::interruptProcess(qint64 pID, int engineType, QString *errorMessage, const bool engineExecutableIs64Bit) +bool Debugger::Internal::interruptProcess(qint64 pID, QString *errorMessage) { bool ok = false; HANDLE inferior = NULL; - do { - const DWORD rights = PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION - |PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ - |PROCESS_DUP_HANDLE|PROCESS_TERMINATE|PROCESS_CREATE_THREAD|PROCESS_SUSPEND_RESUME; - inferior = OpenProcess(rights, FALSE, DWORD(pID)); - if (inferior == NULL) { - *errorMessage = QString::fromLatin1("Cannot open process %1: %2"). - arg(pID).arg(Utils::winErrorMessage(GetLastError())); - break; - } + const DWORD rights = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION | PROCESS_VM_OPERATION + | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_DUP_HANDLE + | PROCESS_TERMINATE | PROCESS_CREATE_THREAD | PROCESS_SUSPEND_RESUME; + inferior = OpenProcess(rights, FALSE, DWORD(pID)); + if (inferior == NULL) { + *errorMessage = QString::fromLatin1("Cannot open process %1: %2") + .arg(pID) + .arg(Utils::winErrorMessage(GetLastError())); + } else if (ok = DebugBreakProcess(inferior); !ok) { + *errorMessage = "DebugBreakProcess failed: " + Utils::winErrorMessage(GetLastError()); + } - enum DebugBreakApi { - UseDebugBreakApi, - UseWin64Interrupt, - UseWin32Interrupt - }; -/* - Windows 64 bit has a 32 bit subsystem (WOW64) which makes it possible to run a - 32 bit application inside a 64 bit environment. - When GDB is used DebugBreakProcess must be called from the same system (32/64 bit) running - the inferior. If CDB is used we could in theory break wow64 processes, - but the break is actually a wow64 breakpoint. CDB is configured to ignore these - breakpoints, because they also appear on module loading. - Therefore we need helper executables (win(32/64)interrupt.exe) on Windows 64 bit calling - DebugBreakProcess from the correct system. - - DebugBreak matrix for windows - - Api = UseDebugBreakApi - Win64 = UseWin64Interrupt - Win32 = UseWin32Interrupt - N/A = This configuration is not possible - - | Windows 32bit | Windows 64bit - | QtCreator 32bit | QtCreator 32bit | QtCreator 64bit - | Inferior 32bit | Inferior 32bit | Inferior 64bit | Inferior 32bit | Inferior 64bit | -----------|-----------------|-----------------|-----------------|-----------------|----------------| -CDB 32bit | Api | Api | NA | Win32 | NA | - 64bit | NA | Win64 | Win64 | Api | Api | -----------|-----------------|-----------------|-----------------|-----------------|----------------| -GDB 32bit | Api | Api | NA | Win32 | NA | - 64bit | NA | Api | Win64 | Win32 | Api | -----------|-----------------|-----------------|-----------------|-----------------|----------------| - -*/ - - DebugBreakApi breakApi = UseDebugBreakApi; -#ifdef Q_OS_WIN64 - if ((engineType == GdbEngineType && isWow64Process(inferior)) - || (engineType == CdbEngineType && !engineExecutableIs64Bit)) { - breakApi = UseWin32Interrupt; - } -#else - if (isWow64Process(GetCurrentProcess()) - && ((engineType == CdbEngineType && engineExecutableIs64Bit) - || (engineType == GdbEngineType && !isWow64Process(inferior)))) { - breakApi = UseWin64Interrupt; - } -#endif - if (breakApi == UseDebugBreakApi) { - ok = DebugBreakProcess(inferior); - if (!ok) - *errorMessage = "DebugBreakProcess failed: " + Utils::winErrorMessage(GetLastError()); - } else { - const QString executable = breakApi == UseWin32Interrupt - ? QCoreApplication::applicationDirPath() + "/win32interrupt.exe" - : QCoreApplication::applicationDirPath() + "/win64interrupt.exe"; - if (!QFileInfo::exists(executable)) { - *errorMessage = QString::fromLatin1( - "%1 does not exist. If you have built %2 " - "on your own, checkout " - "https://code.qt.io/cgit/qt-creator/binary-artifacts.git/.") - .arg(QDir::toNativeSeparators(executable), - QGuiApplication::applicationDisplayName()); - break; - } - switch (QProcess::execute(executable, QStringList(QString::number(pID)))) { - case -2: - *errorMessage = QString::fromLatin1("Cannot start %1. Check src\\tools\\win64interrupt\\win64interrupt.c for more information."). - arg(QDir::toNativeSeparators(executable)); - break; - case 0: - ok = true; - break; - default: - *errorMessage = QDir::toNativeSeparators(executable) - + " could not break the process."; - break; - } - break; - } - } while (false); if (inferior != NULL) CloseHandle(inferior); if (!ok) @@ -159,8 +54,7 @@ GDB 32bit | Api | Api | NA | Win32 #include #include -bool Debugger::Internal::interruptProcess(qint64 pID, int /* engineType */, - QString *errorMessage, const bool /*engineExecutableIs64Bit*/) +bool Debugger::Internal::interruptProcess(qint64 pID, QString *errorMessage) { if (pID <= 0) { *errorMessage = msgCannotInterrupt(pID, QString::fromLatin1("Invalid process id.")); diff --git a/src/plugins/debugger/procinterrupt.h b/src/plugins/debugger/procinterrupt.h index c7872ed2e42..ef4d20300db 100644 --- a/src/plugins/debugger/procinterrupt.h +++ b/src/plugins/debugger/procinterrupt.h @@ -7,7 +7,6 @@ namespace Debugger::Internal { -bool interruptProcess(qint64 pID, int engineType, QString *errorMessage, - const bool engineExecutableIs64Bit = false); +bool interruptProcess(qint64 pID, QString *errorMessage); } // Debugger::Internal diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index c214926ec48..489aaae7900 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -904,7 +904,7 @@ static ConsoleItem *constructLogItemTree(const QVariant &result, const QString & if (child) item->appendChild(child); } - } else if (result.canConvert(QMetaType::QString)) { + } else if (result.canConvert(QMetaType(QMetaType::QString))) { item = new ConsoleItem(ConsoleItem::DefaultType, result.toString()); } else { item = new ConsoleItem(ConsoleItem::DefaultType, "Unknown Value"); diff --git a/src/plugins/designer/CMakeLists.txt b/src/plugins/designer/CMakeLists.txt index d9da4cfaf4d..c8f84ffb2df 100644 --- a/src/plugins/designer/CMakeLists.txt +++ b/src/plugins/designer/CMakeLists.txt @@ -25,7 +25,7 @@ else() endif() add_qtc_plugin(Designer - PLUGIN_CLASS FormEditorPlugin + PLUGIN_CLASS DesignerPlugin CONDITION TARGET Qt::DesignerComponentsPrivate AND TARGET Qt::Designer DEPENDS designerintegrationv2 Qt::Designer Qt::PrintSupport Qt::DesignerComponentsPrivate diff --git a/src/plugins/designer/qtdesignerformclasscodegenerator.cpp b/src/plugins/designer/qtdesignerformclasscodegenerator.cpp index e0afdc45d97..d3937ff696d 100644 --- a/src/plugins/designer/qtdesignerformclasscodegenerator.cpp +++ b/src/plugins/designer/qtdesignerformclasscodegenerator.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -75,7 +76,8 @@ bool QtDesignerFormClassCodeGenerator::generateCpp(const FormClassWizardParamete const QString sourceLicense = CppEditor::AbstractEditorSupport::licenseTemplate( project, FilePath::fromString(parameters.sourceFile), parameters.className); // Include guards - const QString guard = Utils::headerGuard(parameters.headerFile); + const QString guard + = CppEditor::deriveHeaderGuard(FilePath::fromString(parameters.headerFile), project); const QString uiInclude = "ui_" + QFileInfo(parameters.uiFile).completeBaseName() + ".h"; diff --git a/src/plugins/effectcomposer/effectcomposercontextobject.cpp b/src/plugins/effectcomposer/effectcomposercontextobject.cpp index dd42092e72e..95ebe7a3670 100644 --- a/src/plugins/effectcomposer/effectcomposercontextobject.cpp +++ b/src/plugins/effectcomposer/effectcomposercontextobject.cpp @@ -39,9 +39,9 @@ QString EffectComposerContextObject::convertColorToString(const QVariant &color) { QString colorString; QColor theColor; - if (color.canConvert(QVariant::Color)) { + if (color.canConvert(QMetaType(QMetaType::QColor))) { theColor = color.value(); - } else if (color.canConvert(QVariant::Vector3D)) { + } else if (color.canConvert(QMetaType(QMetaType::QVector3D))) { auto vec = color.value(); theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z()); } diff --git a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp index 67c0cf893a2..c9a12900230 100644 --- a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp +++ b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp @@ -548,6 +548,13 @@ static void registerLuaApi() // ... then register the settings. LanguageClientManager::registerClientSettings(client); + // and the client type. + ClientType type; + type.id = client->m_settingsTypeId; + type.name = luaClient->m_name; + type.userAddable = false; + LanguageClientSettings::registerClientType(type); + return luaClient; }); diff --git a/src/plugins/lua/wizards/plugin/project.json b/src/plugins/lua/wizards/plugin/project.json index f537bf2ea9d..b7879f50d77 100644 --- a/src/plugins/lua/wizards/plugin/project.json +++ b/src/plugins/lua/wizards/plugin/project.json @@ -1,4 +1,6 @@ { + "$schema": "https://download.qt.io/official_releases/qtcreator/latest/installer_source/jsonschemas/project.json", + "files.exclude": [".qtcreator/project.json.user"], "targets": [ { "name": "Qt Creator", diff --git a/src/plugins/mcusupport/mcukitaspect.cpp b/src/plugins/mcusupport/mcukitaspect.cpp index 1ab803b2437..7e75288b4f9 100644 --- a/src/plugins/mcusupport/mcukitaspect.cpp +++ b/src/plugins/mcusupport/mcukitaspect.cpp @@ -78,7 +78,7 @@ public: const QVariant checkFormat = kit->value(McuDependenciesKitAspect::id()); if (!checkFormat.isValid() || checkFormat.isNull()) return result; - if (!checkFormat.canConvert(QMetaType::QVariantList)) + if (!checkFormat.canConvert(QMetaType(QMetaType::QVariantList))) return {BuildSystemTask(Task::Error, Tr::tr("The MCU dependencies setting value is invalid."))}; // check paths defined in cmake variables for given dependencies exist @@ -105,7 +105,7 @@ public: QTC_ASSERT(kit, return ); const QVariant variant = kit->value(McuDependenciesKitAspect::id()); - if (!variant.isNull() && !variant.canConvert(QMetaType::QVariantList)) { + if (!variant.isNull() && !variant.canConvert(QMetaType(QMetaType::QVariantList))) { qWarning("Kit \"%s\" has a wrong mcu dependencies value set.", qPrintable(kit->displayName())); McuDependenciesKitAspect::setDependencies(kit, Utils::EnvironmentItems()); diff --git a/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp b/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp index 70412124462..773f4d3bca5 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp @@ -102,90 +102,20 @@ void DesktopProcessSignalOperation::killProcessSilently(qint64 pid) void DesktopProcessSignalOperation::interruptProcessSilently(qint64 pid) { #ifdef Q_OS_WIN - enum SpecialInterrupt { NoSpecialInterrupt, Win32Interrupt, Win64Interrupt }; - - bool is64BitSystem = is64BitWindowsSystem(); - SpecialInterrupt si = NoSpecialInterrupt; - if (is64BitSystem) - si = is64BitWindowsBinary(m_debuggerCommand) ? Win64Interrupt : Win32Interrupt; - /* - Windows 64 bit has a 32 bit subsystem (WOW64) which makes it possible to run a - 32 bit application inside a 64 bit environment. - When GDB is used DebugBreakProcess must be called from the same system (32/64 bit) running - the inferior. If CDB is used we could in theory break wow64 processes, - but the break is actually a wow64 breakpoint. CDB is configured to ignore these - breakpoints, because they also appear on module loading. - Therefore we need helper executables (win(32/64)interrupt.exe) on Windows 64 bit calling - DebugBreakProcess from the correct system. - - DebugBreak matrix for windows - - Api = UseDebugBreakApi - Win64 = UseWin64InterruptHelper - Win32 = UseWin32InterruptHelper - N/A = This configuration is not possible - - | Windows 32bit | Windows 64bit - | QtCreator 32bit | QtCreator 32bit | QtCreator 64bit - | Inferior 32bit | Inferior 32bit | Inferior 64bit | Inferior 32bit | Inferior 64bit -----------|-----------------|-----------------|-----------------|-----------------|---------------- -CDB 32bit | Api | Api | N/A | Win32 | N/A - 64bit | N/A | Win64 | Win64 | Api | Api -----------|-----------------|-----------------|-----------------|-----------------|---------------- -GDB 32bit | Api | Api | N/A | Win32 | N/A - 64bit | N/A | N/A | Win64 | N/A | Api -----------|-----------------|-----------------|-----------------|-----------------|---------------- - - */ HANDLE inferior = NULL; - do { - const DWORD rights = PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION - |PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ - |PROCESS_DUP_HANDLE|PROCESS_TERMINATE|PROCESS_CREATE_THREAD|PROCESS_SUSPEND_RESUME; - inferior = OpenProcess(rights, FALSE, pid); - if (inferior == NULL) { - appendMsgCannotInterrupt(pid, Tr::tr("Cannot open process: %1") - + winErrorMessage(GetLastError())); - break; - } - bool creatorIs64Bit = is64BitWindowsBinary( - FilePath::fromUserInput(QCoreApplication::applicationFilePath())); - if (!is64BitSystem - || si == NoSpecialInterrupt - || (si == Win64Interrupt && creatorIs64Bit) - || (si == Win32Interrupt && !creatorIs64Bit)) { - if (!DebugBreakProcess(inferior)) { - appendMsgCannotInterrupt(pid, Tr::tr("DebugBreakProcess failed:") - + QLatin1Char(' ') + winErrorMessage(GetLastError())); - } - } else if (si == Win32Interrupt || si == Win64Interrupt) { - QString executable = QCoreApplication::applicationDirPath(); - executable += si == Win32Interrupt - ? QLatin1String("/win32interrupt.exe") - : QLatin1String("/win64interrupt.exe"); - if (!QFileInfo::exists(executable)) { - appendMsgCannotInterrupt(pid, - Tr::tr("%1 does not exist. If you built %2 " - "yourself, check out https://code.qt.io/cgit/" - "qt-creator/binary-artifacts.git/.") - .arg(QDir::toNativeSeparators(executable), - QGuiApplication::applicationDisplayName())); - } - switch (QProcess::execute(executable, QStringList(QString::number(pid)))) { - case -2: - appendMsgCannotInterrupt(pid, Tr::tr( - "Cannot start %1. Check src\\tools\\win64interrupt\\win64interrupt.c " - "for more information.").arg(QDir::toNativeSeparators(executable))); - break; - case 0: - break; - default: - appendMsgCannotInterrupt(pid, QDir::toNativeSeparators(executable) - + QLatin1Char(' ') + Tr::tr("could not break the process.")); - break; - } - } - } while (false); + const DWORD rights = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION | PROCESS_VM_OPERATION + | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_DUP_HANDLE + | PROCESS_TERMINATE | PROCESS_CREATE_THREAD | PROCESS_SUSPEND_RESUME; + inferior = OpenProcess(rights, FALSE, pid); + if (inferior == NULL) { + appendMsgCannotInterrupt( + pid, Tr::tr("Cannot open process: %1") + winErrorMessage(GetLastError())); + } else if (!DebugBreakProcess(inferior)) { + appendMsgCannotInterrupt( + pid, + Tr::tr("DebugBreakProcess failed:") + QLatin1Char(' ') + + winErrorMessage(GetLastError())); + } if (inferior != NULL) CloseHandle(inferior); #else diff --git a/src/plugins/projectexplorer/kitaspects.cpp b/src/plugins/projectexplorer/kitaspects.cpp index db3300f3270..35193cf6e90 100644 --- a/src/plugins/projectexplorer/kitaspects.cpp +++ b/src/plugins/projectexplorer/kitaspects.cpp @@ -1539,7 +1539,7 @@ Tasks EnvironmentKitAspectFactory::validate(const Kit *k) const QTC_ASSERT(k, return result); const QVariant variant = k->value(EnvironmentKitAspect::id()); - if (!variant.isNull() && !variant.canConvert(QMetaType::QVariantList)) + if (!variant.isNull() && !variant.canConvert(QMetaType(QMetaType::QVariantList))) result << BuildSystemTask(Task::Error, Tr::tr("The environment setting value is invalid.")); return result; @@ -1550,7 +1550,7 @@ void EnvironmentKitAspectFactory::fix(Kit *k) QTC_ASSERT(k, return); const QVariant variant = k->value(EnvironmentKitAspect::id()); - if (!variant.isNull() && !variant.canConvert(QMetaType::QVariantList)) { + if (!variant.isNull() && !variant.canConvert(QMetaType(QMetaType::QVariantList))) { qWarning("Kit \"%s\" has a wrong environment value set.", qPrintable(k->displayName())); EnvironmentKitAspect::setEnvironmentChanges(k, EnvironmentItems()); } diff --git a/src/plugins/projectexplorer/workspaceproject.cpp b/src/plugins/projectexplorer/workspaceproject.cpp index 5b0a92ba6c9..6cbb858921b 100644 --- a/src/plugins/projectexplorer/workspaceproject.cpp +++ b/src/plugins/projectexplorer/workspaceproject.cpp @@ -253,7 +253,12 @@ public: : Project(FOLDER_MIMETYPE, file.isDir() ? file / ".qtcreator" / "project.json" : file) { QTC_CHECK(projectFilePath().absolutePath().ensureWritableDir()); - QTC_CHECK(projectFilePath().ensureExistingFile()); + if (!projectFilePath().exists() && QTC_GUARD(projectFilePath().ensureExistingFile())) { + QJsonObject projectJson; + projectJson.insert("$schema", "https://download.qt.io/official_releases/qtcreator/latest/installer_source/jsonschemas/project.json"); + projectJson.insert(FILES_EXCLUDE_KEY, QJsonArray{QJsonValue(".qtcreator/project.json.user")}); + projectFilePath().writeFileContents(QJsonDocument(projectJson).toJson()); + } setId(Id::fromString(WORKSPACE_PROJECT_ID)); setDisplayName(projectDirectory().fileName()); diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp index 664006fb7a5..f583498db78 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp @@ -46,9 +46,9 @@ QString MaterialEditorContextObject::convertColorToString(const QVariant &color) { QString colorString; QColor theColor; - if (color.canConvert(QVariant::Color)) { + if (color.canConvert(QMetaType(QMetaType::QColor))) { theColor = color.value(); - } else if (color.canConvert(QVariant::Vector3D)) { + } else if (color.canConvert(QMetaType(QMetaType::QVector3D))) { auto vec = color.value(); theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z()); } diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp index b6d119a4248..1a49ce0c39e 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp @@ -87,9 +87,9 @@ QString PropertyEditorContextObject::convertColorToString(const QVariant &color) { QString colorString; QColor theColor; - if (color.canConvert(QVariant::Color)) { + if (color.canConvert(QMetaType(QMetaType::QColor))) { theColor = color.value(); - } else if (color.canConvert(QVariant::Vector3D)) { + } else if (color.canConvert(QMetaType(QMetaType::QVector3D))) { auto vec = color.value(); theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z()); } diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorcontextobject.cpp b/src/plugins/qmldesigner/components/textureeditor/textureeditorcontextobject.cpp index 73e784846bb..30f276a48db 100644 --- a/src/plugins/qmldesigner/components/textureeditor/textureeditorcontextobject.cpp +++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorcontextobject.cpp @@ -47,9 +47,9 @@ QString TextureEditorContextObject::convertColorToString(const QVariant &color) { QString colorString; QColor theColor; - if (color.canConvert(QVariant::Color)) { + if (color.canConvert(QMetaType(QMetaType::QColor))) { theColor = color.value(); - } else if (color.canConvert(QVariant::Vector3D)) { + } else if (color.canConvert(QMetaType(QMetaType::QVector3D))) { auto vec = color.value(); theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z()); } diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp index 762bd85c8b4..04cc8ebebc6 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp @@ -107,14 +107,14 @@ static void editValue(const ModelNode &frameNode, const std::pair int userType = value.typeId(); QVariant newValue = dialog->value(); - if (newValue.canConvert(userType)) { + if (newValue.canConvert(QMetaType(userType))) { QVariant newValueConverted = newValue; - bool converted = newValueConverted.convert(userType); + bool converted = newValueConverted.convert(QMetaType(userType)); if (!converted) { // convert() fails for int to double, so we try this combination newValueConverted = newValue; - converted = newValueConverted.convert(QMetaType::Double); + converted = newValueConverted.convert(QMetaType(QMetaType::Double)); } if (converted) diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index b66270dca12..ded7fbc5ef4 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -1565,7 +1565,7 @@ void TextToModelMerger::syncVariantProperty(AbstractProperty &modelProperty, const TypeName &astType, DifferenceHandler &differenceHandler) { - if (astValue.canConvert(QMetaType::QString)) + if (astValue.canConvert(QMetaType(QMetaType::QString))) populateQrcMapping(astValue.toString()); if (modelProperty.isVariantProperty()) { diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index 27c26e269c0..322c3553071 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -126,7 +126,6 @@ public: setStartMode(AttachToRemoteServer); setCloseMode(KillAtClose); - setUseCtrlCStub(true); setSolibSearchPath(FileUtils::toFilePathList(searchPaths(k))); if (auto qtVersion = dynamic_cast(QtSupport::QtKitAspect::qtVersion(k))) { setSysRoot(qtVersion->qnxTarget()); @@ -196,7 +195,6 @@ public: { setId("QnxAttachDebugSupport"); setUsePortsGatherer(isCppDebugging(), isQmlDebugging()); - setUseCtrlCStub(true); if (isCppDebugging()) { auto pdebugRunner = new PDebugRunner(runControl, portsGatherer()); diff --git a/src/plugins/qtapplicationmanager/CMakeLists.txt b/src/plugins/qtapplicationmanager/CMakeLists.txt index a49279eba10..6241cb1de36 100644 --- a/src/plugins/qtapplicationmanager/CMakeLists.txt +++ b/src/plugins/qtapplicationmanager/CMakeLists.txt @@ -4,6 +4,7 @@ add_qtc_plugin(QtApplicationManagerIntegration PLUGIN_DEPENDS Core Debugger ProjectExplorer QtSupport RemoteLinux + PLUGIN_CLASS AppManagerPlugin DEPENDS Qt::Network Qt::Widgets ExtensionSystem Utils yaml-cpp SOURCES appmanagerconstants.h diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp index c08fedeb104..93b580a935e 100644 --- a/src/plugins/texteditor/markdowneditor.cpp +++ b/src/plugins/texteditor/markdowneditor.cpp @@ -110,6 +110,21 @@ public: m_textEditorWidget->setTextDocument(m_document); m_textEditorWidget->setupGenericHighlighter(); m_textEditorWidget->setMarksVisible(false); + QObject::connect( + m_textEditorWidget, + &TextEditorWidget::saveCurrentStateForNavigationHistory, + this, + &MarkdownEditor::saveCurrentStateForNavigationHistory); + QObject::connect( + m_textEditorWidget, + &TextEditorWidget::addSavedStateToNavigationHistory, + this, + &MarkdownEditor::addSavedStateToNavigationHistory); + QObject::connect( + m_textEditorWidget, + &TextEditorWidget::addCurrentStateToNavigationHistory, + this, + &MarkdownEditor::addCurrentStateToNavigationHistory); auto context = new IContext(this); context->setWidget(m_textEditorWidget); context->setContext(Context(MARKDOWNVIEWER_TEXT_CONTEXT)); @@ -476,6 +491,18 @@ private: } } + void saveCurrentStateForNavigationHistory() { m_savedNavigationState = saveState(); } + + void addSavedStateToNavigationHistory() + { + EditorManager::addCurrentPositionToNavigationHistory(m_savedNavigationState); + } + + void addCurrentStateToNavigationHistory() + { + EditorManager::addCurrentPositionToNavigationHistory(); + } + private: QTimer m_previewTimer; bool m_performDelayedUpdate = false; @@ -491,6 +518,7 @@ private: QAction *m_togglePreviewVisibleAction; QAction *m_swapViewsAction; std::optional m_previewRestoreScrollPosition; + QByteArray m_savedNavigationState; }; class MarkdownEditorFactory final : public IEditorFactory