Merge remote-tracking branch 'origin/14.0'

Change-Id: Ia809bda892afe5321aaaca2275f24baaf9569abc
This commit is contained in:
Eike Ziller
2024-06-12 11:36:13 +02:00
63 changed files with 721 additions and 555 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -23,7 +23,9 @@
applications on them. applications on them.
\note If you use qmake to build the project and the device does not have \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: The following toolchains are supported for building applications:

View File

@@ -25,6 +25,8 @@
You are advised to use CMake to build applications in the Docker container. 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 To pull images from Docker hub or other registries, use the
\l{https://docs.docker.com/engine/reference/commandline/pull/}{docker pull} \l{https://docs.docker.com/engine/reference/commandline/pull/}{docker pull}
command. command.
@@ -64,7 +66,8 @@
Go to \preferences > \uicontrol Kits to check Go to \preferences > \uicontrol Kits to check
that the automatically generated kits point to the appropriate kit items. 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 \title Set preferences for Docker devices
\note Enable the Docker plugin to use it.
To set preferences for Docker devices: To set preferences for Docker devices:
\list 1 \list 1
@@ -165,7 +170,8 @@
\uicontrol {List Auto-Detected Kit Items}. To remove \uicontrol {List Auto-Detected Kit Items}. To remove
them, select \uicontrol {Remove Auto-Detected Kit Items}. 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 \title Build for and run on Docker devices
\note Enable the Docker plugin to use it.
To specify build settings for Docker images: To specify build settings for Docker images:
\list 1 \list 1
@@ -188,5 +196,6 @@
Select \uicontrol Run to specify run settings. Usually, you can use Select \uicontrol Run to specify run settings. Usually, you can use
the default settings. 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}
*/ */

View File

@@ -124,8 +124,34 @@
The document outline in the \l{Outline} view is backed by clangd's document The document outline in the \l{Outline} view is backed by clangd's document
symbol support, which makes the results more reliable than before. symbol support, which makes the results more reliable than before.
\sa {Code Model}, {Clangd}, {Specify clangd settings}, \sa {Configure C++ code model}, {Specify clangd settings},
{Specify Clang tools settings}, {Use compilation databases} {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. \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. 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
\li Select \preferences > \uicontrol C++ >
\uicontrol {Code Model}.
\image qtcreator-preferences-code-model.webp {C++ Code Model preferences} \image qtcreator-preferences-code-model.webp {C++ Code Model preferences}
\li To instruct the code model to interpret ambiguous header files as C The following table summarizes the preferences.
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}.
\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 \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 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, files to index is limited to 5MB by default.
edit the value for the \uicontrol {Do not index files greater than}
check box. To index all files, deselect the check box.
\li To ignore files that match wildcard patterns, select the To index all files, clear the checkbox.
\uicontrol {Ignore files} check box and enter each wildcard pattern \row
on a separate line in the field. \li \uicontrol {Ignore files}
\li To ignore files that match wildcard patterns, enter each wildcard
\endlist pattern on a separate line in the field.
\endtable
\section1 Inspect preprocessed C++ code \section1 Inspect preprocessed C++ code
@@ -186,7 +215,8 @@
this action also expands all \c {"#include <foo.h>"} statements to their this action also expands all \c {"#include <foo.h>"} statements to their
actual contents. actual contents.
\sa {Specify clangd settings}, {Clang Code Model}, {Clangd} \sa {Configure C++ code model}, {Specify clangd settings},
{Clang Code Model}, {Clangd}
*/ */
/*! /*!

View File

@@ -108,28 +108,45 @@
To verify the installation of a particular Qt version, \QC To verify the installation of a particular Qt version, \QC
calls \c {qmake -query} and checks that the directories referenced in the 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 output exist. If you installed Qt using \QOI, run
version, try running \c {make install} in the build directory to actually \QMT to check for updates or to reinstall the Qt version.
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.
\section1 Minimum requirements \section2 Self-built Qt versions
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.
\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 \li qmake is an executable that understands the \c -query command-line
argument. argument.
\li The \c bin and \c include directories have to exist. \QC fetches \li The \c bin and \c include directories have to exist. \QC fetches
these directories by running \c{qmake -query}. these directories by running \c{qmake -query}.
\li The \c mkspecs directory should be complete enough to parse .pro
files.
\endlist \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}
*/ */

View File

@@ -85,6 +85,7 @@
\li \l{Specify clangd settings}{Clangd} \li \l{Specify clangd settings}{Clangd}
\li \l{Specify Clang tools settings}{Clang Tools} \li \l{Specify Clang tools settings}{Clang Tools}
\li \l{Set Copilot preferences}{Copilot} \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{Specify code style}{C++ Code Style}
\li \l{Set C++ file naming preferences}{C++ File Naming} \li \l{Set C++ file naming preferences}{C++ File Naming}
\li \l{Specify dependencies}{Dependencies} \li \l{Specify dependencies}{Dependencies}

View File

@@ -12,6 +12,7 @@ Product {
property string versionTag: qtc.qtcreator_version.replace(/\.|-/g, "") property string versionTag: qtc.qtcreator_version.replace(/\.|-/g, "")
Qt.core.qdocEnvironment: [ Qt.core.qdocEnvironment: [
"GENERATED_ATTRIBUTIONS_DIR=" + product.buildDirectory,
"IDE_DISPLAY_NAME=" + qtc.ide_display_name, "IDE_DISPLAY_NAME=" + qtc.ide_display_name,
"IDE_CASED_ID=" + qtc.ide_cased_id, "IDE_CASED_ID=" + qtc.ide_cased_id,
"IDE_ID=" + qtc.ide_id, "IDE_ID=" + qtc.ide_id,

View File

@@ -77,6 +77,8 @@ class Dumper(DumperBase):
self.isCdb = True self.isCdb = True
#FIXME #FIXME
def register_known_qt_types(self):
DumperBase.register_known_qt_types(self)
typeid = self.typeid_for_string('@QVariantMap') typeid = self.typeid_for_string('@QVariantMap')
del self.type_code_cache[typeid] del self.type_code_cache[typeid]
del self.type_target_cache[typeid] del self.type_target_cache[typeid]

View File

@@ -172,8 +172,6 @@ class DumperBase():
self.qtCustomEventFunc = 0 self.qtCustomEventFunc = 0
self.qtCustomEventPltFunc = 0 self.qtCustomEventPltFunc = 0
self.qtPropertyFunc = 0 self.qtPropertyFunc = 0
self.qtversion = None
self.qtns = None
self.passExceptions = False self.passExceptions = False
self.isTesting = False self.isTesting = False
self.qtLoaded = False self.qtLoaded = False
@@ -189,6 +187,11 @@ class DumperBase():
self.dumpermodules = [] self.dumpermodules = []
# These are sticky for the session
self.qtversion = None
self.qtversionAtLeast6 = None
self.qtnamespace = None
self.init_type_cache() self.init_type_cache()
try: try:
@@ -211,7 +214,7 @@ class DumperBase():
self.currentPrintsAddress = True self.currentPrintsAddress = True
self.currentChildType = None self.currentChildType = None
self.currentChildNumChild = None self.currentChildNumChild = None
self.register_known_types() self.register_known_simple_types()
def setVariableFetchingOptions(self, args): def setVariableFetchingOptions(self, args):
self.last_args = args self.last_args = args
@@ -233,9 +236,16 @@ class DumperBase():
self.useTimeStamps = int(args.get('timestamps', '0')) self.useTimeStamps = int(args.get('timestamps', '0'))
self.partialVariable = args.get('partialvar', '') self.partialVariable = args.get('partialvar', '')
self.uninitialized = args.get('uninitialized', []) 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)) 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('NAMESPACE: "%s"' % self.qtNamespace())
#self.warn('EXPANDED INAMES: %s' % self.expandedINames) #self.warn('EXPANDED INAMES: %s' % self.expandedINames)
#self.warn('WATCHERS: %s' % self.watchers) #self.warn('WATCHERS: %s' % self.watchers)
@@ -256,11 +266,50 @@ class DumperBase():
args['partialvar'] = '' args['partialvar'] = ''
self.fetchVariables(args) self.fetchVariables(args)
def extractQtVersion(self):
# can be overridden in bridges
pass
def qtVersion(self): def qtVersion(self):
if self.qtversion:
return 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): def qtNamespace(self):
return self.qtnamespace return '' if self.qtnamespace is None else self.qtnamespace
def resetPerStepCaches(self): def resetPerStepCaches(self):
self.perStepCache = {} self.perStepCache = {}
@@ -494,8 +543,13 @@ class DumperBase():
def register_struct(self, name, p5=0, p6=0, s=0, qobject_based=False): def register_struct(self, name, p5=0, p6=0, s=0, qobject_based=False):
# p5 = n -> n * ptrsize for Qt 5 # p5 = n -> n * ptrsize for Qt 5
# p6 = n -> n * ptrsize for Qt 6 # p6 = n -> n * ptrsize for Qt 6
#if self.qtVersion() >= 0x060000: # FIXME: Qt 5, ptrSize() if self.qtversionAtLeast6 is None:
self.warn("TOO EARLY TO GUESS QT VERSION")
size = 8 * p6 + s size = 8 * p6 + s
elif self.qtversionAtLeast6 is True:
size = 8 * p6 + s
else:
size = 8 * p5 + s
typeid = self.typeid_for_string(name) typeid = self.typeid_for_string(name)
self.type_code_cache[typeid] = TypeCode.Struct self.type_code_cache[typeid] = TypeCode.Struct
self.type_size_cache[typeid] = size self.type_size_cache[typeid] = size
@@ -503,7 +557,7 @@ class DumperBase():
self.type_alignment_cache[typeid] = 8 self.type_alignment_cache[typeid] = 8
return typeid return typeid
def register_known_types(self): def register_known_simple_types(self):
typeid = 0 typeid = 0
self.typeid_cache[''] = typeid self.typeid_cache[''] = typeid
self.type_code_cache[typeid] = TypeCode.Void self.type_code_cache[typeid] = TypeCode.Void
@@ -563,6 +617,8 @@ class DumperBase():
self.register_enum('@Qt::ItemDataRole', 4) 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('@QObject', p5=2, p6=2, qobject_based=True)
self.register_struct('@QObjectPrivate', p5=10, p6=10) # FIXME: Not exact self.register_struct('@QObjectPrivate', p5=10, p6=10) # FIXME: Not exact
@@ -680,9 +736,6 @@ class DumperBase():
# Hex decoding operating on str, return str. # Hex decoding operating on str, return str.
@staticmethod @staticmethod
def hexdecode(s, encoding='utf8'): 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) return bytes.fromhex(s).decode(encoding)
# Hex encoding operating on str or bytes, return str. # Hex encoding operating on str or bytes, return str.
@@ -690,10 +743,6 @@ class DumperBase():
def hexencode(s): def hexencode(s):
if s is None: if s is None:
s = '' s = ''
if sys.version_info[0] == 2:
if isinstance(s, buffer):
return bytes(s).encode('hex')
return s.encode('hex')
if isinstance(s, str): if isinstance(s, str):
s = s.encode('utf8') s = s.encode('utf8')
return hexencode_(s) return hexencode_(s)
@@ -711,9 +760,9 @@ class DumperBase():
return limit return limit
def vectorData(self, value): def vectorData(self, value):
if self.qtVersion() >= 0x060000: if self.qtVersionAtLeast(0x060000):
data, length, alloc = self.qArrayData(value) data, length, alloc = self.qArrayData(value)
elif self.qtVersion() >= 0x050000: elif self.qtVersionAtLeast(0x050000):
vector_data_ptr = self.extractPointer(value) vector_data_ptr = self.extractPointer(value)
if self.ptrSize() == 4: if self.ptrSize() == 4:
(ref, length, alloc, offset) = self.split('IIIp', vector_data_ptr) (ref, length, alloc, offset) = self.split('IIIp', vector_data_ptr)
@@ -729,7 +778,7 @@ class DumperBase():
return data, length return data, length
def qArrayData(self, value): def qArrayData(self, value):
if self.qtVersion() >= 0x60000: if self.qtVersionAtLeast(0x60000):
dd, data, length = self.split('ppp', value) dd, data, length = self.split('ppp', value)
if dd: if dd:
_, _, alloc = self.split('iip', dd) _, _, alloc = self.split('iip', dd)
@@ -740,7 +789,7 @@ class DumperBase():
def qArrayDataHelper(self, array_data_ptr): def qArrayDataHelper(self, array_data_ptr):
# array_data_ptr is what is e.g. stored in a QByteArray's d_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: # QTypedArray:
# - QtPrivate::RefCount ref # - QtPrivate::RefCount ref
# - int length # - int length
@@ -753,7 +802,7 @@ class DumperBase():
data = data & 0xffffffff data = data & 0xffffffff
else: else:
data = data & 0xffffffffffffffff data = data & 0xffffffffffffffff
elif self.qtVersion() >= 0x040000: elif self.qtVersionAtLeast(0x040000):
# Data: # Data:
# - QBasicAtomicInt ref; # - QBasicAtomicInt ref;
# - int alloc, length; # - int alloc, length;
@@ -1597,7 +1646,7 @@ class DumperBase():
intSize = 4 intSize = 4
ptrSize = self.ptrSize() ptrSize = self.ptrSize()
if self.qtVersion() >= 0x060000: if self.qtVersionAtLeast(0x060000):
# Size of QObjectData: 9 pointer + 2 int # Size of QObjectData: 9 pointer + 2 int
# - vtable # - vtable
# - QObject *q_ptr; # - QObject *q_ptr;
@@ -1618,7 +1667,7 @@ class DumperBase():
# - QList<QPointer<QObject> > eventFilters; # - QList<QPointer<QObject> > eventFilters;
# - QString objectName # - QString objectName
objectNameAddress = extra + 12 * ptrSize objectNameAddress = extra + 12 * ptrSize
elif self.qtVersion() >= 0x050000: elif self.qtVersionAtLeast(0x050000):
# Size of QObjectData: 5 pointer + 2 int # Size of QObjectData: 5 pointer + 2 int
# - vtable # - vtable
# - QObject *q_ptr; # - 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_OBJECT SMO has a non-null superdata (unless it's QObject itself),
# a Q_GADGET SMO has a null superdata (hopefully) # a Q_GADGET SMO has a null superdata (hopefully)
if result and not isQObjectProper: 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) (direct, indirect) = self.split('pp', result)
# since Qt 6 there is an additional indirect super data getter on windows # since Qt 6 there is an additional indirect super data getter on windows
if direct == 0 and indirect == 0: if direct == 0 and indirect == 0:
@@ -1895,14 +1944,14 @@ class DumperBase():
return result return result
def listData(self, value, check=True): def listData(self, value, check=True):
if self.qtVersion() >= 0x60000: if self.qtVersionAtLeast(0x60000):
dd, data, size = self.split('ppi', value) dd, data, size = self.split('ppi', value)
return data, size return data, size
base = self.extractPointer(value) base = self.extractPointer(value)
(ref, alloc, begin, end) = self.split('IIII', base) (ref, alloc, begin, end) = self.split('IIII', base)
array = base + 16 array = base + 16
if self.qtVersion() < 0x50000: if not self.qtVersionAtLeast(0x50000):
array += self.ptrSize() array += self.ptrSize()
size = end - begin size = end - begin
@@ -1941,7 +1990,7 @@ class DumperBase():
def metaString(self, metaObjectPtr, index, revision): def metaString(self, metaObjectPtr, index, revision):
ptrSize = self.ptrSize() ptrSize = self.ptrSize()
stringdataOffset = ptrSize stringdataOffset = ptrSize
if self.isWindowsTarget() and self.qtVersion() >= 0x060000: if self.isWindowsTarget() and self.qtVersionAtLeast(0x060000):
stringdataOffset += ptrSize # indirect super data member stringdataOffset += ptrSize # indirect super data member
stringdata = self.extract_pointer_at_address(int(metaObjectPtr) + stringdataOffset) stringdata = self.extract_pointer_at_address(int(metaObjectPtr) + stringdataOffset)
@@ -1970,19 +2019,19 @@ class DumperBase():
self.putField('sortgroup', sortorder) self.putField('sortgroup', sortorder)
def putQMetaStuff(self, value, origType): def putQMetaStuff(self, value, origType):
if self.qtVersion() >= 0x060000: if self.qtVersionAtLeast(0x060000):
metaObjectPtr, handle = value.split('pp') metaObjectPtr, handle = value.split('pp')
else: else:
metaObjectPtr, handle = value.split('pI') metaObjectPtr, handle = value.split('pI')
if metaObjectPtr != 0: if metaObjectPtr != 0:
if self.qtVersion() >= 0x060000: if self.qtVersionAtLeast(0x060000):
if handle == 0: if handle == 0:
self.putEmptyValue() self.putEmptyValue()
return return
revision = 9 revision = 9
name, alias, flags, keyCount, data = self.split('IIIII', handle) name, alias, flags, keyCount, data = self.split('IIIII', handle)
index = name index = name
elif self.qtVersion() >= 0x050000: elif self.qtVersionAtLeast(0x050000):
revision = 7 revision = 7
dataPtr = self.extract_pointer_at_address(metaObjectPtr + 2 * self.ptrSize()) dataPtr = self.extract_pointer_at_address(metaObjectPtr + 2 * self.ptrSize())
index = self.extractInt(dataPtr + 4 * handle) index = self.extractInt(dataPtr + 4 * handle)
@@ -2024,7 +2073,7 @@ class DumperBase():
def extractDataPtr(someMetaObjectPtr): def extractDataPtr(someMetaObjectPtr):
# dataPtr = metaObjectPtr['d']['data'] # dataPtr = metaObjectPtr['d']['data']
if self.qtVersion() >= 0x60000 and self.isWindowsTarget(): if self.qtVersionAtLeast(0x60000) and self.isWindowsTarget():
offset = 3 offset = 3
else: else:
offset = 2 offset = 2
@@ -2054,13 +2103,13 @@ class DumperBase():
extraData = 0 extraData = 0
if qobjectPtr: if qobjectPtr:
dd = self.extract_pointer_at_address(qobjectPtr + ptrSize) dd = self.extract_pointer_at_address(qobjectPtr + ptrSize)
if self.qtVersion() >= 0x60000: if self.qtVersionAtLeast(0x60000):
(dvtablePtr, qptr, parent, children, bindingStorageData, bindingStatus, (dvtablePtr, qptr, parent, children, bindingStorageData, bindingStatus,
flags, postedEvents, dynMetaObjectPtr, # Up to here QObjectData. flags, postedEvents, dynMetaObjectPtr, # Up to here QObjectData.
extraData, threadDataPtr, connectionListsPtr, extraData, threadDataPtr, connectionListsPtr,
sendersPtr, currentSenderPtr) \ sendersPtr, currentSenderPtr) \
= self.split('pp{@QObject*}{@QList<@QObject *>}ppIIp' + 'ppppp', dd) = self.split('pp{@QObject*}{@QList<@QObject *>}ppIIp' + 'ppppp', dd)
elif self.qtVersion() >= 0x50000: elif self.qtVersionAtLeast(0x50000):
(dvtablePtr, qptr, parent, children, flags, postedEvents, (dvtablePtr, qptr, parent, children, flags, postedEvents,
dynMetaObjectPtr, # Up to here QObjectData. dynMetaObjectPtr, # Up to here QObjectData.
extraData, threadDataPtr, connectionListsPtr, extraData, threadDataPtr, connectionListsPtr,
@@ -2186,7 +2235,7 @@ typename))
with Children(self): with Children(self):
# Static properties. # Static properties.
for i in range(propertyCount): for i in range(propertyCount):
if self.qtVersion() >= 0x60000: if self.qtVersionAtLeast(0x60000):
t = self.split('IIIII', dataPtr + properties * 4 + 20 * i) t = self.split('IIIII', dataPtr + properties * 4 + 20 * i)
else: else:
t = self.split('III', dataPtr + properties * 4 + 12 * i) t = self.split('III', dataPtr + properties * 4 + 12 * i)
@@ -2239,18 +2288,18 @@ typename))
data += inner_size data += inner_size
variant_typeid = self.cheap_typeid_from_name('@QVariant') variant_typeid = self.cheap_typeid_from_name('@QVariant')
if self.qtVersion() >= 0x60000: if self.qtVersionAtLeast(0x60000):
values = vectorGenerator(extraData + 3 * ptrSize, variant_typeid) values = vectorGenerator(extraData + 3 * ptrSize, variant_typeid)
elif self.qtVersion() >= 0x50600: elif self.qtVersionAtLeast(0x50600):
values = vectorGenerator(extraData + 2 * ptrSize, variant_typeid) values = vectorGenerator(extraData + 2 * ptrSize, variant_typeid)
elif self.qtVersion() >= 0x50000: elif self.qtVersionAtLeast(0x50000):
values = list5Generator(extraData + 2 * ptrSize, variant_typeid) values = list5Generator(extraData + 2 * ptrSize, variant_typeid)
else: else:
variantptr_typeid = self.cheap_typeid_from_name('@QVariant') variantptr_typeid = self.cheap_typeid_from_name('@QVariant')
values = list5Generator(extraData + 2 * ptrSize, variantptr_typeid) values = list5Generator(extraData + 2 * ptrSize, variantptr_typeid)
bytearray_typeid = self.cheap_typeid_from_name('@QByteArray') bytearray_typeid = self.cheap_typeid_from_name('@QByteArray')
if self.qtVersion() >= 0x60000: if self.qtVersionAtLeast(0x60000):
names = list6Generator(extraData, bytearray_typeid) names = list6Generator(extraData, bytearray_typeid)
else: else:
names = list5Generator(extraData + ptrSize, bytearray_typeid) names = list5Generator(extraData + ptrSize, bytearray_typeid)
@@ -2671,10 +2720,7 @@ typename))
try: try:
if funcname.startswith('qdump__'): if funcname.startswith('qdump__'):
typename = funcname[7:] typename = funcname[7:]
if sys.version_info > (3,):
spec = inspect.getfullargspec(function) spec = inspect.getfullargspec(function)
else:
spec = inspect.getargspec(function)
if len(spec.args) == 2: if len(spec.args) == 2:
self.qqDumpers[typename] = function self.qqDumpers[typename] = function
elif len(spec.args) == 3 and len(spec.defaults) == 1: elif len(spec.args) == 3 and len(spec.defaults) == 1:
@@ -2721,11 +2767,8 @@ typename))
def reloadDumpers(self, args): def reloadDumpers(self, args):
for mod in self.dumpermodules: for mod in self.dumpermodules:
m = sys.modules[mod] m = sys.modules[mod]
if sys.version_info[0] >= 3:
import importlib import importlib
importlib.reload(m) importlib.reload(m)
else:
reload(m)
self.setupDumpers(args) self.setupDumpers(args)
def loadDumpers(self, args): def loadDumpers(self, args):
@@ -3427,9 +3470,9 @@ typename))
): ):
return True return True
if strippedName == 'QStringList': if strippedName == 'QStringList':
return self.dumper.qtVersion() >= 0x050000 return self.dumper.qtVersionAtLeast(0x050000)
if strippedName == 'QList': if strippedName == 'QList':
return self.dumper.qtVersion() >= 0x050600 return self.dumper.qtVersionAtLeast(0x050600)
return False return False
class Field: class Field:
@@ -3550,7 +3593,7 @@ typename))
if typename.startswith('QList<') or typename.startswith('QVector<'): if typename.startswith('QList<') or typename.startswith('QVector<'):
typeid = self.typeid_for_string(typename) typeid = self.typeid_for_string(typename)
if typeid: 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_code_cache[typeid] = TypeCode.Struct
self.type_size_cache[typeid] = size self.type_size_cache[typeid] = size
return typeid return typeid

