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.
\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:

View File

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

View File

@@ -124,8 +124,34 @@
The document outline in the \l{Outline} view is backed by clangd's document
symbol support, which makes the results more reliable than before.
\sa {Code Model}, {Clangd}, {Specify clangd settings},
{Specify Clang tools settings}, {Use compilation databases}
\sa {Configure C++ code model}, {Specify clangd settings},
{Specify Clang tools settings}, {Use compilation databases},
{Code Model}, {Clangd}
*/
/*!
\page creator-how-to-cpp-code-model.html
\previouspage creator-how-tos.html
\ingroup creator-how-to-configure-editors
\ingroup creator-how-to-projects-configure
\title Configure C++ code model
The code model offers services such as code completion, syntactic and
semantic highlighting, and diagnostics.
To configure the C++ code model for a project:
\list 1
\li Go to \uicontrol Projects > \uicontrol {Project Settings} >
\uicontrol {C++ Code Model}.
\image qtcreator-projects-cpp-code-model.webp {C++ Code Model settings}
\li Clear \uicontrol {Use global settings}.
\li Set \uicontrol {C++ Code Model} settings for the project.
\endlist
\sa {Code Model}
*/
/*!
@@ -138,40 +164,43 @@
\brief Sets global preferences for the code model.
The Clang code model offers services such as code completion, syntactic and
The code model offers services such as code completion, syntactic and
semantic highlighting, and diagnostics.
To configure the Clang code model globally:
To configure the C++ code model globally, go to \preferences >
\uicontrol C++ > \uicontrol {Code Model}.
\list 1
\image qtcreator-preferences-code-model.webp {C++ Code Model preferences}
\li Select \preferences > \uicontrol C++ >
\uicontrol {Code Model}.
\image qtcreator-preferences-code-model.webp {C++ Code Model preferences}
\li To instruct the code model to interpret ambiguous header files as C
language files if you develop mainly using C, select the
\uicontrol {Interpret ambiguous headers as C headers} check box.
\li To process precompiled headers, deselect the
\uicontrol {Ignore precompiled headers} check box.
\li To use the built-in preprocessor to show the
pre-processed source file in the editor, select
\uicontrol {Use built-in preprocessor to show pre-processed files}.
The following table summarizes the preferences.
\table
\header
\li Setting
\li Value
\row
\li \uicontrol {Interpret ambiguous headers as C headers}
\li Instructs the code model to interpret ambiguous header files as C
language files. Select this checkbox if you develop mainly using C.
\row
\li \uicontrol {Ignore precompiled headers}
\li Clear this checkbox to process precompiled headers.
\row
\li \uicontrol {Use built-in preprocessor to show pre-processed files}
\li Uses the built-in preprocessor to show the
pre-processed source file in the editor.
\row
\li \uicontrol {Do not index files greater than}
\li To avoid out-of-memory crashes caused by indexing huge source files
that are typically auto-generated by scripts or code, the size of
files to index is limited to 5MB by default. To adjust the limit,
edit the value for the \uicontrol {Do not index files greater than}
check box. To index all files, deselect the check box.
files to index is limited to 5MB by default.
\li To ignore files that match wildcard patterns, select the
\uicontrol {Ignore files} check box and enter each wildcard pattern
on a separate line in the field.
\endlist
To index all files, clear the checkbox.
\row
\li \uicontrol {Ignore files}
\li To ignore files that match wildcard patterns, enter each wildcard
pattern on a separate line in the field.
\endtable
\section1 Inspect preprocessed C++ code
@@ -186,7 +215,8 @@
this action also expands all \c {"#include <foo.h>"} statements to their
actual contents.
\sa {Specify clangd settings}, {Clang Code Model}, {Clangd}
\sa {Configure C++ code model}, {Specify clangd settings},
{Clang Code Model}, {Clangd}
*/
/*!

View File

@@ -108,28 +108,45 @@
To verify the installation of a particular Qt version, \QC
calls \c {qmake -query} and checks that the directories referenced in the
output exist. When \QC complains about the installation of a self-built Qt
version, try running \c {make install} in the build directory to actually
install Qt into the configured location. If you installed Qt using the Qt
Installer, run \QMT to check for updates or to reinstall
the Qt version.
output exist. If you installed Qt using \QOI, run
\QMT to check for updates or to reinstall the Qt version.
\section1 Minimum requirements
If your build of Qt is incomplete but you still want to use qmake as build
system, you need to ensure the following minimum requirements to use that
setup with \QC.
\section2 Self-built Qt versions
\list 1
To build projects with a self-built Qt version, add it as described in
\l{Set up new Qt versions}.
Your Qt has to meet the following minimum requirements:
\list
\li qmake is an executable that understands the \c -query command-line
argument.
\li The \c bin and \c include directories have to exist. \QC fetches
these directories by running \c{qmake -query}.
\li The \c mkspecs directory should be complete enough to parse .pro
files.
\endlist
If your Qt version has no \c libQtCore.so, \QC cannot detect the ABI.
Add a kit for the Qt version and configure it for CMake.
\sa {kits-tab}{Kits}
\QC issues warnings if:
\list
\li \c libQtCore.so is missing, so \QC cannot detect the ABI.
\li \c toolchain.cmake is missing. For example, you built Qt with the
\c -static option for an x86 platform.
\endlist
Try the following:
\list
\li Run \c {make install} in the build directory to install Qt into the
configured location.
\li Set the value of the \c CMAKE_PREFIX_PATH variable in \preferences >
\uicontrol Kits > \uicontrol Kits > \uicontrol {CMake Configuration}
to the location where you installed Qt.
\endlist
\image qtcreator-edit-cmake-configuration-self-built-qt.webp {Setting the path to a self-built Qt}
\sa {Manage Kits}{How To: Manage Kits}, {kits-tab}{Kits}
*/

View File

@@ -85,6 +85,7 @@
\li \l{Specify clangd settings}{Clangd}
\li \l{Specify Clang tools settings}{Clang Tools}
\li \l{Set Copilot preferences}{Copilot}
\li \l{Configure C++ code model}{C++ Code Model}
\li \l{Specify code style}{C++ Code Style}
\li \l{Set C++ file naming preferences}{C++ File Naming}
\li \l{Specify dependencies}{Dependencies}

View File

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

View File

@@ -76,7 +76,9 @@ class Dumper(DumperBase):
self.outputLock = threading.Lock()
self.isCdb = True
#FIXME
#FIXME
def register_known_qt_types(self):
DumperBase.register_known_qt_types(self)
typeid = self.typeid_for_string('@QVariantMap')
del self.type_code_cache[typeid]
del self.type_target_cache[typeid]

View File

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

View File