View File

@@ -874,6 +874,36 @@ class Dumper(DumperBase):
except: except:
return '0x%x' % address 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): def createSpecialBreakpoints(self, args):
self.specialBreakpoints = [] self.specialBreakpoints = []

View File

@@ -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 # Simplify development of this module by reloading deps
if 'dumper' in sys.modules: if 'dumper' in sys.modules:
if sys.version_info[0] >= 3:
if sys.version_info[1] > 3:
from importlib import reload from importlib import reload
else:
def reload(m): print('Unsupported Python version - not reloading %s' % str(m))
reload(sys.modules['dumper']) reload(sys.modules['dumper'])
from dumper import DumperBase, SubItem, Children, TopLevelItem from dumper import DumperBase, SubItem, Children, TopLevelItem
@@ -34,16 +30,10 @@ from dumper import DumperBase, SubItem, Children, TopLevelItem
####################################################################### #######################################################################
qqWatchpointOffset = 10000 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): def toCString(s):
if _c_str_trans is not None:
return str(s).translate(_c_str_trans) return str(s).translate(_c_str_trans)
else:
return str(s).replace('\\', '\\\\').replace('\n', '\\n').replace('"', '\\"')
def fileNameAsString(file): def fileNameAsString(file):
return toCString(file) if file.IsValid() else '' return toCString(file) if file.IsValid() else ''
@@ -783,6 +773,54 @@ class Dumper(DumperBase):
self.fetchInternalFunctions = lambda: None 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): def handleCommand(self, command):
result = lldb.SBCommandReturnObject() result = lldb.SBCommandReturnObject()
self.debugger.GetCommandInterpreter().HandleCommand(command, result) self.debugger.GetCommandInterpreter().HandleCommand(command, result)
@@ -2312,9 +2350,6 @@ class SummaryProvider(LogMixin):
if encoding in text_encodings: if encoding in text_encodings:
try: try:
decodedValue = Dumper.hexdecode(summaryValue, encoding) 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 + '"' return '"' + decodedValue + '"'
except: except:
return "<failed to decode '%s' as '%s': %s>" % (summaryValue, encoding, sys.exc_info()[1]) return "<failed to decode '%s' as '%s': %s>" % (summaryValue, encoding, sys.exc_info()[1])

View File

@@ -33,7 +33,8 @@ def qedit__QByteArray(d, value, data):
def qdump__QByteArray(d, value): def qdump__QByteArray(d, value):
if d.qtVersion() >= 0x60000: d.qtVersionPing(value.typeid)
if d.qtVersionAtLeast(0x060000):
dd, data, length = value.split('ppi') dd, data, length = value.split('ppi')
if dd: if dd:
_, _, alloc = d.split('iii', dd) _, _, alloc = d.split('iii', dd)
@@ -76,7 +77,8 @@ def qdump__QByteArray(d, value):
def qdump__QBitArray(d, value): def qdump__QBitArray(d, value):
if d.qtVersion() >= 0x60000: d.qtVersionPing(value.typeid)
if d.qtVersionAtLeast(0x060000):
_, data, basize = value.split('ppi') _, data, basize = value.split('ppi')
else: else:
data, basize, _ = d.qArrayData(value['d']) data, basize, _ = d.qArrayData(value['d'])
@@ -232,13 +234,13 @@ def qdump__QStandardItem(d, value):
#d.createType('@QStandardItem*') #d.createType('@QStandardItem*')
vtable, dptr = value.split('pp') vtable, dptr = value.split('pp')
if d.qtVersion() >= 0x060000: if d.qtVersionAtLeast(0x060000):
model, parent, values, children, rows, cols, item = \ model, parent, values, children, rows, cols, item = \
d.split('pp{@QList<@QStandardItemData>}{@QList<@QStandardItem *>}IIp', dptr) d.split('pp{@QList<@QStandardItemData>}{@QList<@QStandardItem *>}IIp', dptr)
else: else:
# There used to be a virtual destructor that got removed in # There used to be a virtual destructor that got removed in
# 88b6abcebf29b455438 on Apr 18 17:01:22 2017 # 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(); dptr += d.ptrSize();
model, parent, values, children, rows, cols, item = \ model, parent, values, children, rows, cols, item = \
d.split('pp{@QVector<@QStandardItemData>}{@QVector<@QStandardItem *>}IIp', dptr) d.split('pp{@QVector<@QStandardItemData>}{@QVector<@QStandardItem *>}IIp', dptr)
@@ -266,7 +268,7 @@ def qdump__QDate(d, value):
d.enumExpression('DateFormat', 'TextDate')) d.enumExpression('DateFormat', 'TextDate'))
d.putCallItem('(ISO)', '@QString', value, 'toString', d.putCallItem('(ISO)', '@QString', value, 'toString',
d.enumExpression('DateFormat', 'ISODate')) d.enumExpression('DateFormat', 'ISODate'))
if d.qtVersion() < 0x060000: if not d.qtVersionAtLeast(0x060000):
d.putCallItem('(SystemLocale)', '@QString', value, 'toString', d.putCallItem('(SystemLocale)', '@QString', value, 'toString',
d.enumExpression('DateFormat', 'SystemLocaleDate')) d.enumExpression('DateFormat', 'SystemLocaleDate'))
d.putCallItem('(Locale)', '@QString', value, 'toString', d.putCallItem('(Locale)', '@QString', value, 'toString',
@@ -286,7 +288,7 @@ def qdump__QTime(d, value):
d.enumExpression('DateFormat', 'TextDate')) d.enumExpression('DateFormat', 'TextDate'))
d.putCallItem('(ISO)', '@QString', value, 'toString', d.putCallItem('(ISO)', '@QString', value, 'toString',
d.enumExpression('DateFormat', 'ISODate')) 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.putCallItem('(SystemLocale)', '@QString', value, 'toString',
d.enumExpression('DateFormat', 'SystemLocaleDate')) d.enumExpression('DateFormat', 'SystemLocaleDate'))
d.putCallItem('(Locale)', '@QString', value, 'toString', d.putCallItem('(Locale)', '@QString', value, 'toString',
@@ -305,13 +307,12 @@ def qdump__QTimeZone(d, value):
def qdump__QDateTime(d, value): def qdump__QDateTime(d, value):
qtVersion = d.qtVersion()
isValid = False isValid = False
# This relies on the Qt4/Qt5 internal structure layout: # This relies on the Qt4/Qt5 internal structure layout:
# {sharedref(4), ... # {sharedref(4), ...
base = d.extractPointer(value) base = d.extractPointer(value)
is32bit = d.ptrSize() == 4 is32bit = d.ptrSize() == 4
if qtVersion >= 0x050200: if d.qtVersionAtLeast(0x050200):
tiVersion = d.qtTypeInfoVersion() tiVersion = d.qtTypeInfoVersion()
#DumperBase.warn('TI VERSION: %s' % tiVersion) #DumperBase.warn('TI VERSION: %s' % tiVersion)
if tiVersion is None: if tiVersion is None:
@@ -384,9 +385,9 @@ def qdump__QDateTime(d, value):
# - [QTime time;] # - [QTime time;]
# - - uint mds; # - - uint mds;
# - Spec spec; # - 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 # 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 dateBase = base + refPlusPadding
timeBase = dateBase + dateSize timeBase = dateBase + dateSize
mds = d.extractInt(timeBase) mds = d.extractInt(timeBase)
@@ -410,7 +411,7 @@ def qdump__QDateTime(d, value):
d.enumExpression('DateFormat', 'ISODate')) d.enumExpression('DateFormat', 'ISODate'))
d.putCallItem('toUTC', '@QDateTime', value, 'toTimeSpec', d.putCallItem('toUTC', '@QDateTime', value, 'toTimeSpec',
d.enumExpression('TimeSpec', 'UTC')) d.enumExpression('TimeSpec', 'UTC'))
if d.qtVersion() < 0x060000: if not d.qtVersionAtLeast(0x060000):
d.putCallItem('(SystemLocale)', '@QString', value, 'toString', d.putCallItem('(SystemLocale)', '@QString', value, 'toString',
d.enumExpression('DateFormat', 'SystemLocaleDate')) d.enumExpression('DateFormat', 'SystemLocaleDate'))
d.putCallItem('(Locale)', '@QString', value, 'toString', d.putCallItem('(Locale)', '@QString', value, 'toString',
@@ -756,7 +757,6 @@ def qdump__QFile(d, value):
def qdump__QFileInfo(d, value): def qdump__QFileInfo(d, value):
privAddress = d.extractPointer(value) privAddress = d.extractPointer(value)
#bit32 = d.ptrSize() == 4 #bit32 = d.ptrSize() == 4
#qt5 = d.qtVersion() >= 0x050000
#try: #try:
# d.putStringValue(value['d_ptr']['d'].dereference()['fileNames'][3]) # d.putStringValue(value['d_ptr']['d'].dereference()['fileNames'][3])
#except: #except:
@@ -876,7 +876,7 @@ def qdump__QVariantHash(d, value):
def qdumpHelper_QHash(d, value, keyType, valueType): def qdumpHelper_QHash(d, value, keyType, valueType):
if d.qtVersion() >= 0x60000: if d.qtVersionAtLeast(0x060000):
qdumpHelper_QHash_6(d, value, keyType, valueType) qdumpHelper_QHash_6(d, value, keyType, valueType)
else: else:
qdumpHelper_QHash_5(d, value, keyType, valueType) qdumpHelper_QHash_5(d, value, keyType, valueType)
@@ -918,7 +918,7 @@ def qdumpHelper_QHash_5(d, value, keyType, valueType):
d.putItemCount(size) d.putItemCount(size)
if d.isExpanded(): if d.isExpanded():
isShort = d.qtVersion() < 0x050000 and keyType.name == 'int' isShort = not d.qtVersionAtLeast(0x050000) and keyType.name == 'int'
with Children(d, size): with Children(d, size):
node = hashDataFirstNode() node = hashDataFirstNode()
for i in d.childRange(): for i in d.childRange():
@@ -994,7 +994,7 @@ def qHashIteratorHelper(d, value):
if d.isExpanded(): if d.isExpanded():
with Children(d): with Children(d):
node = d.extractPointer(value) node = d.extractPointer(value)
isShort = d.qtVersion() < 0x050000 and keyType.name == 'int' isShort = not d.qtVersionAtLeast(0x050000) and keyType.name == 'int'
if isShort: if isShort:
typeCode = 'P{%s}@{%s}' % (keyType.name, valueType.name) typeCode = 'P{%s}@{%s}' % (keyType.name, valueType.name)
(pnext, key, padding2, val) = d.split(typeCode, node) (pnext, key, padding2, val) = d.split(typeCode, node)
@@ -1015,9 +1015,8 @@ def qdump__QHash__iterator(d, value):
def qdump__QHostAddress(d, value): def qdump__QHostAddress(d, value):
dd = d.extractPointer(value) dd = d.extractPointer(value)
qtVersion = d.qtVersion()
tiVersion = d.qtTypeInfoVersion() tiVersion = d.qtTypeInfoVersion()
#DumperBase.warn('QT: %x, TI: %s' % (qtVersion, tiVersion)) #DumperBase.warn('QT: %x, TI: %s' % (d.qtVersion(), tiVersion))
mayNeedParse = True mayNeedParse = True
if tiVersion is not None: if tiVersion is not None:
if tiVersion >= 16: if tiVersion >= 16:
@@ -1032,14 +1031,14 @@ def qdump__QHostAddress(d, value):
else: else:
(ipString, scopeId, a4, pad, a6, protocol, isParsed) \ (ipString, scopeId, a4, pad, a6, protocol, isParsed) \
= d.split('{@QString}{@QString}{@quint32}I16sI{bool}', dd) = 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(): if d.ptrSize() == 8 or d.isWindowsTarget():
(ipString, scopeId, a4, pad, a6, protocol, isParsed) \ (ipString, scopeId, a4, pad, a6, protocol, isParsed) \
= d.split('{@QString}{@QString}{@quint32}I16sI{bool}', dd) = d.split('{@QString}{@QString}{@quint32}I16sI{bool}', dd)
else: else:
(ipString, scopeId, a4, a6, protocol, isParsed) \ (ipString, scopeId, a4, a6, protocol, isParsed) \
= d.split('{@QString}{@QString}{@quint32}16sI{bool}', dd) = 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) \ (ipString, scopeId, a4, a6, protocol, isParsed) \
= d.split('{@QString}{@QString}{@quint32}16sI{bool}', dd) = d.split('{@QString}{@QString}{@quint32}16sI{bool}', dd)
else: # 4.8.7 at b05d05f else: # 4.8.7 at b05d05f
@@ -1104,7 +1103,8 @@ def qdumpHelper_QList(d, value, inner_typish):
data, size = d.listData(value, check=True) data, size = d.listData(value, check=True)
d.putItemCount(size) d.putItemCount(size)
if d.qtVersion() >= 0x60000: d.qtVersionPing(value.typeid)
if d.qtVersionAtLeast(0x060000):
d.putPlotData(data, size, innerType) d.putPlotData(data, size, innerType)
return return
@@ -1145,9 +1145,9 @@ def qform__QImage():
def qdump__QImage(d, value): def qdump__QImage(d, value):
if d.qtVersion() >= 0x060000: if d.qtVersionAtLeast(0x060000):
vtbl, painters, image_data = value.split('ppp') vtbl, painters, image_data = value.split('ppp')
elif d.qtVersion() >= 0x050000: elif d.qtVersionAtLeast(0x050000):
vtbl, painters, reserved, image_data = value.split('pppp') vtbl, painters, reserved, image_data = value.split('pppp')
else: else:
vtbl, painters, image_data = value.split('ppp') vtbl, painters, image_data = value.split('ppp')
@@ -1161,12 +1161,12 @@ def qdump__QImage(d, value):
d.putExpandable() d.putExpandable()
if d.isExpanded(): if d.isExpanded():
if d.qtVersion() < 0x060000: if d.qtVersionAtLeast(0x060000):
(ref, width, height, depth, nbytes, pad, devicePixelRatio, colorTable,
bits, iformat) = d.split('iiiii@dppi', image_data)
else:
(ref, width, height, depth, nbytes, pad, devicePixelRatio, _, _, _, (ref, width, height, depth, nbytes, pad, devicePixelRatio, _, _, _,
bits, iformat) = d.split('iiiii@dppppi', image_data) 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): with Children(d):
d.putIntItem('width', width) d.putIntItem('width', width)
d.putIntItem('height', height) d.putIntItem('height', height)
@@ -1222,8 +1222,7 @@ def qdump__QLocale(d, value):
# index = int(value['d']['d']['m_data']...) # index = int(value['d']['d']['m_data']...)
#d.check(index >= 0) #d.check(index >= 0)
#d.check(index <= qqLocalesCount) #d.check(index <= qqLocalesCount)
qtVersion = d.qtVersion() if not d.qtVersionAtLeast(0x50000):
if qtVersion < 0x50000:
d.putStringValue(d.call('const char *', value, 'name')) d.putStringValue(d.call('const char *', value, 'name'))
d.putPlainChildren(value) d.putPlainChildren(value)
return return
@@ -1240,7 +1239,7 @@ def qdump__QLocale(d, value):
prefix = ns + 'QLocale::' prefix = ns + 'QLocale::'
try: try:
if qtVersion >= 0x060700: if qtVersionAtLeast(0x060700):
res = d.call('const char *', value, 'name', prefix + 'TagSeparator::Underscore') res = d.call('const char *', value, 'name', prefix + 'TagSeparator::Underscore')
else: else:
res = d.call('const char *', value, 'name') res = d.call('const char *', value, 'name')
@@ -1347,9 +1346,9 @@ def qdump__QMap(d, value):
def qdumpHelper_QMap(d, value, keyType, valueType): def qdumpHelper_QMap(d, value, keyType, valueType):
if d.qtVersion() >= 0x60000: if d.qtVersionAtLeast(0x060000):
qdumpHelper_Qt6_QMap(d, value, keyType, valueType) qdumpHelper_Qt6_QMap(d, value, keyType, valueType)
elif d.qtVersion() >= 0x50000: elif d.qtVersionAtLeast(0x50000):
qdumpHelper_Qt5_QMap(d, value, keyType, valueType) qdumpHelper_Qt5_QMap(d, value, keyType, valueType)
else: else:
qdumpHelper_Qt4_QMap(d, value, keyType, valueType) 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)) d.putBetterType('@QMultiMap<%s, %s>' % (keyType.name, valueType.name))
def qdump__QMultiMap(d, value): def qdump__QMultiMap(d, value):
if d.qtVersion() >= 0x60000: if d.qtVersionAtLeast(0x060000):
qdumpHelper_Qt6_QMultiMap(d, value, value.type[0], value.type[1]) qdumpHelper_Qt6_QMultiMap(d, value, value.type[0], value.type[1])
else: else:
qdump__QMap(d, value) qdump__QMap(d, value)
@@ -1449,9 +1448,9 @@ def qdump__QProcEnvKey(d, value):
def qdump__QPixmap(d, value): def qdump__QPixmap(d, value):
if d.qtVersion() >= 0x060000: if d.qtVersionAtLeast(0x060000):
vtbl, painters, data = value.split('ppp') vtbl, painters, data = value.split('ppp')
elif d.qtVersion() >= 0x050000: elif d.qtVersionAtLeast(0x050000):
vtbl, painters, reserved, data = s = d.split('pppp', value) vtbl, painters, reserved, data = s = d.split('pppp', value)
else: else:
vtbl, painters, data = value.split('ppp') vtbl, painters, data = value.split('ppp')
@@ -1518,15 +1517,15 @@ def qdump__QRegion(d, value):
if d_ptr == 0: if d_ptr == 0:
d.putSpecialValue('empty') d.putSpecialValue('empty')
else: else:
if d.qtVersion() >= 0x060000: if d.qtVersionAtLeast(0x060000):
ref, _, rgn = d.split('i@p', d_ptr) ref, _, rgn = d.split('i@p', d_ptr)
numRects, innerArea, rects, extents, innerRect = \ numRects, innerArea, rects, extents, innerRect = \
d.split('ii{@QList<@QRect>}{@QRect}{@QRect}', rgn) 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) ref, _, rgn = d.split('i@p', d_ptr)
numRects, innerArea, rects, extents, innerRect = \ numRects, innerArea, rects, extents, innerRect = \
d.split('ii{@QVector<@QRect>}{@QRect}{@QRect}', rgn) d.split('ii{@QVector<@QRect>}{@QRect}{@QRect}', rgn)
elif d.qtVersion() >= 0x050000: elif d.qtVersionAtLeast(0x050000):
ref, _, rgn = d.split('i@p', d_ptr) ref, _, rgn = d.split('i@p', d_ptr)
numRects, _, rects, extents, innerRect, innerArea = \ numRects, _, rects, extents, innerRect, innerArea = \
d.split('i@{@QVector<@QRect>}{@QRect}{@QRect}i', rgn) d.split('i@{@QVector<@QRect>}{@QRect}{@QRect}i', rgn)
@@ -1564,7 +1563,7 @@ def qdump__QScopedPointer(d, value):
def qdump__QSet(d, value): def qdump__QSet(d, value):
if d.qtVersion() >= 0x060000: if d.qtVersionAtLeast(0x060000):
qdumpHelper_QSet6(d, value) qdumpHelper_QSet6(d, value)
else: else:
qdumpHelper_QSet45(d, value) qdumpHelper_QSet45(d, value)
@@ -1637,7 +1636,7 @@ def qdumpHelper_QSet45(d, value):
d.putItemCount(length) d.putItemCount(length)
if d.isExpanded(): if d.isExpanded():
keyType = value.type[0] 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): with Children(d, length, childType=keyType):
node = hashDataFirstNode() node = hashDataFirstNode()
for i in d.childRange(): for i in d.childRange():
@@ -1714,7 +1713,7 @@ def qform__QStack():
def qdump__QStack(d, value): def qdump__QStack(d, value):
if d.qtVersion() >= 0x60000: if d.qtVersionAtLeast(0x060000):
qdump__QList(d, value) qdump__QList(d, value)
else: else:
qdump__QVector(d, value) qdump__QVector(d, value)
@@ -1734,7 +1733,7 @@ def qdump__QPolygon(d, value):
def qdump__QGraphicsPolygonItem(d, value): def qdump__QGraphicsPolygonItem(d, value):
(vtbl, dptr) = value.split('pp') (vtbl, dptr) = value.split('pp')
if d.qtVersion() >= 0x060000: if d.qtVersionAtLeast(0x060000):
if d.ptrSize() == 8: if d.ptrSize() == 8:
offset = 424 # sizeof(QGraphicsPolygonItemPrivate), the base offset = 424 # sizeof(QGraphicsPolygonItemPrivate), the base
else: else:
@@ -1764,6 +1763,7 @@ def qform__QString():
def qdump__QString(d, value): def qdump__QString(d, value):
d.qtVersionPing(value.typeid)
d.putStringValue(value) d.putStringValue(value)
data, length, _ = d.stringData(value) data, length, _ = d.stringData(value)
displayFormat = d.currentItemFormat() displayFormat = d.currentItemFormat()
@@ -1924,7 +1924,7 @@ def qdump__QUrl(d, value):
d.putValue('<invalid>') d.putValue('<invalid>')
return return
if d.qtVersion() < 0x050000: if not d.qtVersionAtLeast(0x050000):
d.call('void', value, 'port') # Warm up internal cache. d.call('void', value, 'port') # Warm up internal cache.
d.call('void', value, 'path') d.call('void', value, 'path')
st = '{@QString}' st = '{@QString}'
@@ -2154,7 +2154,8 @@ qdumpHelper_QVariants_F = [
def qdump__QVariant(d, value): def qdump__QVariant(d, value):
if d.qtVersion() >= 0x060000: d.qtVersionPing(value.typeid, 2 * d.ptrSize())
if d.qtVersionAtLeast(0x060000):
qdumpHelper__QVariant6(d, value) qdumpHelper__QVariant6(d, value)
else: else:
qdumpHelper__QVariant45(d, value) qdumpHelper__QVariant45(d, value)
@@ -2208,12 +2209,12 @@ def qdumpHelper__QVariant45(d, value):
return None return None
# Extended Core type (Qt 5) # 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) qdumpHelper_QVariants_D[variantType - 31](d, value)
return None return None
# Extended Core type (Qt 4) # 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: if variantType == 128:
d.putBetterType('@QVariant (void *)') d.putBetterType('@QVariant (void *)')
d.putValue('0x%x' % value.extractPointer()) d.putValue('0x%x' % value.extractPointer())
@@ -2234,7 +2235,7 @@ def qdumpHelper__QVariant45(d, value):
innert = qdumpHelper_QVariants_B[variantType - 7] innert = qdumpHelper_QVariants_B[variantType - 7]
elif variantType <= 74: elif variantType <= 74:
innert = qdumpHelper_QVariants_E[variantType - 64] innert = qdumpHelper_QVariants_E[variantType - 64]
elif d.qtVersion() < 0x050000: elif not d.qtVersionAtLeast(0x050000):
innert = qdumpHelper_QVariants_F[variantType - 76] innert = qdumpHelper_QVariants_F[variantType - 76]
else: else:
innert = qdumpHelper_QVariants_F[variantType - 75] innert = qdumpHelper_QVariants_F[variantType - 75]
@@ -2308,7 +2309,8 @@ def qform__QVector():
def qdump__QVector(d, value): def qdump__QVector(d, value):
if d.qtVersion() >= 0x060000: d.qtVersionPing(value.typeid)
if d.qtVersionAtLeast(0x060000):
data, length = d.listData(value) data, length = d.listData(value)
d.putItemCount(length) d.putItemCount(length)
d.putPlotData(data, length, value.type.target()[0]) d.putPlotData(data, length, value.type.target()[0])
@@ -2330,7 +2332,7 @@ if False:
def qdump__QVarLengthArray(d, value): def qdump__QVarLengthArray(d, value):
if d.qtVersion() >= 0x060000: if d.qtVersionAtLeast(0x060000):
cap, length, data = value.split('QQp') cap, length, data = value.split('QQp')
else: else:
cap, length, data = value.split('iip') cap, length, data = value.split('iip')
@@ -2366,7 +2368,7 @@ def qdump_QWeakPointerHelper(d, value, isWeak, innerType=None):
d.putValue('<invalid>') d.putValue('<invalid>')
return return
if d.qtVersion() >= 0x050000: if d.qtVersionAtLeast(0x050000):
(weakref, strongref) = d.split('ii', d_ptr) (weakref, strongref) = d.split('ii', d_ptr)
else: else:
(vptr, weakref, strongref) = d.split('pii', d_ptr) (vptr, weakref, strongref) = d.split('pii', d_ptr)
@@ -2872,7 +2874,7 @@ def qdump__QJSValue(d, value):
if d.ptrSize() == 4: if d.ptrSize() == 4:
qdump_32__QJSValue(d, value) qdump_32__QJSValue(d, value)
else: else:
if d.qtVersion() >= 0x60000: if d.qtVersionAtLeast(0x060000):
qdump_64__QJSValue_6(d, value) qdump_64__QJSValue_6(d, value)
else: else:
qdump_64__QJSValue_5(d, value) qdump_64__QJSValue_5(d, value)
@@ -2906,7 +2908,7 @@ def qdump_64__QJSValue_6(d, value):
if dd == 0: if dd == 0:
d.putValue('(undefined)') d.putValue('(undefined)')
d.putType(value.type.name + ' (undefined)') d.putType(value.type.name + ' (undefined)')
if d.qtVersion() < 0x60500: if not d.qtVersionAtLeast(0x60500):
typ = dd >> 47 typ = dd >> 47
if typ == 5: if typ == 5:
d.putValue('(null)') d.putValue('(null)')
@@ -3326,7 +3328,7 @@ def qdumpHelper_QJsonObject(d, data, obj):
def qdump__QJsonValue(d, value): def qdump__QJsonValue(d, value):
(data, dd, t) = value.split('QpI') (data, dd, t) = value.split('QpI')
if d.qtVersion() >= 0x050f00: if d.qtVersionAtLeast(0x050f00):
value = d.createProxyValue((data, dd, t, False), 'QCborValue_proxy') value = d.createProxyValue((data, dd, t, False), 'QCborValue_proxy')
d.putItem(value) d.putItem(value)
return return
@@ -3361,13 +3363,13 @@ def qdump__QJsonValue(d, value):
def qdump__QJsonArray(d, value): def qdump__QJsonArray(d, value):
if d.qtVersion() >= 0x060000: if d.qtVersionAtLeast(0x060000):
dptr = d.extractPointer(value) dptr = d.extractPointer(value)
if not dptr: if not dptr:
d.putItemCount(0) d.putItemCount(0)
else: else:
qdumpHelper_QCbor_array(d, dptr, False) qdumpHelper_QCbor_array(d, dptr, False)
elif d.qtVersion() >= 0x050f00: elif d.qtVersionAtLeast(0x050f00):
_, container_ptr = value.split('pp') _, container_ptr = value.split('pp')
qdumpHelper_QCbor_array(d, container_ptr, False) qdumpHelper_QCbor_array(d, container_ptr, False)
else: else:
@@ -3375,13 +3377,13 @@ def qdump__QJsonArray(d, value):
def qdump__QJsonObject(d, value): def qdump__QJsonObject(d, value):
if d.qtVersion() >= 0x060000: if d.qtVersionAtLeast(0x060000):
dptr = d.extractPointer(value) dptr = d.extractPointer(value)
if not dptr: if not dptr:
d.putItemCount(0) d.putItemCount(0)
else: else:
qdumpHelper_QCbor_map(d, dptr, False) qdumpHelper_QCbor_map(d, dptr, False)
elif d.qtVersion() >= 0x050f00: elif d.qtVersionAtLeast(0x050f00):
_, container_ptr = value.split('pp') _, container_ptr = value.split('pp')
qdumpHelper_QCbor_map(d, container_ptr, False) qdumpHelper_QCbor_map(d, container_ptr, False)
else: else:
@@ -3456,15 +3458,15 @@ def qdump__qfloat16(d, value):
def qdumpHelper_QCbor_string(d, container_ptr, element_index, is_bytes): 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, # d.split('i@{@QByteArray::size_type}pp', container_ptr) doesn't work with CDB,
# so be explicit: # so be explicit:
data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersion() >= 0x060000 else 8) data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else 8)
elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersion() >= 0x060000 else d.ptrSize()) elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else d.ptrSize())
elements_data_ptr, elements_size = d.vectorData(elements_pos) elements_data_ptr, elements_size = d.vectorData(elements_pos)
element_at_n_addr = elements_data_ptr + element_index * 16 # sizeof(QtCbor::Element) == 16 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) element_value, _, element_flags = d.split('qII', element_at_n_addr)
enc = 'latin1' if is_bytes or (element_flags & 8) else 'utf16' enc = 'latin1' if is_bytes or (element_flags & 8) else 'utf16'
bytedata, _, _ = d.qArrayData(data_pos) bytedata, _, _ = d.qArrayData(data_pos)
bytedata += element_value bytedata += element_value
if d.qtVersion() >= 0x060000: if d.qtVersionAtLeast(0x060000):
bytedata_len = d.extractInt64(bytedata) bytedata_len = d.extractInt64(bytedata)
bytedata_data = bytedata + 8 bytedata_data = bytedata + 8
else: else:
@@ -3493,8 +3495,8 @@ def qdumpHelper_QCbor_array(d, container_ptr, is_cbor):
return return
# d.split('i@{@QByteArray::size_type}pp', container_ptr) doesn't work with CDB, # d.split('i@{@QByteArray::size_type}pp', container_ptr) doesn't work with CDB,
# so be explicit: # so be explicit:
data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersion() >= 0x060000 else 8) data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else 8)
elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersion() >= 0x060000 else d.ptrSize()) elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else d.ptrSize())
elements_data_ptr, elements_size = d.vectorData(elements_pos) elements_data_ptr, elements_size = d.vectorData(elements_pos)
d.putItemCount(elements_size) d.putItemCount(elements_size)
if d.isExpanded(): if d.isExpanded():
@@ -3515,8 +3517,8 @@ def qdumpHelper_QCbor_map(d, container_ptr, is_cbor):
return return
# d.split('i@{@QByteArray::size_type}pp', container_ptr) doesn't work with CDB, # d.split('i@{@QByteArray::size_type}pp', container_ptr) doesn't work with CDB,
# so be explicit: # so be explicit:
data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersion() >= 0x060000 else 8) data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else 8)
elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersion() >= 0x060000 else d.ptrSize()) elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else d.ptrSize())
elements_data_ptr, elements_size = d.vectorData(elements_pos) elements_data_ptr, elements_size = d.vectorData(elements_pos)
elements_size = int(elements_size / 2) elements_size = int(elements_size / 2)
d.putItemCount(elements_size) d.putItemCount(elements_size)