@@ -874,6 +874,36 @@ class Dumper(DumperBase):
except:
return '0x%x' % address
def qtVersionString(self):
try:
return str(gdb.lookup_symbol('qVersion')[0].value()())
except:
pass
try:
ns = self.qtNamespace()
return str(gdb.parse_and_eval("((const char*(*)())'%sqVersion')()" % ns))
except:
pass
return None
def extractQtVersion(self):
try:
# Only available with Qt 5.3+
return int(str(gdb.parse_and_eval('((void**)&qtHookData)[2]')), 16)
except:
pass
try:
version = self.qtVersionString()
(major, minor, patch) = version[version.find('"') + 1:version.rfind('"')].split('.')
qtversion = 0x10000 * int(major) + 0x100 * int(minor) + int(patch)
self.qtVersion = lambda: qtversion
return qtversion
except:
# Use fallback until we have a better answer.
return None
def createSpecialBreakpoints(self, args):
self.specialBreakpoints = []

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
if 'dumper' in sys.modules:
if sys.version_info[0] >= 3:
if sys.version_info[1] > 3:
from importlib import reload
else:
def reload(m): print('Unsupported Python version - not reloading %s' % str(m))
from importlib import reload
reload(sys.modules['dumper'])
from dumper import DumperBase, SubItem, Children, TopLevelItem
@@ -34,16 +30,10 @@ from dumper import DumperBase, SubItem, Children, TopLevelItem
#######################################################################
qqWatchpointOffset = 10000
_c_str_trans = None
if sys.version_info[0] >= 3:
_c_str_trans = str.maketrans({"\n": "\\n", '"':'\\"', "\\":"\\\\"})
_c_str_trans = str.maketrans({"\n": "\\n", '"':'\\"', "\\":"\\\\"})
def toCString(s):
if _c_str_trans is not None:
return str(s).translate(_c_str_trans)
else:
return str(s).replace('\\', '\\\\').replace('\n', '\\n').replace('"', '\\"')
return str(s).translate(_c_str_trans)
def fileNameAsString(file):
return toCString(file) if file.IsValid() else ''
@@ -783,6 +773,54 @@ class Dumper(DumperBase):
self.fetchInternalFunctions = lambda: None
def extractQtVersion(self):
for func in self.target.FindFunctions('qVersion'):
name = func.GetSymbol().GetName()
if name == None:
continue
if name.endswith('()'):
name = name[:-2]
if name.count(':') > 2:
continue
#qtNamespace = name[:name.find('qVersion')]
#self.qtNamespace = lambda: qtNamespace
options = lldb.SBExpressionOptions()
res = self.target.EvaluateExpression(name + '()', options)
if not res.IsValid() or not res.GetType().IsPointerType():
exp = '((const char*())%s)()' % name
res = self.target.EvaluateExpression(exp, options)
if not res.IsValid() or not res.GetType().IsPointerType():
exp = '((const char*())_Z8qVersionv)()'
res = self.target.EvaluateExpression(exp, options)
if not res.IsValid() or not res.GetType().IsPointerType():
continue
version = str(res)
if version.count('.') != 2:
continue
version.replace("'", '"') # Both seem possible
version = version[version.find('"') + 1:version.rfind('"')]
(major, minor, patch) = version.split('.')
qtVersion = 0x10000 * int(major) + 0x100 * int(minor) + int(patch)
return qtVersion
try:
versionValue = self.target.EvaluateExpression('qtHookData[2]').GetNonSyntheticValue()
if versionValue.IsValid():
return versionValue.unsigned
except:
pass
return None
def handleCommand(self, command):
result = lldb.SBCommandReturnObject()
self.debugger.GetCommandInterpreter().HandleCommand(command, result)
@@ -2312,9 +2350,6 @@ class SummaryProvider(LogMixin):
if encoding in text_encodings:
try:
decodedValue = Dumper.hexdecode(summaryValue, encoding)
# LLDB expects UTF-8 for python 2
if sys.version_info[0] < 3:
return "\"%s\"" % (decodedValue.encode('utf8'))
return '"' + decodedValue + '"'
except:
return "<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):
if d.qtVersion() >= 0x60000:
d.qtVersionPing(value.typeid)
if d.qtVersionAtLeast(0x060000):
dd, data, length = value.split('ppi')
if dd:
_, _, alloc = d.split('iii', dd)
@@ -76,7 +77,8 @@ def qdump__QByteArray(d, value):
def qdump__QBitArray(d, value):
if d.qtVersion() >= 0x60000:
d.qtVersionPing(value.typeid)
if d.qtVersionAtLeast(0x060000):
_, data, basize = value.split('ppi')
else:
data, basize, _ = d.qArrayData(value['d'])
@@ -232,13 +234,13 @@ def qdump__QStandardItem(d, value):
#d.createType('@QStandardItem*')
vtable, dptr = value.split('pp')
if d.qtVersion() >= 0x060000:
if d.qtVersionAtLeast(0x060000):
model, parent, values, children, rows, cols, item = \
d.split('pp{@QList<@QStandardItemData>}{@QList<@QStandardItem *>}IIp', dptr)
else:
# There used to be a virtual destructor that got removed in
# 88b6abcebf29b455438 on Apr 18 17:01:22 2017
if d.qtVersion() < 0x050900 and not d.isMsvcTarget():
if not d.qtVersionAtLeast(0x050900) and not d.isMsvcTarget():
dptr += d.ptrSize();
model, parent, values, children, rows, cols, item = \
d.split('pp{@QVector<@QStandardItemData>}{@QVector<@QStandardItem *>}IIp', dptr)
@@ -266,7 +268,7 @@ def qdump__QDate(d, value):
d.enumExpression('DateFormat', 'TextDate'))
d.putCallItem('(ISO)', '@QString', value, 'toString',
d.enumExpression('DateFormat', 'ISODate'))
if d.qtVersion() < 0x060000:
if not d.qtVersionAtLeast(0x060000):
d.putCallItem('(SystemLocale)', '@QString', value, 'toString',
d.enumExpression('DateFormat', 'SystemLocaleDate'))
d.putCallItem('(Locale)', '@QString', value, 'toString',
@@ -286,7 +288,7 @@ def qdump__QTime(d, value):
d.enumExpression('DateFormat', 'TextDate'))
d.putCallItem('(ISO)', '@QString', value, 'toString',
d.enumExpression('DateFormat', 'ISODate'))
if d.canCallLocale() and d.qtVersion() < 0x060000:
if d.canCallLocale() and not d.qtVersionAtLeast(0x060000):
d.putCallItem('(SystemLocale)', '@QString', value, 'toString',
d.enumExpression('DateFormat', 'SystemLocaleDate'))
d.putCallItem('(Locale)', '@QString', value, 'toString',
@@ -305,13 +307,12 @@ def qdump__QTimeZone(d, value):
def qdump__QDateTime(d, value):
qtVersion = d.qtVersion()
isValid = False
# This relies on the Qt4/Qt5 internal structure layout:
# {sharedref(4), ...
base = d.extractPointer(value)
is32bit = d.ptrSize() == 4
if qtVersion >= 0x050200:
if d.qtVersionAtLeast(0x050200):
tiVersion = d.qtTypeInfoVersion()
#DumperBase.warn('TI VERSION: %s' % tiVersion)
if tiVersion is None:
@@ -384,9 +385,9 @@ def qdump__QDateTime(d, value):
# - [QTime time;]
# - - uint mds;
# - Spec spec;
dateSize = 8 if qtVersion >= 0x050000 else 4 # Qt5: qint64, Qt4 uint
dateSize = 8 if qtVersionAtLeast(0x050000) else 4 # Qt5: qint64, Qt4 uint
# 4 byte padding after 4 byte QAtomicInt if we are on 64 bit and QDate is 64 bit
refPlusPadding = 8 if qtVersion >= 0x050000 and d.ptrSize() == 8 else 4
refPlusPadding = 8 if qtVersionAtLeast(0x050000) and d.ptrSize() == 8 else 4
dateBase = base + refPlusPadding
timeBase = dateBase + dateSize
mds = d.extractInt(timeBase)
@@ -410,7 +411,7 @@ def qdump__QDateTime(d, value):
d.enumExpression('DateFormat', 'ISODate'))
d.putCallItem('toUTC', '@QDateTime', value, 'toTimeSpec',
d.enumExpression('TimeSpec', 'UTC'))
if d.qtVersion() < 0x060000:
if not d.qtVersionAtLeast(0x060000):
d.putCallItem('(SystemLocale)', '@QString', value, 'toString',
d.enumExpression('DateFormat', 'SystemLocaleDate'))
d.putCallItem('(Locale)', '@QString', value, 'toString',
@@ -756,7 +757,6 @@ def qdump__QFile(d, value):
def qdump__QFileInfo(d, value):
privAddress = d.extractPointer(value)
#bit32 = d.ptrSize() == 4
#qt5 = d.qtVersion() >= 0x050000
#try:
# d.putStringValue(value['d_ptr']['d'].dereference()['fileNames'][3])
#except:
@@ -876,7 +876,7 @@ def qdump__QVariantHash(d, value):
def qdumpHelper_QHash(d, value, keyType, valueType):
if d.qtVersion() >= 0x60000:
if d.qtVersionAtLeast(0x060000):
qdumpHelper_QHash_6(d, value, keyType, valueType)
else:
qdumpHelper_QHash_5(d, value, keyType, valueType)
@@ -918,7 +918,7 @@ def qdumpHelper_QHash_5(d, value, keyType, valueType):
d.putItemCount(size)
if d.isExpanded():
isShort = d.qtVersion() < 0x050000 and keyType.name == 'int'
isShort = not d.qtVersionAtLeast(0x050000) and keyType.name == 'int'
with Children(d, size):
node = hashDataFirstNode()
for i in d.childRange():
@@ -994,7 +994,7 @@ def qHashIteratorHelper(d, value):
if d.isExpanded():
with Children(d):
node = d.extractPointer(value)
isShort = d.qtVersion() < 0x050000 and keyType.name == 'int'
isShort = not d.qtVersionAtLeast(0x050000) and keyType.name == 'int'
if isShort:
typeCode = 'P{%s}@{%s}' % (keyType.name, valueType.name)
(pnext, key, padding2, val) = d.split(typeCode, node)
@@ -1015,9 +1015,8 @@ def qdump__QHash__iterator(d, value):
def qdump__QHostAddress(d, value):
dd = d.extractPointer(value)
qtVersion = d.qtVersion()
tiVersion = d.qtTypeInfoVersion()
#DumperBase.warn('QT: %x, TI: %s' % (qtVersion, tiVersion))
#DumperBase.warn('QT: %x, TI: %s' % (d.qtVersion(), tiVersion))
mayNeedParse = True
if tiVersion is not None:
if tiVersion >= 16:
@@ -1032,14 +1031,14 @@ def qdump__QHostAddress(d, value):
else:
(ipString, scopeId, a4, pad, a6, protocol, isParsed) \
= d.split('{@QString}{@QString}{@quint32}I16sI{bool}', dd)
elif qtVersion >= 0x050600: # 5.6.0 at f3aabb42
elif qtVersionAtLeast(0x050600): # 5.6.0 at f3aabb42
if d.ptrSize() == 8 or d.isWindowsTarget():
(ipString, scopeId, a4, pad, a6, protocol, isParsed) \
= d.split('{@QString}{@QString}{@quint32}I16sI{bool}', dd)
else:
(ipString, scopeId, a4, a6, protocol, isParsed) \
= d.split('{@QString}{@QString}{@quint32}16sI{bool}', dd)
elif qtVersion >= 0x050000: # 5.2.0 at 62feb088
elif qtVersionAtLeast(0x050000): # 5.2.0 at 62feb088
(ipString, scopeId, a4, a6, protocol, isParsed) \
= d.split('{@QString}{@QString}{@quint32}16sI{bool}', dd)
else: # 4.8.7 at b05d05f
@@ -1104,7 +1103,8 @@ def qdumpHelper_QList(d, value, inner_typish):
data, size = d.listData(value, check=True)
d.putItemCount(size)
if d.qtVersion() >= 0x60000:
d.qtVersionPing(value.typeid)
if d.qtVersionAtLeast(0x060000):
d.putPlotData(data, size, innerType)
return
@@ -1145,9 +1145,9 @@ def qform__QImage():
def qdump__QImage(d, value):
if d.qtVersion() >= 0x060000:
if d.qtVersionAtLeast(0x060000):
vtbl, painters, image_data = value.split('ppp')
elif d.qtVersion() >= 0x050000:
elif d.qtVersionAtLeast(0x050000):
vtbl, painters, reserved, image_data = value.split('pppp')
else:
vtbl, painters, image_data = value.split('ppp')
@@ -1161,12 +1161,12 @@ def qdump__QImage(d, value):
d.putExpandable()
if d.isExpanded():
if d.qtVersion() < 0x060000:
(ref, width, height, depth, nbytes, pad, devicePixelRatio, colorTable,
bits, iformat) = d.split('iiiii@dppi', image_data)
else:
if d.qtVersionAtLeast(0x060000):
(ref, width, height, depth, nbytes, pad, devicePixelRatio, _, _, _,
bits, iformat) = d.split('iiiii@dppppi', image_data)
else:
(ref, width, height, depth, nbytes, pad, devicePixelRatio, colorTable,
bits, iformat) = d.split('iiiii@dppi', image_data)
with Children(d):
d.putIntItem('width', width)
d.putIntItem('height', height)
@@ -1222,8 +1222,7 @@ def qdump__QLocale(d, value):
# index = int(value['d']['d']['m_data']...)
#d.check(index >= 0)
#d.check(index <= qqLocalesCount)
qtVersion = d.qtVersion()
if qtVersion < 0x50000:
if not d.qtVersionAtLeast(0x50000):
d.putStringValue(d.call('const char *', value, 'name'))
d.putPlainChildren(value)
return
@@ -1240,7 +1239,7 @@ def qdump__QLocale(d, value):
prefix = ns + 'QLocale::'
try:
if qtVersion >= 0x060700:
if qtVersionAtLeast(0x060700):
res = d.call('const char *', value, 'name', prefix + 'TagSeparator::Underscore')
else:
res = d.call('const char *', value, 'name')
@@ -1347,9 +1346,9 @@ def qdump__QMap(d, value):
def qdumpHelper_QMap(d, value, keyType, valueType):
if d.qtVersion() >= 0x60000:
if d.qtVersionAtLeast(0x060000):
qdumpHelper_Qt6_QMap(d, value, keyType, valueType)
elif d.qtVersion() >= 0x50000:
elif d.qtVersionAtLeast(0x50000):
qdumpHelper_Qt5_QMap(d, value, keyType, valueType)
else:
qdumpHelper_Qt4_QMap(d, value, keyType, valueType)
@@ -1369,7 +1368,7 @@ def qdumpHelper_Qt6_QMultiMap(d, value, keyType, valueType):
d.putBetterType('@QMultiMap<%s, %s>' % (keyType.name, valueType.name))
def qdump__QMultiMap(d, value):
if d.qtVersion() >= 0x60000:
if d.qtVersionAtLeast(0x060000):
qdumpHelper_Qt6_QMultiMap(d, value, value.type[0], value.type[1])
else:
qdump__QMap(d, value)
@@ -1449,9 +1448,9 @@ def qdump__QProcEnvKey(d, value):
def qdump__QPixmap(d, value):
if d.qtVersion() >= 0x060000:
if d.qtVersionAtLeast(0x060000):
vtbl, painters, data = value.split('ppp')
elif d.qtVersion() >= 0x050000:
elif d.qtVersionAtLeast(0x050000):
vtbl, painters, reserved, data = s = d.split('pppp', value)
else:
vtbl, painters, data = value.split('ppp')
@@ -1518,15 +1517,15 @@ def qdump__QRegion(d, value):
if d_ptr == 0:
d.putSpecialValue('empty')
else:
if d.qtVersion() >= 0x060000:
if d.qtVersionAtLeast(0x060000):
ref, _, rgn = d.split('i@p', d_ptr)
numRects, innerArea, rects, extents, innerRect = \
d.split('ii{@QList<@QRect>}{@QRect}{@QRect}', rgn)
elif d.qtVersion() >= 0x050400: # Padding removed in ee324e4ed
elif d.qtVersionAtLeast(0x050400): # Padding removed in ee324e4ed
ref, _, rgn = d.split('i@p', d_ptr)
numRects, innerArea, rects, extents, innerRect = \
d.split('ii{@QVector<@QRect>}{@QRect}{@QRect}', rgn)
elif d.qtVersion() >= 0x050000:
elif d.qtVersionAtLeast(0x050000):
ref, _, rgn = d.split('i@p', d_ptr)
numRects, _, rects, extents, innerRect, innerArea = \
d.split('i@{@QVector<@QRect>}{@QRect}{@QRect}i', rgn)
@@ -1564,7 +1563,7 @@ def qdump__QScopedPointer(d, value):
def qdump__QSet(d, value):
if d.qtVersion() >= 0x060000:
if d.qtVersionAtLeast(0x060000):
qdumpHelper_QSet6(d, value)
else:
qdumpHelper_QSet45(d, value)
@@ -1637,7 +1636,7 @@ def qdumpHelper_QSet45(d, value):
d.putItemCount(length)
if d.isExpanded():
keyType = value.type[0]
isShort = d.qtVersion() < 0x050000 and keyType.name == 'int'
isShort = not d.qtVersionAtLeast(0x050000) and keyType.name == 'int'
with Children(d, length, childType=keyType):
node = hashDataFirstNode()
for i in d.childRange():
@@ -1714,7 +1713,7 @@ def qform__QStack():
def qdump__QStack(d, value):
if d.qtVersion() >= 0x60000:
if d.qtVersionAtLeast(0x060000):
qdump__QList(d, value)
else:
qdump__QVector(d, value)
@@ -1734,7 +1733,7 @@ def qdump__QPolygon(d, value):
def qdump__QGraphicsPolygonItem(d, value):
(vtbl, dptr) = value.split('pp')
if d.qtVersion() >= 0x060000:
if d.qtVersionAtLeast(0x060000):
if d.ptrSize() == 8:
offset = 424 # sizeof(QGraphicsPolygonItemPrivate), the base
else:
@@ -1764,6 +1763,7 @@ def qform__QString():
def qdump__QString(d, value):
d.qtVersionPing(value.typeid)
d.putStringValue(value)
data, length, _ = d.stringData(value)
displayFormat = d.currentItemFormat()
@@ -1924,7 +1924,7 @@ def qdump__QUrl(d, value):
d.putValue('<invalid>')
return
if d.qtVersion() < 0x050000:
if not d.qtVersionAtLeast(0x050000):
d.call('void', value, 'port') # Warm up internal cache.
d.call('void', value, 'path')
st = '{@QString}'
@@ -2154,7 +2154,8 @@ qdumpHelper_QVariants_F = [
def qdump__QVariant(d, value):
if d.qtVersion() >= 0x060000:
d.qtVersionPing(value.typeid, 2 * d.ptrSize())
if d.qtVersionAtLeast(0x060000):
qdumpHelper__QVariant6(d, value)
else:
qdumpHelper__QVariant45(d, value)
@@ -2208,12 +2209,12 @@ def qdumpHelper__QVariant45(d, value):
return None
# Extended Core type (Qt 5)
if variantType >= 31 and variantType <= 38 and d.qtVersion() >= 0x050000:
if variantType >= 31 and variantType <= 38 and d.qtVersionAtLeast(0x050000):
qdumpHelper_QVariants_D[variantType - 31](d, value)
return None
# Extended Core type (Qt 4)
if variantType >= 128 and variantType <= 135 and d.qtVersion() < 0x050000:
if variantType >= 128 and variantType <= 135 and not d.qtVersionAtLeast(0x050000):
if variantType == 128:
d.putBetterType('@QVariant (void *)')
d.putValue('0x%x' % value.extractPointer())
@@ -2234,7 +2235,7 @@ def qdumpHelper__QVariant45(d, value):
innert = qdumpHelper_QVariants_B[variantType - 7]
elif variantType <= 74:
innert = qdumpHelper_QVariants_E[variantType - 64]
elif d.qtVersion() < 0x050000:
elif not d.qtVersionAtLeast(0x050000):
innert = qdumpHelper_QVariants_F[variantType - 76]
else:
innert = qdumpHelper_QVariants_F[variantType - 75]
@@ -2308,7 +2309,8 @@ def qform__QVector():
def qdump__QVector(d, value):
if d.qtVersion() >= 0x060000:
d.qtVersionPing(value.typeid)
if d.qtVersionAtLeast(0x060000):
data, length = d.listData(value)
d.putItemCount(length)
d.putPlotData(data, length, value.type.target()[0])
@@ -2330,7 +2332,7 @@ if False:
def qdump__QVarLengthArray(d, value):
if d.qtVersion() >= 0x060000:
if d.qtVersionAtLeast(0x060000):
cap, length, data = value.split('QQp')
else:
cap, length, data = value.split('iip')
@@ -2366,7 +2368,7 @@ def qdump_QWeakPointerHelper(d, value, isWeak, innerType=None):
d.putValue('<invalid>')
return
if d.qtVersion() >= 0x050000:
if d.qtVersionAtLeast(0x050000):
(weakref, strongref) = d.split('ii', d_ptr)
else:
(vptr, weakref, strongref) = d.split('pii', d_ptr)
@@ -2872,7 +2874,7 @@ def qdump__QJSValue(d, value):
if d.ptrSize() == 4:
qdump_32__QJSValue(d, value)
else:
if d.qtVersion() >= 0x60000:
if d.qtVersionAtLeast(0x060000):
qdump_64__QJSValue_6(d, value)
else:
qdump_64__QJSValue_5(d, value)
@@ -2906,7 +2908,7 @@ def qdump_64__QJSValue_6(d, value):
if dd == 0:
d.putValue('(undefined)')
d.putType(value.type.name + ' (undefined)')
if d.qtVersion() < 0x60500:
if not d.qtVersionAtLeast(0x60500):
typ = dd >> 47
if typ == 5:
d.putValue('(null)')
@@ -3326,7 +3328,7 @@ def qdumpHelper_QJsonObject(d, data, obj):
def qdump__QJsonValue(d, value):
(data, dd, t) = value.split('QpI')
if d.qtVersion() >= 0x050f00:
if d.qtVersionAtLeast(0x050f00):
value = d.createProxyValue((data, dd, t, False), 'QCborValue_proxy')
d.putItem(value)
return
@@ -3361,13 +3363,13 @@ def qdump__QJsonValue(d, value):
def qdump__QJsonArray(d, value):
if d.qtVersion() >= 0x060000:
if d.qtVersionAtLeast(0x060000):
dptr = d.extractPointer(value)
if not dptr:
d.putItemCount(0)
else:
qdumpHelper_QCbor_array(d, dptr, False)
elif d.qtVersion() >= 0x050f00:
elif d.qtVersionAtLeast(0x050f00):
_, container_ptr = value.split('pp')
qdumpHelper_QCbor_array(d, container_ptr, False)
else:
@@ -3375,13 +3377,13 @@ def qdump__QJsonArray(d, value):
def qdump__QJsonObject(d, value):
if d.qtVersion() >= 0x060000:
if d.qtVersionAtLeast(0x060000):
dptr = d.extractPointer(value)
if not dptr:
d.putItemCount(0)
else:
qdumpHelper_QCbor_map(d, dptr, False)
elif d.qtVersion() >= 0x050f00:
elif d.qtVersionAtLeast(0x050f00):
_, container_ptr = value.split('pp')
qdumpHelper_QCbor_map(d, container_ptr, False)
else:
@@ -3456,15 +3458,15 @@ def qdump__qfloat16(d, value):
def qdumpHelper_QCbor_string(d, container_ptr, element_index, is_bytes):
# d.split('i@{@QByteArray::size_type}pp', container_ptr) doesn't work with CDB,
# so be explicit:
data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersion() >= 0x060000 else 8)
elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersion() >= 0x060000 else d.ptrSize())
data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else 8)
elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else d.ptrSize())
elements_data_ptr, elements_size = d.vectorData(elements_pos)
element_at_n_addr = elements_data_ptr + element_index * 16 # sizeof(QtCbor::Element) == 16
element_value, _, element_flags = d.split('qII', element_at_n_addr)
enc = 'latin1' if is_bytes or (element_flags & 8) else 'utf16'
bytedata, _, _ = d.qArrayData(data_pos)
bytedata += element_value
if d.qtVersion() >= 0x060000:
if d.qtVersionAtLeast(0x060000):
bytedata_len = d.extractInt64(bytedata)
bytedata_data = bytedata + 8
else:
@@ -3493,8 +3495,8 @@ def qdumpHelper_QCbor_array(d, container_ptr, is_cbor):
return
# d.split('i@{@QByteArray::size_type}pp', container_ptr) doesn't work with CDB,
# so be explicit:
data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersion() >= 0x060000 else 8)
elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersion() >= 0x060000 else d.ptrSize())
data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else 8)
elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else d.ptrSize())
elements_data_ptr, elements_size = d.vectorData(elements_pos)
d.putItemCount(elements_size)
if d.isExpanded():
@@ -3515,8 +3517,8 @@ def qdumpHelper_QCbor_map(d, container_ptr, is_cbor):
return
# d.split('i@{@QByteArray::size_type}pp', container_ptr) doesn't work with CDB,
# so be explicit:
data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersion() >= 0x060000 else 8)
elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersion() >= 0x060000 else d.ptrSize())
data_pos = container_ptr + (2 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else 8)
elements_pos = data_pos + (3 * d.ptrSize() if d.qtVersionAtLeast(0x060000) else d.ptrSize())
elements_data_ptr, elements_size = d.vectorData(elements_pos)
elements_size = int(elements_size / 2)
d.putItemCount(elements_size)