View File

@@ -844,11 +844,9 @@ Utils::expected_str<void> PluginSpecPrivate::readMetaData(const QJsonObject &dat
value = metaData.value(QLatin1String(PLUGIN_DISABLED_BY_DEFAULT)); value = metaData.value(QLatin1String(PLUGIN_DISABLED_BY_DEFAULT));
if (!value.isUndefined() && !value.isBool()) if (!value.isUndefined() && !value.isBool())
return reportError(msgValueIsNotABool(PLUGIN_DISABLED_BY_DEFAULT)); return reportError(msgValueIsNotABool(PLUGIN_DISABLED_BY_DEFAULT));
enabledByDefault = !value.toBool(false); enabledByDefault = !value.toBool(experimental || deprecated);
qCDebug(pluginLog) << "enabledByDefault =" << enabledByDefault; qCDebug(pluginLog) << "enabledByDefault =" << enabledByDefault;
if (experimental || deprecated)
enabledByDefault = false;
enabledBySettings = enabledByDefault; enabledBySettings = enabledByDefault;
value = metaData.value(QLatin1String(PLUGIN_SOFTLOADABLE)); value = metaData.value(QLatin1String(PLUGIN_SOFTLOADABLE));

View File

@@ -261,6 +261,12 @@ DocumentHighlightsResult::DocumentHighlightsResult(const QJsonValue &value)
} }
} }
template<>
MarkedString fromJsonValue<MarkedString>(const QJsonValue &value)
{
return MarkedString(value);
}
MarkedString::MarkedString(const QJsonValue &value) MarkedString::MarkedString(const QJsonValue &value)
{ {
if (value.isObject()) if (value.isObject())

View File

@@ -52,6 +52,9 @@ public:
operator QJsonValue() const; operator QJsonValue() const;
}; };
template<>
LANGUAGESERVERPROTOCOL_EXPORT MarkedString fromJsonValue<MarkedString>(const QJsonValue &value);
class LANGUAGESERVERPROTOCOL_EXPORT HoverContent class LANGUAGESERVERPROTOCOL_EXPORT HoverContent
: public std::variant<MarkedString, QList<MarkedString>, MarkupContent> : public std::variant<MarkedString, QList<MarkedString>, MarkupContent>
{ {

View File

@@ -68,7 +68,7 @@ public:
if (value.isArray()) { if (value.isArray()) {
QList<T> values; QList<T> values;
values.reserve(value.toArray().count()); values.reserve(value.toArray().count());
for (auto arrayValue : value.toArray()) for (const auto &arrayValue : value.toArray())
values << fromJsonValue<T>(arrayValue); values << fromJsonValue<T>(arrayValue);
*this = values; *this = values;
} else { } else {

View File

@@ -24,7 +24,7 @@ void Barrier::start()
{ {
QT_ASSERT(!isRunning(), return); QT_ASSERT(!isRunning(), return);
m_current = 0; m_current = 0;
m_result = {}; m_result.reset();
} }
void Barrier::advance() void Barrier::advance()

View File

@@ -1450,6 +1450,11 @@ ExecutableItem ExecutableItem::withTimeout(milliseconds timeout,
static QString currentTime() { return QTime::currentTime().toString(Qt::ISODateWithMs); } 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, 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. 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 ExecutableItem ExecutableItem::withLog(const QString &logName) const
{ {
const auto header = [logName] {
return QString::fromLatin1("TASK TREE LOG [%1] \"%2\"").arg(currentTime(), logName);
};
struct LogStorage struct LogStorage
{ {
time_point<system_clock, nanoseconds> start; time_point<system_clock, nanoseconds> start;
@@ -1474,21 +1476,22 @@ ExecutableItem ExecutableItem::withLog(const QString &logName) const
const Storage<LogStorage> storage; const Storage<LogStorage> storage;
return Group { return Group {
storage, storage,
onGroupSetup([storage, header] { onGroupSetup([storage, logName] {
storage->start = system_clock::now(); storage->start = system_clock::now();
storage->asyncCount = activeTaskTree()->asyncCount(); storage->asyncCount = activeTaskTree()->asyncCount();
qDebug().noquote() << header() << "started."; qDebug().noquote().nospace() << logHeader(logName) << " started.";
}), }),
*this, *this,
onGroupDone([storage, header](DoneWith result) { onGroupDone([storage, logName](DoneWith result) {
const auto elapsed = duration_cast<milliseconds>(system_clock::now() - storage->start); const auto elapsed = duration_cast<milliseconds>(system_clock::now() - storage->start);
const int asyncCountDiff = activeTaskTree()->asyncCount() - storage->asyncCount; const int asyncCountDiff = activeTaskTree()->asyncCount() - storage->asyncCount;
QT_CHECK(asyncCountDiff >= 0); QT_CHECK(asyncCountDiff >= 0);
const QMetaEnum doneWithEnum = QMetaEnum::fromType<DoneWith>(); const QMetaEnum doneWithEnum = QMetaEnum::fromType<DoneWith>();
const QString syncType = asyncCountDiff ? QString::fromLatin1("asynchronously") const QString syncType = asyncCountDiff ? QString::fromLatin1("asynchronously")
: QString::fromLatin1("synchronously"); : QString::fromLatin1("synchronously");
qDebug().noquote().nospace() << header() << " finished " << syncType << " with " qDebug().noquote().nospace() << logHeader(logName) << " finished " << syncType
<< doneWithEnum.valueToKey(int(result)) << " within " << elapsed.count() << "ms."; << " with " << doneWithEnum.valueToKey(int(result))
<< " within " << elapsed.count() << "ms.";
}) })
}; };
} }
@@ -3383,7 +3386,7 @@ TimeoutTaskAdapter::~TimeoutTaskAdapter()
void TimeoutTaskAdapter::start() void TimeoutTaskAdapter::start()
{ {
m_timerId = scheduleTimeout(*task(), this, [this] { m_timerId = scheduleTimeout(*task(), this, [this] {
m_timerId = {}; m_timerId.reset();
emit done(DoneResult::Success); emit done(DoneResult::Success);
}); });
} }

View File

@@ -29,23 +29,6 @@ QTCREATOR_UTILS_EXPORT QString fileNameToCppIdentifier(const QString &s)
return rc; 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 QTCREATOR_UTILS_EXPORT
void writeIncludeFileDirective(const QString &file, bool globalInclude, void writeIncludeFileDirective(const QString &file, bool globalInclude,
QTextStream &str) QTextStream &str)

View File

@@ -17,9 +17,6 @@ namespace Utils {
// or replacing them by an underscore). // or replacing them by an underscore).
QTCREATOR_UTILS_EXPORT QString fileNameToCppIdentifier(const QString &s); 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 QTCREATOR_UTILS_EXPORT
void writeIncludeFileDirective(const QString &file, void writeIncludeFileDirective(const QString &file,
bool globalInclude, bool globalInclude,

View File

@@ -3,6 +3,7 @@
"Version" : "${IDE_VERSION}", "Version" : "${IDE_VERSION}",
"CompatVersion" : "${IDE_VERSION_COMPAT}", "CompatVersion" : "${IDE_VERSION_COMPAT}",
"Experimental" : true, "Experimental" : true,
"DisabledByDefault" : ${APPSTATISTICSMONITOR_DISABLEDBYDEFAULT},
"Vendor" : "The Qt Company Ltd", "Vendor" : "The Qt Company Ltd",
"Copyright" : "(C) ${IDE_COPYRIGHT_YEAR} The Qt Company Ltd", "Copyright" : "(C) ${IDE_COPYRIGHT_YEAR} The Qt Company Ltd",
"License" : [ "Commercial Usage", "License" : [ "Commercial Usage",

View File

@@ -13,6 +13,8 @@ set(CMAKE_CXX_EXTENSIONS OFF)
find_package(Qt6 COMPONENTS Charts QUIET) find_package(Qt6 COMPONENTS Charts QUIET)
set(APPSTATISTICSMONITOR_DISABLEDBYDEFAULT "true")
if (NOT QT_CREATOR_API_DEFINED) if (NOT QT_CREATOR_API_DEFINED)
# standalone build # standalone build
set(DESTINATION DESTINATION .) set(DESTINATION DESTINATION .)
@@ -21,6 +23,8 @@ if (NOT QT_CREATOR_API_DEFINED)
qtc_handle_compiler_cache_support() qtc_handle_compiler_cache_support()
find_package(QtCreator COMPONENTS Core ProjectExplorer Utils REQUIRED) find_package(QtCreator COMPONENTS Core ProjectExplorer Utils REQUIRED)
set(APPSTATISTICSMONITOR_DISABLEDBYDEFAULT "false")
endif() endif()

View File

@@ -51,6 +51,8 @@ using namespace Utils;
namespace Axivion::Internal { namespace Axivion::Internal {
void showIssuesFromDashboard(const QString &kind); // impl at bottom
class DashboardWidget : public QScrollArea class DashboardWidget : public QScrollArea
{ {
public: public:
@@ -147,14 +149,24 @@ void DashboardWidget::updateUi()
} }
return prefix; 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("<a href='%1'>%2</a>").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); const QString currentToolTip = toolTip(issueKind);
QLabel *label = new QLabel(issueKind, this); QLabel *label = new QLabel(issueKind, this);
label->setToolTip(currentToolTip); label->setToolTip(currentToolTip);
m_gridLayout->addWidget(label, row, 0); 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->setToolTip(currentToolTip);
label->setAlignment(Qt::AlignRight); label->setAlignment(Qt::AlignRight);
if (link) {
connect(label, &QLabel::linkActivated, this, [](const QString &issueKind) {
showIssuesFromDashboard(issueKind);
});
}
m_gridLayout->addWidget(label, row, 1); m_gridLayout->addWidget(label, row, 1);
label = new QLabel(this); label = new QLabel(this);
label->setPixmap(trendIcon(added, removed)); label->setPixmap(trendIcon(added, removed));
@@ -190,12 +202,12 @@ void DashboardWidget::updateUi()
allAdded += added; allAdded += added;
qint64 removed = extract_value(counts, QStringLiteral("Removed")); qint64 removed = extract_value(counts, QStringLiteral("Removed"));
allRemoved += removed; allRemoved += removed;
addValuesWidgets(issueCount.first, total, added, removed, row); addValuesWidgets(issueCount.first, total, added, removed, row, true);
++row; ++row;
} }
} }
} }
addValuesWidgets(Tr::tr("Total:"), allTotal, allAdded, allRemoved, row); addValuesWidgets(Tr::tr("Total:"), allTotal, allAdded, allRemoved, row, false);
} }
struct LinkWithColumns struct LinkWithColumns
@@ -263,7 +275,7 @@ class IssuesWidget : public QScrollArea
{ {
public: public:
explicit IssuesWidget(QWidget *parent = nullptr); explicit IssuesWidget(QWidget *parent = nullptr);
void updateUi(); void updateUi(const QString &kind);
const std::optional<Dto::TableInfoDto> currentTableInfo() const { return m_currentTableInfo; } const std::optional<Dto::TableInfoDto> currentTableInfo() const { return m_currentTableInfo; }
IssueListSearch searchFromUi() const; IssueListSearch searchFromUi() const;
@@ -378,7 +390,7 @@ IssuesWidget::IssuesWidget(QWidget *parent)
setWidgetResizable(true); setWidgetResizable(true);
} }
void IssuesWidget::updateUi() void IssuesWidget::updateUi(const QString &kind)
{ {
setFiltersEnabled(false); setFiltersEnabled(false);
const std::optional<Dto::ProjectInfoDto> projectInfo = Internal::projectInfo(); const std::optional<Dto::ProjectInfoDto> projectInfo = Internal::projectInfo();
@@ -392,11 +404,30 @@ void IssuesWidget::updateUi()
setFiltersEnabled(true); setFiltersEnabled(true);
// avoid refetching existing data // avoid refetching existing data
if (!m_currentPrefix.isEmpty() || m_issuesModel->rowCount()) if (kind.isEmpty() && (!m_currentPrefix.isEmpty() || m_issuesModel->rowCount()))
return; return;
if (info.issueKinds.size()) if (!kind.isEmpty()) {
m_currentPrefix = info.issueKinds.front().prefix; 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(); fetchTable();
} }
@@ -767,12 +798,7 @@ public:
m_showIssues->setIcon(Icons::ZOOM_TOOLBAR.icon()); m_showIssues->setIcon(Icons::ZOOM_TOOLBAR.icon());
m_showIssues->setToolTip(Tr::tr("Search for issues")); m_showIssues->setToolTip(Tr::tr("Search for issues"));
m_showIssues->setCheckable(true); m_showIssues->setCheckable(true);
connect(m_showIssues, &QToolButton::clicked, this, [this] { connect(m_showIssues, &QToolButton::clicked, this, [this] { handleShowIssues({}); });
QTC_ASSERT(m_outputWidget, return);
m_outputWidget->setCurrentIndex(1);
if (auto issues = static_cast<IssuesWidget *>(m_outputWidget->widget(1)))
issues->updateUi();
});
auto *butonGroup = new QButtonGroup(this); auto *butonGroup = new QButtonGroup(this);
butonGroup->addButton(m_showDashboard); butonGroup->addButton(m_showDashboard);
butonGroup->addButton(m_showIssues); butonGroup->addButton(m_showIssues);
@@ -814,6 +840,14 @@ public:
void goToNext() final {} void goToNext() final {}
void goToPrev() final {} void goToPrev() final {}
void handleShowIssues(const QString &kind)
{
QTC_ASSERT(m_outputWidget, return);
m_outputWidget->setCurrentIndex(1);
if (auto issues = static_cast<IssuesWidget *>(m_outputWidget->widget(1)))
issues->updateUi(kind);
}
void updateDashboard() void updateDashboard()
{ {
if (auto dashboard = static_cast<DashboardWidget *>(m_outputWidget->widget(0))) { if (auto dashboard = static_cast<DashboardWidget *>(m_outputWidget->widget(0))) {
@@ -897,4 +931,10 @@ static bool issueListContextMenuEvent(const ItemViewEvent &ev)
return theAxivionOutputPane->handleContextMenu(issue, ev); return theAxivionOutputPane->handleContextMenu(issue, ev);
} }
void showIssuesFromDashboard(const QString &kind)
{
QTC_ASSERT(theAxivionOutputPane, return);
theAxivionOutputPane->handleShowIssues(kind);
}
} // Axivion::Internal } // Axivion::Internal

View File

@@ -474,11 +474,10 @@ ClangTool::ClangTool(const QString &name, Id id, ClangToolType type)
// Expand/Collapse // Expand/Collapse
action = new QAction(this); action = new QAction(this);
action->setDisabled(true);
action->setCheckable(true); action->setCheckable(true);
action->setIcon(Utils::Icons::EXPAND_ALL_TOOLBAR.icon()); action->setIcon(Utils::Icons::EXPAND_ALL_TOOLBAR.icon());
action->setToolTip(Tr::tr("Expand All")); m_expandCollapse = action;
connect(action, &QAction::toggled, this, [this](bool checked){ const auto handleCollapseExpandToggled = [this](bool checked){
if (checked) { if (checked) {
m_expandCollapse->setToolTip(Tr::tr("Collapse All")); m_expandCollapse->setToolTip(Tr::tr("Collapse All"));
m_diagnosticView->expandAll(); m_diagnosticView->expandAll();
@@ -486,8 +485,9 @@ ClangTool::ClangTool(const QString &name, Id id, ClangToolType type)
m_expandCollapse->setToolTip(Tr::tr("Expand All")); m_expandCollapse->setToolTip(Tr::tr("Expand All"));
m_diagnosticView->collapseAll(); m_diagnosticView->collapseAll();
} }
}); };
m_expandCollapse = action; connect(action, &QAction::toggled, this, handleCollapseExpandToggled);
handleCollapseExpandToggled(action->isChecked());
// Filter button // Filter button
action = m_showFilter = new QAction(this); action = m_showFilter = new QAction(this);
@@ -1242,8 +1242,32 @@ QSet<Diagnostic> ClangTool::diagnostics() const
void ClangTool::onNewDiagnosticsAvailable(const Diagnostics &diagnostics, bool generateMarks) 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); 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() void ClangTool::updateForCurrentState()
@@ -1273,7 +1297,6 @@ void ClangTool::updateForCurrentState()
m_goBack->setEnabled(issuesVisible > 0); m_goBack->setEnabled(issuesVisible > 0);
m_goNext->setEnabled(issuesVisible > 0); m_goNext->setEnabled(issuesVisible > 0);
m_clear->setEnabled(!isRunning); m_clear->setEnabled(!isRunning);
m_expandCollapse->setEnabled(issuesVisible);
m_loadExported->setEnabled(!isRunning); m_loadExported->setEnabled(!isRunning);
m_showFilter->setEnabled(issuesFound > 1); m_showFilter->setEnabled(issuesFound > 1);

View File

@@ -10,6 +10,7 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <cppeditor/clangdiagnosticconfigsmodel.h> #include <cppeditor/clangdiagnosticconfigsmodel.h>
#include <cppeditor/compileroptionsbuilder.h>
#include <cppeditor/cppcodemodelsettings.h> #include <cppeditor/cppcodemodelsettings.h>
#include <cppeditor/cppprojectfile.h> #include <cppeditor/cppprojectfile.h>
#include <cppeditor/cpptoolsreuse.h> #include <cppeditor/cpptoolsreuse.h>

View File

@@ -34,7 +34,6 @@
#include <projectexplorer/devicesupport/idevice.h> #include <projectexplorer/devicesupport/idevice.h>
#include <projectexplorer/environmentaspectwidget.h> #include <projectexplorer/environmentaspectwidget.h>
#include <projectexplorer/environmentwidget.h> #include <projectexplorer/environmentwidget.h>
#include <projectexplorer/gcctoolchain.h>
#include <projectexplorer/kitaspects.h> #include <projectexplorer/kitaspects.h>
#include <projectexplorer/namedwidget.h> #include <projectexplorer/namedwidget.h>
#include <projectexplorer/processparameters.h> #include <projectexplorer/processparameters.h>
@@ -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::toArgumentsList(k));
cmd.addArgs(CMakeConfigurationKitAspect::additionalConfiguration(k), CommandLine::Raw); cmd.addArgs(CMakeConfigurationKitAspect::additionalConfiguration(k), CommandLine::Raw);
@@ -1356,7 +1331,7 @@ static void addCMakeConfigurePresetToInitialArguments(QStringList &initialArgume
if (argFilePath != presetFilePath) if (argFilePath != presetFilePath)
arg = presetItem.toArgument(); 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) // Append the preset value with at the initial parameters value (e.g. QML Debugging)
if (argItem.expandedValue(k) != QString::fromUtf8(presetItem.value)) { if (argItem.expandedValue(k) != QString::fromUtf8(presetItem.value)) {
argItem.value.append(" "); argItem.value.append(" ");

View File

@@ -227,7 +227,7 @@ void CppEditorPlugin::initialize()
void CppEditorPlugin::extensionsInitialized() void CppEditorPlugin::extensionsInitialized()
{ {
setupCppQuickFixProjectPanel(); setupCppQuickFixProjectPanel();
setupCppFileSettings(); setupCppFileSettings(*this);
setupCppCodeModelProjectSettingsPanel(); setupCppCodeModelProjectSettingsPanel();
if (CppModelManager::isClangCodeModelActive()) { if (CppModelManager::isClangCodeModelActive()) {

View File

@@ -6,15 +6,19 @@
#include "cppeditortr.h" #include "cppeditortr.h"
#include "cppheadersource.h" #include "cppheadersource.h"
#include <extensionsystem/iplugin.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <projectexplorer/project.h> #include <projectexplorer/project.h>
#include <projectexplorer/projectpanelfactory.h> #include <projectexplorer/projectpanelfactory.h>
#include <utils/aspects.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/layoutbuilder.h> #include <utils/layoutbuilder.h>
#include <utils/macroexpander.h>
#include <utils/mimeconstants.h> #include <utils/mimeconstants.h>
#include <utils/mimeutils.h> #include <utils/mimeutils.h>
#include <utils/pathchooser.h> #include <utils/pathchooser.h>
@@ -29,10 +33,30 @@
#include <QTextStream> #include <QTextStream>
#include <QVBoxLayout> #include <QVBoxLayout>
#ifdef WITH_TESTS
#include <QtTest>
#endif
using namespace ProjectExplorer; using namespace ProjectExplorer;
using namespace Utils; using namespace Utils;
namespace CppEditor::Internal { 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 projectSettingsKeyC[] = "CppEditorFileNames";
const char useGlobalKeyC[] = "UseGlobal"; const char useGlobalKeyC[] = "UseGlobal";
@@ -44,6 +68,7 @@ const char headerSearchPathsKeyC[] = "HeaderSearchPaths";
const char sourceSearchPathsKeyC[] = "SourceSearchPaths"; const char sourceSearchPathsKeyC[] = "SourceSearchPaths";
const char headerPragmaOnceC[] = "HeaderPragmaOnce"; const char headerPragmaOnceC[] = "HeaderPragmaOnce";
const char licenseTemplatePathKeyC[] = "LicenseTemplate"; const char licenseTemplatePathKeyC[] = "LicenseTemplate";
const char headerGuardTemplateKeyC[] = "HeaderGuardTemplate";
const char *licenseTemplateTemplate = QT_TRANSLATE_NOOP("QtC::CppEditor", const char *licenseTemplateTemplate = QT_TRANSLATE_NOOP("QtC::CppEditor",
"/**************************************************************************\n" "/**************************************************************************\n"
@@ -67,6 +92,7 @@ void CppFileSettings::toSettings(QtcSettings *s) const
s->setValueWithDefault(headerPragmaOnceC, headerPragmaOnce, def.headerPragmaOnce); s->setValueWithDefault(headerPragmaOnceC, headerPragmaOnce, def.headerPragmaOnce);
s->setValueWithDefault(licenseTemplatePathKeyC, licenseTemplatePath.toSettings(), s->setValueWithDefault(licenseTemplatePathKeyC, licenseTemplatePath.toSettings(),
def.licenseTemplatePath.toSettings()); def.licenseTemplatePath.toSettings());
s->setValueWithDefault(headerGuardTemplateKeyC, headerGuardTemplate, def.headerGuardTemplate);
s->endGroup(); s->endGroup();
} }
@@ -84,6 +110,7 @@ void CppFileSettings::fromSettings(QtcSettings *s)
headerPragmaOnce = s->value(headerPragmaOnceC, def.headerPragmaOnce).toBool(); headerPragmaOnce = s->value(headerPragmaOnceC, def.headerPragmaOnce).toBool();
licenseTemplatePath = FilePath::fromSettings(s->value(licenseTemplatePathKeyC, licenseTemplatePath = FilePath::fromSettings(s->value(licenseTemplatePathKeyC,
def.licenseTemplatePath.toSettings())); def.licenseTemplatePath.toSettings()));
headerGuardTemplate = s->value(headerGuardTemplateKeyC, def.headerGuardTemplate).toString();
s->endGroup(); s->endGroup();
} }
@@ -124,6 +151,7 @@ bool CppFileSettings::equals(const CppFileSettings &rhs) const
&& sourceSuffix == rhs.sourceSuffix && sourceSuffix == rhs.sourceSuffix
&& headerSearchPaths == rhs.headerSearchPaths && headerSearchPaths == rhs.headerSearchPaths
&& sourceSearchPaths == rhs.sourceSearchPaths && sourceSearchPaths == rhs.sourceSearchPaths
&& headerGuardTemplate == rhs.headerGuardTemplate
&& licenseTemplatePath == rhs.licenseTemplatePath; && licenseTemplatePath == rhs.licenseTemplatePath;
} }
@@ -237,6 +265,11 @@ QString CppFileSettings::licenseTemplate() const
return license; return license;
} }
QString CppFileSettings::headerGuard(const Utils::FilePath &headerFilePath) const
{
return HeaderGuardExpander(headerFilePath).expand(headerGuardTemplate);
}
// ------------------ CppFileSettingsWidget // ------------------ CppFileSettingsWidget
class CppFileSettingsWidget final : public Core::IOptionsPageWidget class CppFileSettingsWidget final : public Core::IOptionsPageWidget
@@ -269,6 +302,8 @@ private:
QLineEdit *m_sourcePrefixesEdit = nullptr; QLineEdit *m_sourcePrefixesEdit = nullptr;
QCheckBox *m_lowerCaseFileNamesCheckBox = nullptr; QCheckBox *m_lowerCaseFileNamesCheckBox = nullptr;
PathChooser *m_licenseTemplatePathChooser = nullptr; PathChooser *m_licenseTemplatePathChooser = nullptr;
StringAspect m_headerGuardAspect;
HeaderGuardExpander m_headerGuardExpander{{}};
}; };
CppFileSettingsWidget::CppFileSettingsWidget(CppFileSettings *settings) CppFileSettingsWidget::CppFileSettingsWidget(CppFileSettings *settings)
@@ -276,7 +311,7 @@ CppFileSettingsWidget::CppFileSettingsWidget(CppFileSettings *settings)
, m_headerSuffixComboBox(new QComboBox) , m_headerSuffixComboBox(new QComboBox)
, m_headerSearchPathsEdit(new QLineEdit) , m_headerSearchPathsEdit(new QLineEdit)
, m_headerPrefixesEdit(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_sourceSuffixComboBox(new QComboBox)
, m_sourceSearchPathsEdit(new QLineEdit) , m_sourceSearchPathsEdit(new QLineEdit)
, m_sourcePrefixesEdit(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" m_sourcePrefixesEdit->setToolTip(Tr::tr("Comma-separated list of source prefixes.\n"
"\n" "\n"
"These prefixes are used in addition to current file name on Switch Header/Source.")); "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; using namespace Layouting;
@@ -311,8 +348,8 @@ CppFileSettingsWidget::CppFileSettingsWidget(CppFileSettings *settings)
Tr::tr("&Suffix:"), m_headerSuffixComboBox, st, br, Tr::tr("&Suffix:"), m_headerSuffixComboBox, st, br,
Tr::tr("S&earch paths:"), m_headerSearchPathsEdit, br, Tr::tr("S&earch paths:"), m_headerSearchPathsEdit, br,
Tr::tr("&Prefixes:"), m_headerPrefixesEdit, br, Tr::tr("&Prefixes:"), m_headerPrefixesEdit, br,
Tr::tr("Include guards"), m_headerPragmaOnceCheckBox Tr::tr("Include guard template:"), m_headerPragmaOnceCheckBox, m_headerGuardAspect
} },
}, },
Group { Group {
title(Tr::tr("Sources")), title(Tr::tr("Sources")),
@@ -361,12 +398,21 @@ CppFileSettingsWidget::CppFileSettingsWidget(CppFileSettings *settings)
this, &CppFileSettingsWidget::userChange); this, &CppFileSettingsWidget::userChange);
connect(m_sourcePrefixesEdit, &QLineEdit::textEdited, connect(m_sourcePrefixesEdit, &QLineEdit::textEdited,
this, &CppFileSettingsWidget::userChange); this, &CppFileSettingsWidget::userChange);
connect(m_headerPragmaOnceCheckBox, &QCheckBox::stateChanged,
this, &CppFileSettingsWidget::userChange);
connect(m_lowerCaseFileNamesCheckBox, &QCheckBox::stateChanged, connect(m_lowerCaseFileNamesCheckBox, &QCheckBox::stateChanged,
this, &CppFileSettingsWidget::userChange); this, &CppFileSettingsWidget::userChange);
connect(m_licenseTemplatePathChooser, &PathChooser::textChanged, connect(m_licenseTemplatePathChooser, &PathChooser::textChanged,
this, &CppFileSettingsWidget::userChange); 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 FilePath CppFileSettingsWidget::licenseTemplatePath() const
@@ -417,6 +463,7 @@ void CppFileSettingsWidget::setSettings(const CppFileSettings &s)
m_headerSearchPathsEdit->setText(s.headerSearchPaths.join(comma)); m_headerSearchPathsEdit->setText(s.headerSearchPaths.join(comma));
m_sourceSearchPathsEdit->setText(s.sourceSearchPaths.join(comma)); m_sourceSearchPathsEdit->setText(s.sourceSearchPaths.join(comma));
setLicenseTemplatePath(s.licenseTemplatePath); setLicenseTemplatePath(s.licenseTemplatePath);
m_headerGuardAspect.setValue(s.headerGuardTemplate);
} }
CppFileSettings CppFileSettingsWidget::currentSettings() const CppFileSettings CppFileSettingsWidget::currentSettings() const
@@ -431,6 +478,7 @@ CppFileSettings CppFileSettingsWidget::currentSettings() const
rc.headerSearchPaths = trimmedPaths(m_headerSearchPathsEdit->text()); rc.headerSearchPaths = trimmedPaths(m_headerSearchPathsEdit->text());
rc.sourceSearchPaths = trimmedPaths(m_sourceSearchPathsEdit->text()); rc.sourceSearchPaths = trimmedPaths(m_sourceSearchPathsEdit->text());
rc.licenseTemplatePath = licenseTemplatePath(); rc.licenseTemplatePath = licenseTemplatePath();
rc.headerGuardTemplate = m_headerGuardAspect.value();
return rc; return rc;
} }
@@ -536,6 +584,8 @@ void CppFileSettingsForProject::loadSettings()
m_customSettings.lowerCaseFiles).toBool(); m_customSettings.lowerCaseFiles).toBool();
m_customSettings.headerPragmaOnce = data.value(headerPragmaOnceC, m_customSettings.headerPragmaOnce = data.value(headerPragmaOnceC,
m_customSettings.headerPragmaOnce).toBool(); m_customSettings.headerPragmaOnce).toBool();
m_customSettings.headerGuardTemplate
= data.value(headerGuardTemplateKeyC, m_customSettings.headerGuardTemplate).toString();
m_customSettings.licenseTemplatePath m_customSettings.licenseTemplatePath
= FilePath::fromSettings(data.value(licenseTemplatePathKeyC, = FilePath::fromSettings(data.value(licenseTemplatePathKeyC,
m_customSettings.licenseTemplatePath.toSettings())); m_customSettings.licenseTemplatePath.toSettings()));
@@ -560,6 +610,7 @@ void CppFileSettingsForProject::saveSettings()
data.insert(sourceSearchPathsKeyC, m_customSettings.sourceSearchPaths); data.insert(sourceSearchPathsKeyC, m_customSettings.sourceSearchPaths);
data.insert(Constants::LOWERCASE_CPPFILES_KEY, m_customSettings.lowerCaseFiles); data.insert(Constants::LOWERCASE_CPPFILES_KEY, m_customSettings.lowerCaseFiles);
data.insert(headerPragmaOnceC, m_customSettings.headerPragmaOnce); data.insert(headerPragmaOnceC, m_customSettings.headerPragmaOnce);
data.insert(headerGuardTemplateKeyC, m_customSettings.headerGuardTemplate);
data.insert(licenseTemplatePathKeyC, m_customSettings.licenseTemplatePath.toSettings()); data.insert(licenseTemplatePathKeyC, m_customSettings.licenseTemplatePath.toSettings());
m_project->setNamedSettings(projectSettingsKeyC, data); 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() CppFileSettings &globalCppFileSettings()
{ {
// This is the global instance. There could be more. // This is the global instance. There could be more.
@@ -653,6 +694,59 @@ CppFileSettings cppFileSettingsForProject(ProjectExplorer::Project *project)
return CppFileSettingsForProject(project).settings(); return CppFileSettingsForProject(project).settings();
} }
#ifdef WITH_TESTS
namespace {
class CppFileSettingsTest : public QObject
{
Q_OBJECT
private slots:
void testHeaderGuard_data()
{
QTest::addColumn<QString>("guardTemplate");
QTest::addColumn<QString>("headerFile");
QTest::addColumn<QString>("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 } // namespace CppEditor::Internal
#include <cppfilesettingspage.moc> #include <cppfilesettingspage.moc>

View File

@@ -9,6 +9,7 @@
#include <QDir> #include <QDir>
namespace ExtensionSystem { class IPlugin; }
namespace ProjectExplorer { class Project; } namespace ProjectExplorer { class Project; }
namespace CppEditor::Internal { namespace CppEditor::Internal {
@@ -28,6 +29,7 @@ public:
QDir::toNativeSeparators("../Src"), QDir::toNativeSeparators("../Src"),
".."}; ".."};
Utils::FilePath licenseTemplatePath; Utils::FilePath licenseTemplatePath;
QString headerGuardTemplate = "%{JS: '%{Header:FileName}'.toUpperCase().replace(/[.]/g, '_')}";
bool headerPragmaOnce = false; bool headerPragmaOnce = false;
bool lowerCaseFiles = Constants::LOWERCASE_CPPFILES_DEFAULT; bool lowerCaseFiles = Constants::LOWERCASE_CPPFILES_DEFAULT;
@@ -39,6 +41,9 @@ public:
// Convenience to return a license template completely formatted. // Convenience to return a license template completely formatted.
QString licenseTemplate() const; QString licenseTemplate() const;
// Expanded headerGuardTemplate.
QString headerGuard(const Utils::FilePath &headerFilePath) const;
bool equals(const CppFileSettings &rhs) 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); }
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); CppFileSettings cppFileSettingsForProject(ProjectExplorer::Project *project);
void setupCppFileSettings(); void setupCppFileSettings(ExtensionSystem::IPlugin &plugin);
} // namespace CppEditor::Internal } // namespace CppEditor::Internal

View File

@@ -42,7 +42,7 @@ static QString fileName(const QString &path, const QString &extension)
QString CppToolsJsExtension::headerGuard(const QString &in) const QString CppToolsJsExtension::headerGuard(const QString &in) const
{ {
return Utils::headerGuard(in); return fileSettings().headerGuard(Utils::FilePath::fromString(in));
} }
QString CppToolsJsExtension::licenseTemplate() const QString CppToolsJsExtension::licenseTemplate() const

View File

@@ -358,6 +358,11 @@ CppCompletionAssistProcessor *getCppCompletionAssistProcessor()
return new Internal::InternalCppCompletionAssistProcessor(); 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) bool fileSizeExceedsLimit(const FilePath &filePath, int sizeLimitInMb)
{ {
if (sizeLimitInMb <= 0) if (sizeLimitInMb <= 0)

View File

@@ -6,7 +6,6 @@
#include "cppeditor_global.h" #include "cppeditor_global.h"
#include "clangdiagnosticconfig.h" #include "clangdiagnosticconfig.h"
#include "compileroptionsbuilder.h"
#include "projectpart.h" #include "projectpart.h"
#include <texteditor/quickfix.h> #include <texteditor/quickfix.h>
@@ -65,6 +64,9 @@ quickFixOperations(const TextEditor::AssistInterface *interface);
CppCompletionAssistProcessor CPPEDITOR_EXPORT *getCppCompletionAssistProcessor(); CppCompletionAssistProcessor CPPEDITOR_EXPORT *getCppCompletionAssistProcessor();
QString CPPEDITOR_EXPORT
deriveHeaderGuard(const Utils::FilePath &filePath, ProjectExplorer::Project *project);
enum class CacheUsage { ReadWrite, ReadOnly }; enum class CacheUsage { ReadWrite, ReadOnly };
Utils::FilePath CPPEDITOR_EXPORT correspondingHeaderOrSource( Utils::FilePath CPPEDITOR_EXPORT correspondingHeaderOrSource(

View File

@@ -388,7 +388,7 @@ private:
= Utils::transform<QStringList>(state->namespacePath, [&](const Namespace *ns) { = Utils::transform<QStringList>(state->namespacePath, [&](const Namespace *ns) {
return ov.prettyName(ns->name()); return ov.prettyName(ns->name());
}); });
const QString headerGuard = Utils::headerGuard(headerFileName); const QString headerGuard = fileSettings.headerGuard(headerFilePath);
if (fileSettings.headerPragmaOnce) { if (fileSettings.headerPragmaOnce) {
headerContent.append("#pragma once\n"); headerContent.append("#pragma once\n");
} else { } else {

View File

@@ -27,6 +27,8 @@ const char SHOW_LOG[] = "showLog";
const char SHOW_WARNING[] = "showWarning"; const char SHOW_WARNING[] = "showWarning";
const char SHOW_ERROR[] = "showError"; const char SHOW_ERROR[] = "showError";
using namespace Utils;
namespace Debugger::Internal { namespace Debugger::Internal {
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
@@ -90,8 +92,8 @@ Console::Console()
m_showDebug.setLabelText(Tr::tr("Show debug, log, and info messages.")); m_showDebug.setLabelText(Tr::tr("Show debug, log, and info messages."));
m_showDebug.setToolTip(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.setValue(true);
m_showDebug.action()->setIcon(Utils::Icons::INFO_TOOLBAR.icon()); m_showDebug.setIcon(Icons::INFO_TOOLBAR.icon());
connect(&m_showDebug, &Utils::BoolAspect::changed, connect(&m_showDebug, &BoolAspect::changed,
proxyModel, [this, proxyModel] { proxyModel->setShowLogs(m_showDebug()); }); proxyModel, [this, proxyModel] { proxyModel->setShowLogs(m_showDebug()); });
m_showDebugButton->setDefaultAction(m_showDebug.action()); m_showDebugButton->setDefaultAction(m_showDebug.action());
@@ -102,8 +104,8 @@ Console::Console()
m_showWarning.setLabelText(Tr::tr("Show warning messages.")); m_showWarning.setLabelText(Tr::tr("Show warning messages."));
m_showWarning.setToolTip(Tr::tr("Show warning messages.")); m_showWarning.setToolTip(Tr::tr("Show warning messages."));
m_showWarning.setValue(true); m_showWarning.setValue(true);
m_showWarning.action()->setIcon(Utils::Icons::WARNING_TOOLBAR.icon()); m_showWarning.setIcon(Icons::WARNING_TOOLBAR.icon());
connect(m_showWarning.action(), &QAction::toggled, connect(&m_showWarning, &BoolAspect::changed,
proxyModel, [this, proxyModel] { proxyModel->setShowWarnings(m_showWarning()); }); proxyModel, [this, proxyModel] { proxyModel->setShowWarnings(m_showWarning()); });
m_showWarningButton->setDefaultAction(m_showWarning.action()); m_showWarningButton->setDefaultAction(m_showWarning.action());
@@ -114,8 +116,8 @@ Console::Console()
m_showError.setLabelText(Tr::tr("Show error messages.")); m_showError.setLabelText(Tr::tr("Show error messages."));
m_showError.setToolTip(Tr::tr("Show error messages.")); m_showError.setToolTip(Tr::tr("Show error messages."));
m_showError.setValue(true); m_showError.setValue(true);
m_showError.action()->setIcon(Utils::Icons::CRITICAL_TOOLBAR.icon()); m_showError.setIcon(Icons::CRITICAL_TOOLBAR.icon());
connect(m_showError.action(), &QAction::toggled, connect(&m_showError, &BoolAspect::changed,
proxyModel, [this, proxyModel] { proxyModel->setShowErrors(m_showError()); }); proxyModel, [this, proxyModel] { proxyModel->setShowErrors(m_showError()); });
m_showErrorButton->setDefaultAction(m_showError.action()); m_showErrorButton->setDefaultAction(m_showError.action());

View File

@@ -125,9 +125,6 @@ public:
// Used by Valgrind // Used by Valgrind
QStringList expectedSignals; QStringList expectedSignals;
// For QNX debugging
bool useCtrlCStub = false;
// Used by Android to avoid false positives on warnOnRelease // Used by Android to avoid false positives on warnOnRelease
bool skipExecutableValidation = false; bool skipExecutableValidation = false;
bool useTargetAsync = false; bool useTargetAsync = false;

View File

@@ -440,8 +440,11 @@ static DebuggerItem::MatchLevel matchSingle(const Abi &debuggerAbi, const Abi &t
return matchOnMultiarch; return matchOnMultiarch;
} }
if (debuggerAbi.wordWidth() == 64 && targetAbi.wordWidth() == 32) if (debuggerAbi.wordWidth() == 64 && targetAbi.wordWidth() == 32) {
return DebuggerItem::MatchesSomewhat; return HostOsInfo::isWindowsHost() && engineType == CdbEngineType
? DebuggerItem::MatchesPerfectly
: DebuggerItem::MatchesSomewhat;
}
if (debuggerAbi.wordWidth() != 0 && debuggerAbi.wordWidth() != targetAbi.wordWidth()) if (debuggerAbi.wordWidth() != 0 && debuggerAbi.wordWidth() != targetAbi.wordWidth())
return matchOnMultiarch; return matchOnMultiarch;

View File

@@ -783,6 +783,12 @@ void DebuggerItemModel::readDebuggers(const FilePath &fileName, bool isSystem)
.arg(item.command().toUserOutput(), item.id().toString(), fileName.toUserOutput()); .arg(item.command().toUserOutput(), item.id().toString(), fileName.toUserOutput());
continue; 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. // FIXME: During startup, devices are not yet available, so we cannot check if the file still exists.
if (!item.command().needsDevice() && !item.command().isExecutableFile()) { if (!item.command().needsDevice() && !item.command().isExecutableFile()) {
qWarning() << QString("DebuggerItem \"%1\" (%2) read from \"%3\" dropped since the command is not executable.") qWarning() << QString("DebuggerItem \"%1\" (%2) read from \"%3\" dropped since the command is not executable.")

View File

@@ -388,6 +388,15 @@ public:
k->setValue(DebuggerKitAspect::id(), bestLevel != DebuggerItem::DoesNotMatch ? bestItem.id() : QVariant()); 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 KitAspect *createKitAspect(Kit *k) const override
{ {
return new Internal::DebuggerKitAspectImpl(k, this); return new Internal::DebuggerKitAspectImpl(k, this);

View File

@@ -276,11 +276,6 @@ void DebuggerRunTool::setSkipExecutableValidation(bool on)
m_runParameters.skipExecutableValidation = on; m_runParameters.skipExecutableValidation = on;
} }
void DebuggerRunTool::setUseCtrlCStub(bool on)
{
m_runParameters.useCtrlCStub = on;
}
void DebuggerRunTool::setBreakOnMain(bool on) void DebuggerRunTool::setBreakOnMain(bool on)
{ {
m_runParameters.breakOnMain = on; m_runParameters.breakOnMain = on;

View File

@@ -100,7 +100,6 @@ protected:
void setRemoteChannel(const QUrl &url); void setRemoteChannel(const QUrl &url);
void setUseTargetAsync(bool on); void setUseTargetAsync(bool on);
void setSkipExecutableValidation(bool on); void setSkipExecutableValidation(bool on);
void setUseCtrlCStub(bool on);
void setIosPlatform(const QString &platform); void setIosPlatform(const QString &platform);
void setDeviceSymbolsRoot(const QString &deviceSymbolsRoot); void setDeviceSymbolsRoot(const QString &deviceSymbolsRoot);

View File

@@ -124,6 +124,7 @@ const char notCompatibleMessage[] = "is not compatible with target architecture"
GdbEngine::GdbEngine() GdbEngine::GdbEngine()
{ {
m_gdbProc.setProcessMode(ProcessMode::Writer); m_gdbProc.setProcessMode(ProcessMode::Writer);
m_gdbProc.setUseCtrlCStub(true);
setObjectName("GdbEngine"); setObjectName("GdbEngine");
setDebuggerName("GDB"); setDebuggerName("GDB");
@@ -673,28 +674,9 @@ void GdbEngine::interruptInferior()
} else { } else {
showStatusMessage(Tr::tr("Stop requested..."), 5000); showStatusMessage(Tr::tr("Stop requested..."), 5000);
showMessage("TRYING TO INTERRUPT INFERIOR"); 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();
} }
} }
}
void GdbEngine::runCommand(const DebuggerCommand &command) void GdbEngine::runCommand(const DebuggerCommand &command)
{ {
@@ -1265,9 +1247,11 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
handleStop1(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) void GdbEngine::handleStop1(const GdbMi &data)
@@ -1416,7 +1400,7 @@ void GdbEngine::handleStop2(const GdbMi &data)
QString meaning = data["signal-meaning"].data(); QString meaning = data["signal-meaning"].data();
// Ignore these as they are showing up regularly when // Ignore these as they are showing up regularly when
// stopping debugging. // 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."); showMessage(name + " CONSIDERED HARMLESS. CONTINUING.");
} else if (m_isQnxGdb && name == "0" && meaning == "Signal 0") { } else if (m_isQnxGdb && name == "0" && meaning == "Signal 0") {
showMessage("SIGNAL 0 CONSIDERED BOGUS."); showMessage("SIGNAL 0 CONSIDERED BOGUS.");
@@ -3817,9 +3801,6 @@ void GdbEngine::setupEngine()
CHECK_STATE(EngineSetupRequested); CHECK_STATE(EngineSetupRequested);
showMessage("TRYING TO START ADAPTER"); showMessage("TRYING TO START ADAPTER");
if (isRemoteEngine())
m_gdbProc.setUseCtrlCStub(runParameters().useCtrlCStub); // This is only set for QNX
const DebuggerRunParameters &rp = runParameters(); const DebuggerRunParameters &rp = runParameters();
CommandLine gdbCommand = rp.debugger.command; CommandLine gdbCommand = rp.debugger.command;
@@ -4314,7 +4295,6 @@ void GdbEngine::interruptLocalInferior(qint64 pid)
showMessage("TRYING TO INTERRUPT INFERIOR BEFORE PID WAS OBTAINED", LogError); showMessage("TRYING TO INTERRUPT INFERIOR BEFORE PID WAS OBTAINED", LogError);
return; return;
} }
QString errorMessage;
if (runParameters().runAsRoot) { if (runParameters().runAsRoot) {
Environment env = Environment::systemEnvironment(); Environment env = Environment::systemEnvironment();
RunControl::provideAskPassEntry(env); RunControl::provideAskPassEntry(env);
@@ -4323,11 +4303,8 @@ void GdbEngine::interruptLocalInferior(qint64 pid)
proc.setEnvironment(env); proc.setEnvironment(env);
proc.start(); proc.start();
proc.waitForFinished(); proc.waitForFinished();
} else if (interruptProcess(pid, GdbEngineType, &errorMessage)) {
showMessage("Interrupted " + QString::number(pid));
} else { } else {
showMessage(errorMessage, LogError); m_gdbProc.interrupt();
notifyInferiorStopFailed();
} }
} }

View File

@@ -143,7 +143,7 @@ void PdbEngine::handlePdbStarted()
void PdbEngine::interruptInferior() void PdbEngine::interruptInferior()
{ {
QString error; QString error;
interruptProcess(m_proc.processId(), GdbEngineType, &error); interruptProcess(m_proc.processId(), &error);
} }
void PdbEngine::executeStepIn(bool) void PdbEngine::executeStepIn(bool)

View File

@@ -23,128 +23,23 @@ static inline QString msgCannotInterrupt(qint64 pid, const QString &why)
# define PROCESS_SUSPEND_RESUME (0x0800) # define PROCESS_SUSPEND_RESUME (0x0800)
#endif // PROCESS_SUSPEND_RESUME #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<LPFN_ISWOW64PROCESS>(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 // 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; bool ok = false;
HANDLE inferior = NULL; HANDLE inferior = NULL;
do { const DWORD rights = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION | PROCESS_VM_OPERATION
const DWORD rights = PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_DUP_HANDLE
|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ | PROCESS_TERMINATE | PROCESS_CREATE_THREAD | PROCESS_SUSPEND_RESUME;
|PROCESS_DUP_HANDLE|PROCESS_TERMINATE|PROCESS_CREATE_THREAD|PROCESS_SUSPEND_RESUME;
inferior = OpenProcess(rights, FALSE, DWORD(pID)); inferior = OpenProcess(rights, FALSE, DWORD(pID));
if (inferior == NULL) { if (inferior == NULL) {
*errorMessage = QString::fromLatin1("Cannot open process %1: %2"). *errorMessage = QString::fromLatin1("Cannot open process %1: %2")
arg(pID).arg(Utils::winErrorMessage(GetLastError())); .arg(pID)
break; .arg(Utils::winErrorMessage(GetLastError()));
} } else if (ok = DebugBreakProcess(inferior); !ok) {
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()); *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) if (inferior != NULL)
CloseHandle(inferior); CloseHandle(inferior);
if (!ok) if (!ok)
@@ -159,8 +54,7 @@ GDB 32bit | Api | Api | NA | Win32
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
bool Debugger::Internal::interruptProcess(qint64 pID, int /* engineType */, bool Debugger::Internal::interruptProcess(qint64 pID, QString *errorMessage)
QString *errorMessage, const bool /*engineExecutableIs64Bit*/)
{ {
if (pID <= 0) { if (pID <= 0) {
*errorMessage = msgCannotInterrupt(pID, QString::fromLatin1("Invalid process id.")); *errorMessage = msgCannotInterrupt(pID, QString::fromLatin1("Invalid process id."));

View File

@@ -7,7 +7,6 @@
namespace Debugger::Internal { namespace Debugger::Internal {
bool interruptProcess(qint64 pID, int engineType, QString *errorMessage, bool interruptProcess(qint64 pID, QString *errorMessage);
const bool engineExecutableIs64Bit = false);
} // Debugger::Internal } // Debugger::Internal

View File

@@ -904,7 +904,7 @@ static ConsoleItem *constructLogItemTree(const QVariant &result, const QString &
if (child) if (child)
item->appendChild(child); item->appendChild(child);
} }
} else if (result.canConvert(QMetaType::QString)) { } else if (result.canConvert(QMetaType(QMetaType::QString))) {
item = new ConsoleItem(ConsoleItem::DefaultType, result.toString()); item = new ConsoleItem(ConsoleItem::DefaultType, result.toString());
} else { } else {
item = new ConsoleItem(ConsoleItem::DefaultType, "Unknown Value"); item = new ConsoleItem(ConsoleItem::DefaultType, "Unknown Value");

View File

@@ -25,7 +25,7 @@ else()
endif() endif()
add_qtc_plugin(Designer add_qtc_plugin(Designer
PLUGIN_CLASS FormEditorPlugin PLUGIN_CLASS DesignerPlugin
CONDITION TARGET Qt::DesignerComponentsPrivate AND TARGET Qt::Designer CONDITION TARGET Qt::DesignerComponentsPrivate AND TARGET Qt::Designer
DEPENDS designerintegrationv2 DEPENDS designerintegrationv2
Qt::Designer Qt::PrintSupport Qt::DesignerComponentsPrivate Qt::Designer Qt::PrintSupport Qt::DesignerComponentsPrivate

View File

@@ -8,6 +8,7 @@
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <cppeditor/abstracteditorsupport.h> #include <cppeditor/abstracteditorsupport.h>
#include <cppeditor/cpptoolsreuse.h>
#include <projectexplorer/projecttree.h> #include <projectexplorer/projecttree.h>
#include <qtsupport/codegenerator.h> #include <qtsupport/codegenerator.h>
#include <qtsupport/codegensettings.h> #include <qtsupport/codegensettings.h>
@@ -75,7 +76,8 @@ bool QtDesignerFormClassCodeGenerator::generateCpp(const FormClassWizardParamete
const QString sourceLicense = CppEditor::AbstractEditorSupport::licenseTemplate( const QString sourceLicense = CppEditor::AbstractEditorSupport::licenseTemplate(
project, FilePath::fromString(parameters.sourceFile), parameters.className); project, FilePath::fromString(parameters.sourceFile), parameters.className);
// Include guards // 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"; const QString uiInclude = "ui_" + QFileInfo(parameters.uiFile).completeBaseName() + ".h";

View File

@@ -39,9 +39,9 @@ QString EffectComposerContextObject::convertColorToString(const QVariant &color)
{ {
QString colorString; QString colorString;
QColor theColor; QColor theColor;
if (color.canConvert(QVariant::Color)) { if (color.canConvert(QMetaType(QMetaType::QColor))) {
theColor = color.value<QColor>(); theColor = color.value<QColor>();
} else if (color.canConvert(QVariant::Vector3D)) { } else if (color.canConvert(QMetaType(QMetaType::QVector3D))) {
auto vec = color.value<QVector3D>(); auto vec = color.value<QVector3D>();
theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z()); theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z());
} }

View File

@@ -548,6 +548,13 @@ static void registerLuaApi()
// ... then register the settings. // ... then register the settings.
LanguageClientManager::registerClientSettings(client); 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; return luaClient;
}); });

View File

@@ -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": [ "targets": [
{ {
"name": "Qt Creator", "name": "Qt Creator",

View File

@@ -78,7 +78,7 @@ public:
const QVariant checkFormat = kit->value(McuDependenciesKitAspect::id()); const QVariant checkFormat = kit->value(McuDependenciesKitAspect::id());
if (!checkFormat.isValid() || checkFormat.isNull()) if (!checkFormat.isValid() || checkFormat.isNull())
return result; 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."))}; return {BuildSystemTask(Task::Error, Tr::tr("The MCU dependencies setting value is invalid."))};
// check paths defined in cmake variables for given dependencies exist // check paths defined in cmake variables for given dependencies exist
@@ -105,7 +105,7 @@ public:
QTC_ASSERT(kit, return ); QTC_ASSERT(kit, return );
const QVariant variant = kit->value(McuDependenciesKitAspect::id()); 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.", qWarning("Kit \"%s\" has a wrong mcu dependencies value set.",
qPrintable(kit->displayName())); qPrintable(kit->displayName()));
McuDependenciesKitAspect::setDependencies(kit, Utils::EnvironmentItems()); McuDependenciesKitAspect::setDependencies(kit, Utils::EnvironmentItems());

View File

@@ -102,90 +102,20 @@ void DesktopProcessSignalOperation::killProcessSilently(qint64 pid)
void DesktopProcessSignalOperation::interruptProcessSilently(qint64 pid) void DesktopProcessSignalOperation::interruptProcessSilently(qint64 pid)
{ {
#ifdef Q_OS_WIN #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; HANDLE inferior = NULL;
do { const DWORD rights = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION | PROCESS_VM_OPERATION
const DWORD rights = PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_DUP_HANDLE
|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ | PROCESS_TERMINATE | PROCESS_CREATE_THREAD | PROCESS_SUSPEND_RESUME;
|PROCESS_DUP_HANDLE|PROCESS_TERMINATE|PROCESS_CREATE_THREAD|PROCESS_SUSPEND_RESUME;
inferior = OpenProcess(rights, FALSE, pid); inferior = OpenProcess(rights, FALSE, pid);
if (inferior == NULL) { if (inferior == NULL) {
appendMsgCannotInterrupt(pid, Tr::tr("Cannot open process: %1") appendMsgCannotInterrupt(
pid, Tr::tr("Cannot open process: %1") + winErrorMessage(GetLastError()));
} else if (!DebugBreakProcess(inferior)) {
appendMsgCannotInterrupt(
pid,
Tr::tr("DebugBreakProcess failed:") + QLatin1Char(' ')
+ winErrorMessage(GetLastError())); + 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);
if (inferior != NULL) if (inferior != NULL)
CloseHandle(inferior); CloseHandle(inferior);
#else #else

View File

@@ -1539,7 +1539,7 @@ Tasks EnvironmentKitAspectFactory::validate(const Kit *k) const
QTC_ASSERT(k, return result); QTC_ASSERT(k, return result);
const QVariant variant = k->value(EnvironmentKitAspect::id()); 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.")); result << BuildSystemTask(Task::Error, Tr::tr("The environment setting value is invalid."));
return result; return result;
@@ -1550,7 +1550,7 @@ void EnvironmentKitAspectFactory::fix(Kit *k)
QTC_ASSERT(k, return); QTC_ASSERT(k, return);
const QVariant variant = k->value(EnvironmentKitAspect::id()); 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())); qWarning("Kit \"%s\" has a wrong environment value set.", qPrintable(k->displayName()));
EnvironmentKitAspect::setEnvironmentChanges(k, EnvironmentItems()); EnvironmentKitAspect::setEnvironmentChanges(k, EnvironmentItems());
} }

View File

@@ -253,7 +253,12 @@ public:
: Project(FOLDER_MIMETYPE, file.isDir() ? file / ".qtcreator" / "project.json" : file) : Project(FOLDER_MIMETYPE, file.isDir() ? file / ".qtcreator" / "project.json" : file)
{ {
QTC_CHECK(projectFilePath().absolutePath().ensureWritableDir()); 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)); setId(Id::fromString(WORKSPACE_PROJECT_ID));
setDisplayName(projectDirectory().fileName()); setDisplayName(projectDirectory().fileName());

View File

@@ -46,9 +46,9 @@ QString MaterialEditorContextObject::convertColorToString(const QVariant &color)
{ {
QString colorString; QString colorString;
QColor theColor; QColor theColor;
if (color.canConvert(QVariant::Color)) { if (color.canConvert(QMetaType(QMetaType::QColor))) {
theColor = color.value<QColor>(); theColor = color.value<QColor>();
} else if (color.canConvert(QVariant::Vector3D)) { } else if (color.canConvert(QMetaType(QMetaType::QVector3D))) {
auto vec = color.value<QVector3D>(); auto vec = color.value<QVector3D>();
theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z()); theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z());
} }

View File

@@ -87,9 +87,9 @@ QString PropertyEditorContextObject::convertColorToString(const QVariant &color)
{ {
QString colorString; QString colorString;
QColor theColor; QColor theColor;
if (color.canConvert(QVariant::Color)) { if (color.canConvert(QMetaType(QMetaType::QColor))) {
theColor = color.value<QColor>(); theColor = color.value<QColor>();
} else if (color.canConvert(QVariant::Vector3D)) { } else if (color.canConvert(QMetaType(QMetaType::QVector3D))) {
auto vec = color.value<QVector3D>(); auto vec = color.value<QVector3D>();
theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z()); theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z());
} }

View File

@@ -47,9 +47,9 @@ QString TextureEditorContextObject::convertColorToString(const QVariant &color)
{ {
QString colorString; QString colorString;
QColor theColor; QColor theColor;
if (color.canConvert(QVariant::Color)) { if (color.canConvert(QMetaType(QMetaType::QColor))) {
theColor = color.value<QColor>(); theColor = color.value<QColor>();
} else if (color.canConvert(QVariant::Vector3D)) { } else if (color.canConvert(QMetaType(QMetaType::QVector3D))) {
auto vec = color.value<QVector3D>(); auto vec = color.value<QVector3D>();
theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z()); theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z());
} }

View File

@@ -107,14 +107,14 @@ static void editValue(const ModelNode &frameNode, const std::pair<qreal, qreal>
int userType = value.typeId(); int userType = value.typeId();
QVariant newValue = dialog->value(); QVariant newValue = dialog->value();
if (newValue.canConvert(userType)) { if (newValue.canConvert(QMetaType(userType))) {
QVariant newValueConverted = newValue; QVariant newValueConverted = newValue;
bool converted = newValueConverted.convert(userType); bool converted = newValueConverted.convert(QMetaType(userType));
if (!converted) { if (!converted) {
// convert() fails for int to double, so we try this combination // convert() fails for int to double, so we try this combination
newValueConverted = newValue; newValueConverted = newValue;
converted = newValueConverted.convert(QMetaType::Double); converted = newValueConverted.convert(QMetaType(QMetaType::Double));
} }
if (converted) if (converted)

View File

@@ -1565,7 +1565,7 @@ void TextToModelMerger::syncVariantProperty(AbstractProperty &modelProperty,
const TypeName &astType, const TypeName &astType,
DifferenceHandler &differenceHandler) DifferenceHandler &differenceHandler)
{ {
if (astValue.canConvert(QMetaType::QString)) if (astValue.canConvert(QMetaType(QMetaType::QString)))
populateQrcMapping(astValue.toString()); populateQrcMapping(astValue.toString());
if (modelProperty.isVariantProperty()) { if (modelProperty.isVariantProperty()) {

View File

@@ -126,7 +126,6 @@ public:
setStartMode(AttachToRemoteServer); setStartMode(AttachToRemoteServer);
setCloseMode(KillAtClose); setCloseMode(KillAtClose);
setUseCtrlCStub(true);
setSolibSearchPath(FileUtils::toFilePathList(searchPaths(k))); setSolibSearchPath(FileUtils::toFilePathList(searchPaths(k)));
if (auto qtVersion = dynamic_cast<QnxQtVersion *>(QtSupport::QtKitAspect::qtVersion(k))) { if (auto qtVersion = dynamic_cast<QnxQtVersion *>(QtSupport::QtKitAspect::qtVersion(k))) {
setSysRoot(qtVersion->qnxTarget()); setSysRoot(qtVersion->qnxTarget());
@@ -196,7 +195,6 @@ public:
{ {
setId("QnxAttachDebugSupport"); setId("QnxAttachDebugSupport");
setUsePortsGatherer(isCppDebugging(), isQmlDebugging()); setUsePortsGatherer(isCppDebugging(), isQmlDebugging());
setUseCtrlCStub(true);
if (isCppDebugging()) { if (isCppDebugging()) {
auto pdebugRunner = new PDebugRunner(runControl, portsGatherer()); auto pdebugRunner = new PDebugRunner(runControl, portsGatherer());

View File

@@ -4,6 +4,7 @@ add_qtc_plugin(QtApplicationManagerIntegration
PLUGIN_DEPENDS PLUGIN_DEPENDS
Core Debugger ProjectExplorer Core Debugger ProjectExplorer
QtSupport RemoteLinux QtSupport RemoteLinux
PLUGIN_CLASS AppManagerPlugin
DEPENDS Qt::Network Qt::Widgets ExtensionSystem Utils yaml-cpp DEPENDS Qt::Network Qt::Widgets ExtensionSystem Utils yaml-cpp
SOURCES SOURCES
appmanagerconstants.h appmanagerconstants.h

View File

@@ -110,6 +110,21 @@ public:
m_textEditorWidget->setTextDocument(m_document); m_textEditorWidget->setTextDocument(m_document);
m_textEditorWidget->setupGenericHighlighter(); m_textEditorWidget->setupGenericHighlighter();
m_textEditorWidget->setMarksVisible(false); 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); auto context = new IContext(this);
context->setWidget(m_textEditorWidget); context->setWidget(m_textEditorWidget);
context->setContext(Context(MARKDOWNVIEWER_TEXT_CONTEXT)); 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: private:
QTimer m_previewTimer; QTimer m_previewTimer;
bool m_performDelayedUpdate = false; bool m_performDelayedUpdate = false;
@@ -491,6 +518,7 @@ private:
QAction *m_togglePreviewVisibleAction; QAction *m_togglePreviewVisibleAction;
QAction *m_swapViewsAction; QAction *m_swapViewsAction;
std::optional<QPoint> m_previewRestoreScrollPosition; std::optional<QPoint> m_previewRestoreScrollPosition;
QByteArray m_savedNavigationState;
}; };
class MarkdownEditorFactory final : public IEditorFactory class MarkdownEditorFactory final : public IEditorFactory