View File

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

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)
{
if (value.isObject())

View File

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

View File

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

View File

@@ -24,7 +24,7 @@ void Barrier::start()
{
QT_ASSERT(!isRunning(), return);
m_current = 0;
m_result = {};
m_result.reset();
}
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 logHeader(const QString &logName)
{
return QString::fromLatin1("TASK TREE LOG [%1] \"%2\"").arg(currentTime(), logName);
};
/*!
Attaches a custom debug printout to a copy of \c this ExecutableItem,
issued on task startup and after the task is finished, and returns the coupled item.
@@ -1463,9 +1468,6 @@ static QString currentTime() { return QTime::currentTime().toString(Qt::ISODateW
*/
ExecutableItem ExecutableItem::withLog(const QString &logName) const
{
const auto header = [logName] {
return QString::fromLatin1("TASK TREE LOG [%1] \"%2\"").arg(currentTime(), logName);
};
struct LogStorage
{
time_point<system_clock, nanoseconds> start;
@@ -1474,21 +1476,22 @@ ExecutableItem ExecutableItem::withLog(const QString &logName) const
const Storage<LogStorage> storage;
return Group {
storage,
onGroupSetup([storage, header] {
onGroupSetup([storage, logName] {
storage->start = system_clock::now();
storage->asyncCount = activeTaskTree()->asyncCount();
qDebug().noquote() << header() << "started.";
qDebug().noquote().nospace() << logHeader(logName) << " started.";
}),
*this,
onGroupDone([storage, header](DoneWith result) {
onGroupDone([storage, logName](DoneWith result) {
const auto elapsed = duration_cast<milliseconds>(system_clock::now() - storage->start);
const int asyncCountDiff = activeTaskTree()->asyncCount() - storage->asyncCount;
QT_CHECK(asyncCountDiff >= 0);
const QMetaEnum doneWithEnum = QMetaEnum::fromType<DoneWith>();
const QString syncType = asyncCountDiff ? QString::fromLatin1("asynchronously")
: QString::fromLatin1("synchronously");
qDebug().noquote().nospace() << header() << " finished " << syncType << " with "
<< doneWithEnum.valueToKey(int(result)) << " within " << elapsed.count() << "ms.";
qDebug().noquote().nospace() << logHeader(logName) << " finished " << syncType
<< " with " << doneWithEnum.valueToKey(int(result))
<< " within " << elapsed.count() << "ms.";
})
};
}
@@ -3383,7 +3386,7 @@ TimeoutTaskAdapter::~TimeoutTaskAdapter()
void TimeoutTaskAdapter::start()
{
m_timerId = scheduleTimeout(*task(), this, [this] {
m_timerId = {};
m_timerId.reset();
emit done(DoneResult::Success);
});
}

View File

@@ -29,23 +29,6 @@ QTCREATOR_UTILS_EXPORT QString fileNameToCppIdentifier(const QString &s)
return rc;
}
QTCREATOR_UTILS_EXPORT QString headerGuard(const QString &file)
{
return headerGuard(file, QStringList());
}
QTCREATOR_UTILS_EXPORT QString headerGuard(const QString &file, const QStringList &namespaceList)
{
const QChar underscore = QLatin1Char('_');
QString rc;
for (int i = 0; i < namespaceList.count(); i++)
rc += namespaceList.at(i).toUpper() + underscore;
const QFileInfo fi(file);
rc += fileNameToCppIdentifier(fi.fileName()).toUpper();
return rc;
}
QTCREATOR_UTILS_EXPORT
void writeIncludeFileDirective(const QString &file, bool globalInclude,
QTextStream &str)

View File

@@ -17,9 +17,6 @@ namespace Utils {
// or replacing them by an underscore).
QTCREATOR_UTILS_EXPORT QString fileNameToCppIdentifier(const QString &s);
QTCREATOR_UTILS_EXPORT QString headerGuard(const QString &file);
QTCREATOR_UTILS_EXPORT QString headerGuard(const QString &file, const QStringList &namespaceList);
QTCREATOR_UTILS_EXPORT
void writeIncludeFileDirective(const QString &file,
bool globalInclude,

View File

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

View File

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

View File

@@ -51,6 +51,8 @@ using namespace Utils;
namespace Axivion::Internal {
void showIssuesFromDashboard(const QString &kind); // impl at bottom
class DashboardWidget : public QScrollArea
{
public:
@@ -147,14 +149,24 @@ void DashboardWidget::updateUi()
}
return prefix;
};
auto addValuesWidgets = [this, &toolTip](const QString &issueKind, qint64 total, qint64 added, qint64 removed, int row) {
auto linked = [](const QString &text, const QString &href, bool link) {
return link ? QString("<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);
QLabel *label = new QLabel(issueKind, this);
label->setToolTip(currentToolTip);
m_gridLayout->addWidget(label, row, 0);
label = new QLabel(QString::number(total), this);
label = new QLabel(linked(QString::number(total), issueKind, link), this);
label->setToolTip(currentToolTip);
label->setAlignment(Qt::AlignRight);
if (link) {
connect(label, &QLabel::linkActivated, this, [](const QString &issueKind) {
showIssuesFromDashboard(issueKind);
});
}
m_gridLayout->addWidget(label, row, 1);
label = new QLabel(this);
label->setPixmap(trendIcon(added, removed));
@@ -190,12 +202,12 @@ void DashboardWidget::updateUi()
allAdded += added;
qint64 removed = extract_value(counts, QStringLiteral("Removed"));
allRemoved += removed;
addValuesWidgets(issueCount.first, total, added, removed, row);
addValuesWidgets(issueCount.first, total, added, removed, row, true);
++row;
}
}
}
addValuesWidgets(Tr::tr("Total:"), allTotal, allAdded, allRemoved, row);
addValuesWidgets(Tr::tr("Total:"), allTotal, allAdded, allRemoved, row, false);
}
struct LinkWithColumns
@@ -263,7 +275,7 @@ class IssuesWidget : public QScrollArea
{
public:
explicit IssuesWidget(QWidget *parent = nullptr);
void updateUi();
void updateUi(const QString &kind);
const std::optional<Dto::TableInfoDto> currentTableInfo() const { return m_currentTableInfo; }
IssueListSearch searchFromUi() const;
@@ -378,7 +390,7 @@ IssuesWidget::IssuesWidget(QWidget *parent)
setWidgetResizable(true);
}
void IssuesWidget::updateUi()
void IssuesWidget::updateUi(const QString &kind)
{
setFiltersEnabled(false);
const std::optional<Dto::ProjectInfoDto> projectInfo = Internal::projectInfo();
@@ -392,11 +404,30 @@ void IssuesWidget::updateUi()
setFiltersEnabled(true);
// avoid refetching existing data
if (!m_currentPrefix.isEmpty() || m_issuesModel->rowCount())
if (kind.isEmpty() && (!m_currentPrefix.isEmpty() || m_issuesModel->rowCount()))
return;
if (info.issueKinds.size())
m_currentPrefix = info.issueKinds.front().prefix;
if (!kind.isEmpty()) {
const int index
= Utils::indexOf( info.issueKinds, [kind](const Dto::IssueKindInfoDto &dto) {
return dto.prefix == kind; });
if (index != -1) {
m_currentPrefix = kind;
auto kindButton = m_typesButtonGroup->button(index + 1);
if (QTC_GUARD(kindButton))
kindButton->setChecked(true);
// reset filters - if kind is not empty we get triggered from dashboard overview
if (!m_userNames.isEmpty())
m_ownerFilter->setCurrentIndex(0);
m_pathGlobFilter->clear();
if (m_versionDates.size() > 1) {
m_versionStart->setCurrentIndex(m_versionDates.count() - 1);
m_versionEnd->setCurrentIndex(0);
}
}
}
if (m_currentPrefix.isEmpty())
m_currentPrefix = info.issueKinds.size() ? info.issueKinds.front().prefix : QString{};
fetchTable();
}
@@ -767,12 +798,7 @@ public:
m_showIssues->setIcon(Icons::ZOOM_TOOLBAR.icon());
m_showIssues->setToolTip(Tr::tr("Search for issues"));
m_showIssues->setCheckable(true);
connect(m_showIssues, &QToolButton::clicked, this, [this] {
QTC_ASSERT(m_outputWidget, return);
m_outputWidget->setCurrentIndex(1);
if (auto issues = static_cast<IssuesWidget *>(m_outputWidget->widget(1)))
issues->updateUi();
});
connect(m_showIssues, &QToolButton::clicked, this, [this] { handleShowIssues({}); });
auto *butonGroup = new QButtonGroup(this);
butonGroup->addButton(m_showDashboard);
butonGroup->addButton(m_showIssues);
@@ -814,6 +840,14 @@ public:
void goToNext() final {}
void goToPrev() final {}
void handleShowIssues(const QString &kind)
{
QTC_ASSERT(m_outputWidget, return);
m_outputWidget->setCurrentIndex(1);
if (auto issues = static_cast<IssuesWidget *>(m_outputWidget->widget(1)))
issues->updateUi(kind);
}
void updateDashboard()
{
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);
}
void showIssuesFromDashboard(const QString &kind)
{
QTC_ASSERT(theAxivionOutputPane, return);
theAxivionOutputPane->handleShowIssues(kind);
}
} // Axivion::Internal

View File

@@ -474,11 +474,10 @@ ClangTool::ClangTool(const QString &name, Id id, ClangToolType type)
// Expand/Collapse
action = new QAction(this);
action->setDisabled(true);
action->setCheckable(true);
action->setIcon(Utils::Icons::EXPAND_ALL_TOOLBAR.icon());
action->setToolTip(Tr::tr("Expand All"));
connect(action, &QAction::toggled, this, [this](bool checked){
m_expandCollapse = action;
const auto handleCollapseExpandToggled = [this](bool checked){
if (checked) {
m_expandCollapse->setToolTip(Tr::tr("Collapse All"));
m_diagnosticView->expandAll();
@@ -486,8 +485,9 @@ ClangTool::ClangTool(const QString &name, Id id, ClangToolType type)
m_expandCollapse->setToolTip(Tr::tr("Expand All"));
m_diagnosticView->collapseAll();
}
});
m_expandCollapse = action;
};
connect(action, &QAction::toggled, this, handleCollapseExpandToggled);
handleCollapseExpandToggled(action->isChecked());
// Filter button
action = m_showFilter = new QAction(this);
@@ -1242,8 +1242,32 @@ QSet<Diagnostic> ClangTool::diagnostics() const
void ClangTool::onNewDiagnosticsAvailable(const Diagnostics &diagnostics, bool generateMarks)
{
QTC_ASSERT(m_diagnosticModel, return);
const int oldLevel1RowCount = m_diagnosticModel->rowCount();
const auto getOldLastLevel1Index = [&] {
return m_diagnosticModel->index(oldLevel1RowCount - 1, 0);
};
const auto getLevel2RowCountForOldLastLevel1Index = [&] {
return oldLevel1RowCount == 0 ? -1 : m_diagnosticModel->rowCount(getOldLastLevel1Index());
};
const int oldLevel2RowCount = getLevel2RowCountForOldLastLevel1Index();
m_diagnosticModel->addDiagnostics(diagnostics, generateMarks);
if (!m_expandCollapse->isChecked())
return;
// Now expand newly added items, both in existing file nodes and in newly added ones.
// We assume diagnostics arrive "in order", i.e. things are only ever added at the end
// (in the source model).
const int newLevel2RowCount = getLevel2RowCountForOldLastLevel1Index();
for (int i = oldLevel2RowCount; i < newLevel2RowCount; ++i) {
m_diagnosticView->expand(m_diagnosticFilterModel->mapFromSource(
m_diagnosticModel
->index(i, 0, m_diagnosticFilterModel->mapFromSource(getOldLastLevel1Index()))));
}
const int newLevel1RowCount = m_diagnosticFilterModel->rowCount();
for (int i = oldLevel1RowCount; i < newLevel1RowCount; ++i) {
m_diagnosticView->expandRecursively(
m_diagnosticFilterModel->mapFromSource(m_diagnosticModel->index(i, 0)));
}
}
void ClangTool::updateForCurrentState()
@@ -1273,7 +1297,6 @@ void ClangTool::updateForCurrentState()
m_goBack->setEnabled(issuesVisible > 0);
m_goNext->setEnabled(issuesVisible > 0);
m_clear->setEnabled(!isRunning);
m_expandCollapse->setEnabled(issuesVisible);
m_loadExported->setEnabled(!isRunning);
m_showFilter->setEnabled(issuesFound > 1);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -358,6 +358,11 @@ CppCompletionAssistProcessor *getCppCompletionAssistProcessor()
return new Internal::InternalCppCompletionAssistProcessor();
}
QString deriveHeaderGuard(const Utils::FilePath &filePath, ProjectExplorer::Project *project)
{
return Internal::cppFileSettingsForProject(project).headerGuard(filePath);
}
bool fileSizeExceedsLimit(const FilePath &filePath, int sizeLimitInMb)
{
if (sizeLimitInMb <= 0)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -783,6 +783,12 @@ void DebuggerItemModel::readDebuggers(const FilePath &fileName, bool isSystem)
.arg(item.command().toUserOutput(), item.id().toString(), fileName.toUserOutput());
continue;
}
if (item.engineType() == CdbEngineType
&& Abi::abisOfBinary(item.command()).value(0).wordWidth() == 32) {
qWarning() << QString("32 bit CDB \"%1\" (%2) read from \"%3\" dropped since it is not supported anymore.")
.arg(item.command().toUserOutput(), item.id().toString(), fileName.toUserOutput());
continue;
}
// FIXME: During startup, devices are not yet available, so we cannot check if the file still exists.
if (!item.command().needsDevice() && !item.command().isExecutableFile()) {
qWarning() << QString("DebuggerItem \"%1\" (%2) read from \"%3\" dropped since the command is not executable.")

View File

@@ -388,6 +388,15 @@ public:
k->setValue(DebuggerKitAspect::id(), bestLevel != DebuggerItem::DoesNotMatch ? bestItem.id() : QVariant());
}
void fix(Kit *k) override
{
const QVariant id = k->value(DebuggerKitAspect::id());
if (Utils::anyOf(DebuggerItemManager::debuggers(), Utils::equal(&DebuggerItem::id, id)))
return;
k->removeKeySilently(DebuggerKitAspect::id());
setup(k);
}
KitAspect *createKitAspect(Kit *k) const override
{
return new Internal::DebuggerKitAspectImpl(k, this);

View File

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

View File

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

View File

@@ -124,6 +124,7 @@ const char notCompatibleMessage[] = "is not compatible with target architecture"
GdbEngine::GdbEngine()
{
m_gdbProc.setProcessMode(ProcessMode::Writer);
m_gdbProc.setUseCtrlCStub(true);
setObjectName("GdbEngine");
setDebuggerName("GDB");
@@ -673,26 +674,7 @@ void GdbEngine::interruptInferior()
} else {
showStatusMessage(Tr::tr("Stop requested..."), 5000);
showMessage("TRYING TO INTERRUPT INFERIOR");
if (HostOsInfo::isWindowsHost() && !m_isQnxGdb) {
IDevice::ConstPtr dev = device();
QTC_ASSERT(dev, notifyInferiorStopFailed(); return);
DeviceProcessSignalOperation::Ptr signalOperation = dev->signalOperation();
QTC_ASSERT(signalOperation, notifyInferiorStopFailed(); return);
connect(signalOperation.get(), &DeviceProcessSignalOperation::finished,
this, [this, signalOperation](const QString &error) {
if (error.isEmpty()) {
showMessage("Interrupted " + QString::number(inferiorPid()));
notifyInferiorStopOk();
} else {
showMessage(error, LogError);
notifyInferiorStopFailed();
}
});
signalOperation->setDebuggerCommand(runParameters().debugger.command.executable());
signalOperation->interruptProcess(inferiorPid());
} else {
interruptInferior2();
}
interruptInferior2();
}
}
@@ -1265,9 +1247,11 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
handleStop1(data);
}
static QString stopSignal(const Abi &abi)
static QStringList stopSignals(const Abi &abi)
{
return QLatin1String(abi.os() == Abi::WindowsOS ? "SIGTRAP" : "SIGINT");
static QStringList winSignals = { "SIGTRAP", "SIGINT" };
static QStringList unixSignals = { "SIGINT" };
return abi.os() == Abi::WindowsOS ? winSignals : unixSignals;
}
void GdbEngine::handleStop1(const GdbMi &data)
@@ -1416,7 +1400,7 @@ void GdbEngine::handleStop2(const GdbMi &data)
QString meaning = data["signal-meaning"].data();
// Ignore these as they are showing up regularly when
// stopping debugging.
if (name == stopSignal(rp.toolChainAbi) || rp.expectedSignals.contains(name)) {
if (stopSignals(rp.toolChainAbi).contains(name) || rp.expectedSignals.contains(name)) {
showMessage(name + " CONSIDERED HARMLESS. CONTINUING.");
} else if (m_isQnxGdb && name == "0" && meaning == "Signal 0") {
showMessage("SIGNAL 0 CONSIDERED BOGUS.");
@@ -3817,9 +3801,6 @@ void GdbEngine::setupEngine()
CHECK_STATE(EngineSetupRequested);
showMessage("TRYING TO START ADAPTER");
if (isRemoteEngine())
m_gdbProc.setUseCtrlCStub(runParameters().useCtrlCStub); // This is only set for QNX
const DebuggerRunParameters &rp = runParameters();
CommandLine gdbCommand = rp.debugger.command;
@@ -4314,7 +4295,6 @@ void GdbEngine::interruptLocalInferior(qint64 pid)
showMessage("TRYING TO INTERRUPT INFERIOR BEFORE PID WAS OBTAINED", LogError);
return;
}
QString errorMessage;
if (runParameters().runAsRoot) {
Environment env = Environment::systemEnvironment();
RunControl::provideAskPassEntry(env);
@@ -4323,11 +4303,8 @@ void GdbEngine::interruptLocalInferior(qint64 pid)
proc.setEnvironment(env);
proc.start();
proc.waitForFinished();
} else if (interruptProcess(pid, GdbEngineType, &errorMessage)) {
showMessage("Interrupted " + QString::number(pid));
} else {
showMessage(errorMessage, LogError);
notifyInferiorStopFailed();
m_gdbProc.interrupt();
}
}

View File

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

View File

@@ -23,128 +23,23 @@ static inline QString msgCannotInterrupt(qint64 pid, const QString &why)
# define PROCESS_SUSPEND_RESUME (0x0800)
#endif // PROCESS_SUSPEND_RESUME
static BOOL isWow64Process(HANDLE hproc)
{
using LPFN_ISWOW64PROCESS = BOOL (WINAPI*)(HANDLE, PBOOL);
BOOL ret = false;
static LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
if (!fnIsWow64Process) {
if (HMODULE hModule = GetModuleHandle(L"kernel32.dll"))
fnIsWow64Process = reinterpret_cast<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
bool Debugger::Internal::interruptProcess(qint64 pID, int engineType, QString *errorMessage, const bool engineExecutableIs64Bit)
bool Debugger::Internal::interruptProcess(qint64 pID, QString *errorMessage)
{
bool ok = false;
HANDLE inferior = NULL;
do {
const DWORD rights = PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION
|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ
|PROCESS_DUP_HANDLE|PROCESS_TERMINATE|PROCESS_CREATE_THREAD|PROCESS_SUSPEND_RESUME;
inferior = OpenProcess(rights, FALSE, DWORD(pID));
if (inferior == NULL) {
*errorMessage = QString::fromLatin1("Cannot open process %1: %2").
arg(pID).arg(Utils::winErrorMessage(GetLastError()));
break;
}
const DWORD rights = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION | PROCESS_VM_OPERATION
| PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_DUP_HANDLE
| PROCESS_TERMINATE | PROCESS_CREATE_THREAD | PROCESS_SUSPEND_RESUME;
inferior = OpenProcess(rights, FALSE, DWORD(pID));
if (inferior == NULL) {
*errorMessage = QString::fromLatin1("Cannot open process %1: %2")
.arg(pID)
.arg(Utils::winErrorMessage(GetLastError()));
} else if (ok = DebugBreakProcess(inferior); !ok) {
*errorMessage = "DebugBreakProcess failed: " + Utils::winErrorMessage(GetLastError());
}
enum DebugBreakApi {
UseDebugBreakApi,
UseWin64Interrupt,
UseWin32Interrupt
};
/*
Windows 64 bit has a 32 bit subsystem (WOW64) which makes it possible to run a
32 bit application inside a 64 bit environment.
When GDB is used DebugBreakProcess must be called from the same system (32/64 bit) running
the inferior. If CDB is used we could in theory break wow64 processes,
but the break is actually a wow64 breakpoint. CDB is configured to ignore these
breakpoints, because they also appear on module loading.
Therefore we need helper executables (win(32/64)interrupt.exe) on Windows 64 bit calling
DebugBreakProcess from the correct system.
DebugBreak matrix for windows
Api = UseDebugBreakApi
Win64 = UseWin64Interrupt
Win32 = UseWin32Interrupt
N/A = This configuration is not possible
| Windows 32bit | Windows 64bit
| QtCreator 32bit | QtCreator 32bit | QtCreator 64bit
| Inferior 32bit | Inferior 32bit | Inferior 64bit | Inferior 32bit | Inferior 64bit |
----------|-----------------|-----------------|-----------------|-----------------|----------------|
CDB 32bit | Api | Api | NA | Win32 | NA |
64bit | NA | Win64 | Win64 | Api | Api |
----------|-----------------|-----------------|-----------------|-----------------|----------------|
GDB 32bit | Api | Api | NA | Win32 | NA |
64bit | NA | Api | Win64 | Win32 | Api |
----------|-----------------|-----------------|-----------------|-----------------|----------------|
*/
DebugBreakApi breakApi = UseDebugBreakApi;
#ifdef Q_OS_WIN64
if ((engineType == GdbEngineType && isWow64Process(inferior))
|| (engineType == CdbEngineType && !engineExecutableIs64Bit)) {
breakApi = UseWin32Interrupt;
}
#else
if (isWow64Process(GetCurrentProcess())
&& ((engineType == CdbEngineType && engineExecutableIs64Bit)
|| (engineType == GdbEngineType && !isWow64Process(inferior)))) {
breakApi = UseWin64Interrupt;
}
#endif
if (breakApi == UseDebugBreakApi) {
ok = DebugBreakProcess(inferior);
if (!ok)
*errorMessage = "DebugBreakProcess failed: " + Utils::winErrorMessage(GetLastError());
} else {
const QString executable = breakApi == UseWin32Interrupt
? QCoreApplication::applicationDirPath() + "/win32interrupt.exe"
: QCoreApplication::applicationDirPath() + "/win64interrupt.exe";
if (!QFileInfo::exists(executable)) {
*errorMessage = QString::fromLatin1(
"%1 does not exist. If you have built %2 "
"on your own, checkout "
"https://code.qt.io/cgit/qt-creator/binary-artifacts.git/.")
.arg(QDir::toNativeSeparators(executable),
QGuiApplication::applicationDisplayName());
break;
}
switch (QProcess::execute(executable, QStringList(QString::number(pID)))) {
case -2:
*errorMessage = QString::fromLatin1("Cannot start %1. Check src\\tools\\win64interrupt\\win64interrupt.c for more information.").
arg(QDir::toNativeSeparators(executable));
break;
case 0:
ok = true;
break;
default:
*errorMessage = QDir::toNativeSeparators(executable)
+ " could not break the process.";
break;
}
break;
}
} while (false);
if (inferior != NULL)
CloseHandle(inferior);
if (!ok)
@@ -159,8 +54,7 @@ GDB 32bit | Api | Api | NA | Win32
#include <errno.h>
#include <string.h>
bool Debugger::Internal::interruptProcess(qint64 pID, int /* engineType */,
QString *errorMessage, const bool /*engineExecutableIs64Bit*/)
bool Debugger::Internal::interruptProcess(qint64 pID, QString *errorMessage)
{
if (pID <= 0) {
*errorMessage = msgCannotInterrupt(pID, QString::fromLatin1("Invalid process id."));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -548,6 +548,13 @@ static void registerLuaApi()
// ... then register the settings.
LanguageClientManager::registerClientSettings(client);
// and the client type.
ClientType type;
type.id = client->m_settingsTypeId;
type.name = luaClient->m_name;
type.userAddable = false;
LanguageClientSettings::registerClientType(type);
return luaClient;
});

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

View File

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

View File

@@ -102,90 +102,20 @@ void DesktopProcessSignalOperation::killProcessSilently(qint64 pid)
void DesktopProcessSignalOperation::interruptProcessSilently(qint64 pid)
{
#ifdef Q_OS_WIN
enum SpecialInterrupt { NoSpecialInterrupt, Win32Interrupt, Win64Interrupt };
bool is64BitSystem = is64BitWindowsSystem();
SpecialInterrupt si = NoSpecialInterrupt;
if (is64BitSystem)
si = is64BitWindowsBinary(m_debuggerCommand) ? Win64Interrupt : Win32Interrupt;
/*
Windows 64 bit has a 32 bit subsystem (WOW64) which makes it possible to run a
32 bit application inside a 64 bit environment.
When GDB is used DebugBreakProcess must be called from the same system (32/64 bit) running
the inferior. If CDB is used we could in theory break wow64 processes,
but the break is actually a wow64 breakpoint. CDB is configured to ignore these
breakpoints, because they also appear on module loading.
Therefore we need helper executables (win(32/64)interrupt.exe) on Windows 64 bit calling
DebugBreakProcess from the correct system.
DebugBreak matrix for windows
Api = UseDebugBreakApi
Win64 = UseWin64InterruptHelper
Win32 = UseWin32InterruptHelper
N/A = This configuration is not possible
| Windows 32bit | Windows 64bit
| QtCreator 32bit | QtCreator 32bit | QtCreator 64bit
| Inferior 32bit | Inferior 32bit | Inferior 64bit | Inferior 32bit | Inferior 64bit
----------|-----------------|-----------------|-----------------|-----------------|----------------
CDB 32bit | Api | Api | N/A | Win32 | N/A
64bit | N/A | Win64 | Win64 | Api | Api
----------|-----------------|-----------------|-----------------|-----------------|----------------
GDB 32bit | Api | Api | N/A | Win32 | N/A
64bit | N/A | N/A | Win64 | N/A | Api
----------|-----------------|-----------------|-----------------|-----------------|----------------
*/
HANDLE inferior = NULL;
do {
const DWORD rights = PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION
|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ
|PROCESS_DUP_HANDLE|PROCESS_TERMINATE|PROCESS_CREATE_THREAD|PROCESS_SUSPEND_RESUME;
inferior = OpenProcess(rights, FALSE, pid);
if (inferior == NULL) {
appendMsgCannotInterrupt(pid, Tr::tr("Cannot open process: %1")
+ winErrorMessage(GetLastError()));
break;
}
bool creatorIs64Bit = is64BitWindowsBinary(
FilePath::fromUserInput(QCoreApplication::applicationFilePath()));
if (!is64BitSystem
|| si == NoSpecialInterrupt
|| (si == Win64Interrupt && creatorIs64Bit)
|| (si == Win32Interrupt && !creatorIs64Bit)) {
if (!DebugBreakProcess(inferior)) {
appendMsgCannotInterrupt(pid, Tr::tr("DebugBreakProcess failed:")
+ QLatin1Char(' ') + winErrorMessage(GetLastError()));
}
} else if (si == Win32Interrupt || si == Win64Interrupt) {
QString executable = QCoreApplication::applicationDirPath();
executable += si == Win32Interrupt
? QLatin1String("/win32interrupt.exe")
: QLatin1String("/win64interrupt.exe");
if (!QFileInfo::exists(executable)) {
appendMsgCannotInterrupt(pid,
Tr::tr("%1 does not exist. If you built %2 "
"yourself, check out https://code.qt.io/cgit/"
"qt-creator/binary-artifacts.git/.")
.arg(QDir::toNativeSeparators(executable),
QGuiApplication::applicationDisplayName()));
}
switch (QProcess::execute(executable, QStringList(QString::number(pid)))) {
case -2:
appendMsgCannotInterrupt(pid, Tr::tr(
"Cannot start %1. Check src\\tools\\win64interrupt\\win64interrupt.c "
"for more information.").arg(QDir::toNativeSeparators(executable)));
break;
case 0:
break;
default:
appendMsgCannotInterrupt(pid, QDir::toNativeSeparators(executable)
+ QLatin1Char(' ') + Tr::tr("could not break the process."));
break;
}
}
} while (false);
const DWORD rights = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION | PROCESS_VM_OPERATION
| PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_DUP_HANDLE
| PROCESS_TERMINATE | PROCESS_CREATE_THREAD | PROCESS_SUSPEND_RESUME;
inferior = OpenProcess(rights, FALSE, pid);
if (inferior == NULL) {
appendMsgCannotInterrupt(
pid, Tr::tr("Cannot open process: %1") + winErrorMessage(GetLastError()));
} else if (!DebugBreakProcess(inferior)) {
appendMsgCannotInterrupt(
pid,
Tr::tr("DebugBreakProcess failed:") + QLatin1Char(' ')
+ winErrorMessage(GetLastError()));
}
if (inferior != NULL)
CloseHandle(inferior);
#else

View File

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

View File

@@ -253,7 +253,12 @@ public:
: Project(FOLDER_MIMETYPE, file.isDir() ? file / ".qtcreator" / "project.json" : file)
{
QTC_CHECK(projectFilePath().absolutePath().ensureWritableDir());
QTC_CHECK(projectFilePath().ensureExistingFile());
if (!projectFilePath().exists() && QTC_GUARD(projectFilePath().ensureExistingFile())) {
QJsonObject projectJson;
projectJson.insert("$schema", "https://download.qt.io/official_releases/qtcreator/latest/installer_source/jsonschemas/project.json");
projectJson.insert(FILES_EXCLUDE_KEY, QJsonArray{QJsonValue(".qtcreator/project.json.user")});
projectFilePath().writeFileContents(QJsonDocument(projectJson).toJson());
}
setId(Id::fromString(WORKSPACE_PROJECT_ID));
setDisplayName(projectDirectory().fileName());

View File

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

View File

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

View File

@@ -47,9 +47,9 @@ QString TextureEditorContextObject::convertColorToString(const QVariant &color)
{
QString colorString;
QColor theColor;
if (color.canConvert(QVariant::Color)) {
if (color.canConvert(QMetaType(QMetaType::QColor))) {
theColor = color.value<QColor>();
} else if (color.canConvert(QVariant::Vector3D)) {
} else if (color.canConvert(QMetaType(QMetaType::QVector3D))) {
auto vec = color.value<QVector3D>();
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();
QVariant newValue = dialog->value();
if (newValue.canConvert(userType)) {
if (newValue.canConvert(QMetaType(userType))) {
QVariant newValueConverted = newValue;
bool converted = newValueConverted.convert(userType);
bool converted = newValueConverted.convert(QMetaType(userType));
if (!converted) {
// convert() fails for int to double, so we try this combination
newValueConverted = newValue;
converted = newValueConverted.convert(QMetaType::Double);
converted = newValueConverted.convert(QMetaType(QMetaType::Double));
}
if (converted)

View File

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

View File

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

View File

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

View File

@@ -110,6 +110,21 @@ public:
m_textEditorWidget->setTextDocument(m_document);
m_textEditorWidget->setupGenericHighlighter();
m_textEditorWidget->setMarksVisible(false);
QObject::connect(
m_textEditorWidget,
&TextEditorWidget::saveCurrentStateForNavigationHistory,
this,
&MarkdownEditor::saveCurrentStateForNavigationHistory);
QObject::connect(
m_textEditorWidget,
&TextEditorWidget::addSavedStateToNavigationHistory,
this,
&MarkdownEditor::addSavedStateToNavigationHistory);
QObject::connect(
m_textEditorWidget,
&TextEditorWidget::addCurrentStateToNavigationHistory,
this,
&MarkdownEditor::addCurrentStateToNavigationHistory);
auto context = new IContext(this);
context->setWidget(m_textEditorWidget);
context->setContext(Context(MARKDOWNVIEWER_TEXT_CONTEXT));
@@ -476,6 +491,18 @@ private:
}
}
void saveCurrentStateForNavigationHistory() { m_savedNavigationState = saveState(); }
void addSavedStateToNavigationHistory()
{
EditorManager::addCurrentPositionToNavigationHistory(m_savedNavigationState);
}
void addCurrentStateToNavigationHistory()
{
EditorManager::addCurrentPositionToNavigationHistory();
}
private:
QTimer m_previewTimer;
bool m_performDelayedUpdate = false;
@@ -491,6 +518,7 @@ private:
QAction *m_togglePreviewVisibleAction;
QAction *m_swapViewsAction;
std::optional<QPoint> m_previewRestoreScrollPosition;
QByteArray m_savedNavigationState;
};
class MarkdownEditorFactory final : public IEditorFactory