Merge remote-tracking branch 'origin/master' into 4.2

Change-Id: Ibc8b4de34e6790854d23b829c96a1a128ea0e6a4
This commit is contained in:
Eike Ziller
2016-10-10 09:24:59 +02:00
189 changed files with 6031 additions and 2898 deletions

View File

@@ -18,6 +18,7 @@ imagedirs = $SRCDIR/images \
$SRCDIR/../src/plugins/projectexplorer/images \
$SRCDIR/../src/plugins/qmldesigner/components/formeditor \
$SRCDIR/../src/plugins/qmldesigner/components/navigator \
$SRCDIR/../src/plugins/scxmleditor/common/images \
$SRCDIR/../src/plugins/texteditor/images
outputdir = $OUTDIR

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -137,8 +137,8 @@
\list 1
\li Select \uicontrol Tools > \uicontrol Options > \uicontrol Android to add paths to the
Android NDK and SDK.
\li Select \uicontrol Tools > \uicontrol Options > \uicontrol Devices >
\uicontrol Android to add paths to the Android NDK and SDK.
You can use the \inlineimage download.png
(\uicontrol Download) buttons to go to the sites where you can download
@@ -219,7 +219,8 @@
\section1 Using the Android Emulator
To run your application on the Android Emulator, you must create Android
virtual devices (AVD). Select \uicontrol Tools > \uicontrol Options > \uicontrol Android >
virtual devices (AVD). Select \uicontrol Tools > \uicontrol Options >
\uicontrol Devices > \uicontrol Android >
\uicontrol Add. If you run an application without a device connected to the
development PC and without an AVD specified, \QC asks you to add an AVD.

View File

@@ -51,7 +51,7 @@
\li Restart \QC to be able to use the plugin.
\li Select \uicontrol Tools > \uicontrol Options >
\li Select \uicontrol Tools > \uicontrol Options > \uicontrol Devices >
\uicontrol {Bare Metal} > \uicontrol Add > \uicontrol Default,
\uicontrol OpenCD, or \uicontrol {ST-LINK Utility} to specify
connections to GDB servers or hardware debuggers:
@@ -113,10 +113,9 @@
\li Open a project for an application you want to develop for the
device.
\li Select \uicontrol Projects > \uicontrol {Build & Run} >
\uicontrol {Add Kit}, and then select the kit for building and
running the application on the bare metal device specified in the
kit.
\li Select \uicontrol Projects > \uicontrol {Build & Run}, and then
select the kit for building and running the application on the bare
metal device specified in the kit.
\image creator-baremetal-kit-for-project.png "Adding a bare metal kit for a project"

View File

@@ -902,100 +902,125 @@
structures, but it does usually not give enough insight into more complex
structures, such as \c QObjects or associative containers. These items are
internally represented by a complex arrangement of pointers, often highly
optimized, with part of the data not directly accessible through either
sub-structures or pointers.
To give the user simple access also to these items, \QC employs so-called
\e{debugging helpers}. Debugging helpers come in two varieties, a compiled
one, for use with the CDB backend, and a set of Python scripts for use with
the GDB and LLDB backends.
optimized, with part of the data not directly accessible through neither
sub-structures nor pointers.
To give the user simple access also to these items, \QC employs Python
scripts that are called \e {debugging helpers}.
Debugging helpers are always automatically used. To force a plain C-like
display of structures, select \uicontrol Tools > \uicontrol Options >
\uicontrol Debugger > \uicontrol {Locals & Expressions}, and then deselect
the \uicontrol {Use Debugging Helper} check box. For GDB and LLDB this will
still use the Python scripts, but generate more basic output. To force plain
display for a single object or for all objects of a given type, select the
the \uicontrol {Use Debugging Helper} check box. This will still use the
Python scripts, but generate more basic output. To force the plain display
for a single object or for all objects of a given type, select the
corresponding option from the context menu.
\QC ships with debugging helpers for more than 130 of the most popular Qt
classes, Standard C++ containers and smart pointers, covering the usual
\QC ships with debugging helpers for more than 200 of the most popular Qt
classes, standard C++ containers, and smart pointers, covering the usual
needs of a C++ application developer out-of-the-box.
\section1 Extending GDB and LLDB Debugging Helpers
\section1 Extending Debugging Helpers
When using either GDB or LLDB as the debugging backend, \QC uses Python
scripts to display information in the \uicontrol {Locals and Expressions}
\QC uses Python scripts to translate raw memory contents and type information
data from native debugger backends (GDB, LLDB, and CDB are currently supported)
into the form presented to the user in the \uicontrol {Locals and Expressions}
view.
You can easily extend these scripts to cover your own types, using the same
code for both the GDB and the LLDB backend. No compilation is required, just
adding a few lines of Python. The scripts can address multiple versions of
Qt, or of your own library, at the same time.
Unlike GDB's
\l{https://sourceware.org/gdb/onlinedocs/gdb/Pretty-Printing.html#Pretty-Printing}
{pretty printers} and LLDB's \l{http://lldb.llvm.org/varformats.html}
{data formatters}, Qt Creator's debugging helpers are independent of the
native debugging backend. That is, the same code can be used with GDB on
Linux, LLDB on macOS, and CDB on Windows, or any other platform on which at
least one of the three supported backends is available.
To extend the shipped Python based debugging helpers for custom types, add
debugging helper implementations to the GDB startup file \c{~/.gdbinit}, or
specify them directly in the \uicontrol {Additional Startup Commands} in
\uicontrol Tools > \uicontrol Options > \uicontrol Debugger >
\uicontrol GDB.
To add debugging helpers for your own types, no compilation is required,
just adding a few lines of Python. The scripts can address multiple versions
of Qt, or of your own library, at the same time.
To add debugging helpers for custom types, add debugging helper
implementations to the startup file of the native debuggers (for example,
\c{~/.gdbinit} or \c{~/.lldbinit}) or specify them directly in the
\uicontrol {Additional Startup Commands} in \uicontrol Tools >
\uicontrol Options > \uicontrol Debugger > \uicontrol GDB.
\section2 Debugging Helper Overview
The implementation of a debugging helper typically consists of a single
Python function, which needs to be named \c{qdump__NS__Foo}, where
\c{NS::Foo} is the class or class template to be examined. Note that the
\c{::} scope resolution operator is replaced by double underscores \c{__}.
\c{::} scope resolution operator is replaced by double underscores: \c{__}.
Nested namespaces are possible.
The debugger plugin calls this function whenever you want to display an
\QC's debugger plugin calls this function whenever you want to display an
object of this type. The function is passed the following parameters:
\list
\li \c d of type \c Dumper, an object containing current settings and
providing facilities to build up an object representing part of the
Locals and Expressions view,
\li \c d of type \c Dumper, an object containing the current settings and
providing facilities to build up an object representing a part of
the \uicontrol {Locals and Expressions} view.
\li \c value of type \c Value, wrapping either a
\l{https://sourceware.org/gdb/onlinedocs/gdb/Values-From-Inferior.html}{gdb.Value}
or an
\l{http://lldb.llvm.org/cpp_reference/html/classlldb_1_1SBValue.html}{lldb.SBValue}.
\li \c value of type \c Value, wrapping either a
\l{https://sourceware.org/gdb/onlinedocs/gdb/Values-From-Inferior.html}
{gdb.Value} or an
\l{http://lldb.llvm.org/cpp_reference/html/classlldb_1_1SBValue.html}
{lldb.SBValue}.
\endlist
The \c{qdump__*} function has to feed the Dumper object with certain
information which is used to build up the object and its children's display
information that is used to build up the object and its children's display
in the \uicontrol {Locals and Expressions} view.
Example:
\code
def qdump__QFiniteStack(d, value):
alloc = int(value["_alloc"])
size = int(value["_size"])
alloc = value["_alloc"].integer()
size = value["_size"].integer()
d.putItemCount(size)
d.putNumChild(size)
if d.isExpanded():
innerType = d.templateArgument(value.type, 0)
d.putArrayData(innerType, value["_array"], size)
d.putArrayData(value.type[0], value["_array"], size)
\endcode
\note To create dumper functions usable with both LLDB and GDB backends,
avoid direct access to the \c gdb.* and \c lldb.* namespaces and use
avoid direct access to the \c gdb.* and \c lldb.* namespaces and use the
functions of the \c Dumper class instead.
\section2 Dumper Class
Debugging helpers can be set up to be called whenever a type name matches
a regular expression. To do so, the debugging helper's function name must
begin with \c{qdump__} (with two underscore characters). In addition,
the function needs to have a third parameter called \c regex with a default
value that specifies the regular expression that the type name should match.
For example, the Nim 0.12 compiler assigns artificial names, such as \c{TY1}
and \c{TY2}, to all generic sequences it compiles. To visualize these in
\QC, the following debugging helper may be used:
\code
def qdump__NimGenericSequence__(d, value, regex = "^TY.*$"):
size = value["Sup"]["len"]
base = value["data"].dereference()
typeobj = base.dereference().type
d.putArrayData(base, size, typeobj)
\endcode
\section2 Debugging Helper Implementation
A debugging helper creates a description of the displayed data item
in a format that is similar to GDB/MI and JSON.
For each line in the \uicontrol {Locals and Expressions} view, a string like
the following needs to be created and channeled to the debugger plugin.
\code
{iname='some internal name', # optional
addr='object address in memory', # optional
{ iname='some internal name', # optional
address='object address in memory', # optional
name='contents of the name column', # optional
value='contents of the value column',
type='contents of the type column',
numchild='number of children', # zero/nonzero is sufficient
childtype='default type of children', # optional
childnumchild='default number of grandchildren', # optional
children=[ # only needed if item is expanded in view
{iname='internal name of first child',
},
@@ -1006,99 +1031,42 @@
\endcode
The value of the \c iname field is the internal name of the object,
constituting a dot-separated list of identifiers, corresponding to the
which consists of a dot-separated list of identifiers, corresponding to the
position of the object's representation in the view. If it is not present,
is it generated by concatenating the parent object's iname, a dot, and a
it is generated by concatenating the parent object's \c iname, a dot, and a
sequential number.
The value of the \c name field is displayed in the \uicontrol Name column
of the view. If it is not specified, a simple number in brackets is used
instead.
While in theory you can build up the entire string above manually, it is
easier to employ the Dumper Python class for that purpose. The Dumper Python
class contains a complete framework to take care of the \c iname and \c addr
fields, to handle children of simple types, references, pointers, enums,
known and unknown structs as well as some convenience functions to handle
As the format is not guaranteed to be stable, it is strongly recommended
not to generate the wire format directly, but to use the abstraction
layer provided by the Python Dumper classes, specifically the \c{Dumper}
class itself, and the \c{Dumper:Value} and \c{Dumper:Type} abstractions.
These provide a complete framework to take care of the \c iname and \c addr
fields, to handle children of simple types, references, pointers, enums, and
known and unknown structs, as well as some convenience functions to handle
common situations.
\section3 Dumper Class
The \c Dumper class contains generic bookkeeping, low-level, and convenience
functions.
The member functions of the \c Dumper class are the following:
\list
\li \c{__init__(self)} - Initializes the output to an empty string and
empties the child stack. This should not be used in user code.
\li \c{put(self, value)} - Low level function to directly append to the
output string. That is also the fastest way to append output.
\li \c{putField(self, name, value)} - Appends a \c{name='value'} field.
\li \c{childRange(self)} - Returns the range of children specified in
the current \c Children scope.
\li \c{putItemCount(self, count)} - Appends a field
\c {value='<%d items'} to the output.
\li \c{putName(self, name)} - Appends a \c {name=''} field.
\li \c{putType(self, type, priority=0)} - Appends a field \c {type=''}
unless the \a type coincides with the parent's default child type or
\c putType was already called for the current item with a higher
value of \c priority.
\li \c{putBetterType(self, type)} - Overrides the last recorded
\c type.
\li \c{putNumChild(self, numchild)} - Appends a field \c {numchild=''}
unless the \c numchild coincides with the parent's default child
numchild value.
\li \c{putValue(self, value, encoding = None)} - Append a file
\c {value=''}, optionally followed by a field \c {valueencoding=''}.
The \c value needs to be convertible to a string entirely consisting
of alphanumerical values. The \c encoding parameter can be used to
specify the encoding in case the real value had to be encoded in
some way to meet the alphanumerical-only requirement. Currently the
following encodings are supported:
\list
\li 0: unencoded 8 bit data, interpreted as Latin1.
\li 1: base64 encoded 8 bit data, used for QByteArray, double quotes
are added.
\li 2: base64 encoded 16 bit data, used for QString, double quotes
are added.
\li 3: base64 encoded 32 bit data, double quotes are added.
\li 4: base64 encoded 16 bit data, without quotes (see 2)
\li 5: base64 encoded 8 bit data, without quotes (see 1)
\li 6: %02x encoded 8 bit data (as with \c QByteArray::toHex),
double quotes are added.
\li 7: %04x encoded 16 bit data (as with \c QByteArray::toHex),
double quotes are added.
\endlist
\li \c{putStringValue(self, value)} - Encodes a QString and calls
\c putValue with the correct \c encoding setting.
\li \c{putByteArrayValue(self, value)} - Encodes a QByteArray and calls
\c putValue with the correct \c encoding setting.
\li \c{isExpanded()} - Checks whether the current item is expanded in
the view.
\li \c{putItem(self, value)} - The \e {master function} that handles
basic types, references, pointers, and enums directly, iterates over
base classes and class members of compound types, and calls
\c qdump__* functions when appropriate.
\li \c{putIntItem(self, name, value)} - Equivalent to:
\code
with SubItem(self, name):
self.putValue(value)
self.putAddress(value.address)
self.putType("int")
self.putNumChild(0)
\endcode
@@ -1111,21 +1079,32 @@
self.putNumChild(0)
\endcode
\li \c{putCallItem(self, name, value, func, *args)} - Uses GDB to call
the function \c func on the value specified by \a {value} and output
the resulting item. Use \c{putCallItem} only if there is no other
way to access the data. Calls cannot be executed when inspecting a
core file, they are expensive to execute and have the potential to
change the state of the debugged program.
\li \c{putCallItem(self, name, value, func, *args)} - Uses the native
debugger backend to place the function call \c func on the value
specified by \a {value} and output the resulting item.
\li \c{putArrayData(self, type, address, size)} - Creates \c size
children of type \c type of an array-like object located at
\c address.
Native calls are extremely powerful and can leverage existing
debugging or logging facilities in the debugged process, for
example. However, they should only be used in a controlled
environment, and only if there is no other way to access the data,
for the following reasons:
\li \c{putItem(self, value)} - The "master function", handling basic
types, references, pointers and enums directly, iterates over base
classes and class members of compound types and calls \c qdump__*
functions whenever appropriate.
\list
\li Direct execution of code is dangerous. It runs native code
with the privileges of the debugged process, with the
potential to not only corrupt the debugged process, but also
to access the disk and network.
\li Calls cannot be executed when inspecting a core file.
\li Calls are expensive to set up and execute in the debugger.
\endlist
\li \c{putArrayData(self, type, address, itemCount)} - Creates the
number of children specified by \c itemCount of the type \c type of
an array-like object located at \c address.
\li \c{putSubItem(self, component, value)} - Equivalent to:
\code
@@ -1141,9 +1120,247 @@
d.put('value="<invalid>",type="<unknown>",numchild="0",')
\endcode
\li \c{put(self, value)} - A low-level function to directly append to
the output string. That is also the fastest way to append output.
\li \c{putField(self, name, value)} - Appends a \c{name='value'} field.
\li \c{childRange(self)} - Returns the range of children specified in
the current \c Children scope.
\li \c{putItemCount(self, count)} - Appends the field
\c {value='<%d items>'} to the output.
\li \c{putName(self, name)} - Appends the \c {name=''} field.
\li \c{putType(self, type, priority=0)} - Appends the field \c {type=''},
unless the \a type coincides with the parent's default child type or
\c putType was already called for the current item with a higher
value of \c priority.
\li \c{putBetterType(self, type)} - Overrides the last recorded \c type.
\li \c{putNumChild(self, numchild)} - Announces the existence
(\c numchild > 0) or non-existence of child items for the current
value. If \c putNumChild is not explicitly called, the
existence of child items is implied.
\li \c{putValue(self, value, encoding = None)} - Appends the file
\c {value=''}, optionally followed by the field \c {valueencoding=''}.
The \c value needs to be convertible to a string entirely consisting
of alphanumerical values. The \c encoding parameter can be used to
specify the encoding in case the real value had to be encoded in
some way to meet the alphanumerical-only requirement. The parameter
\c{encoding} is either a string of the form \c codec:itemsize:quote
where \c{codec} is any of \c{latin1}, \c{utf8}, \c{utf16}, \c{ucs4},
\c{int}, or \c{float}. \c{itemsize} gives the size of the basic
component of the object if it is not implied by \c codec and
\c quote specifies whether or not the value should be surrounded by
quotes in the display.
Example:
\code
# Safe transport of quirky data. Put quotes around the result.
d.putValue(d.hexencode("ABC\"DEF"), "utf8:1:1")
\endcode
\li \c{putStringValue(self, value)} - Encodes a QString and calls
\c putValue with the correct \c encoding setting.
\li \c{putByteArrayValue(self, value)} - Encodes a QByteArray and calls
\c putValue with the correct \c encoding setting.
\li \c{isExpanded(self)} - Checks whether the current item is expanded in
the view.
\li \c{createType(self, pattern, size = None)} - Creates a \c{Dumper.Type}
object. The exact operation depends on \c pattern.
\list
\li If \c pattern matches the name of a well-known type, a
\c{Dumper.Type} object describing this type is returned.
\li If \c pattern is the name of a type known to the native backend,
the returned type describes the native type.
\li Otherwise, \c pattern is used to construct a type description by
interpreting a sequence of items describing the field of a
structure as follows. Field descriptions consist of one or
more characters as follows:
\list
\li \c q - Signed 8-byte integral value
\li \c Q - Unsigned 8-byte integral value
\li \c i - Signed 4-byte integral value
\li \c I - Unsigned 4-byte integral value
\li \c h - Signed 2-byte integral value
\li \c H - Unsigned 2-byte integral value
\li \c b - Signed 1-byte integral value
\li \c B - Unsigned 1-byte integral value
\li \c d - 8-byte IEEE 754 floating point value
\li \c f - 4-byte IEEE 754 floating point value
\li \c p - A pointer, that is, an unsigned integral value of
suitable size according to the target architecture
\li \c @ - Suitable padding. The size is determined by the
preceding and following field and the target architecture
\li \c <n>s - A blob of <n> bytes, with implied alignment of 1
\li \c {<typename>} - A blob of suitable size and suitable
alignment determined by a \c{Dumper.Type} with the name
\c typename
\endlist
\endlist
\endlist
\section2 Children and SubItem Class
\section3 Dumper.Type Class
The \c{Dumper.Type} class describes the type of a piece of data, typically
a C++ class or struct, a pointer to a struct, or a primitive type, such as
an integral or floating point type.
Type objects, that is, instances of the \c{Dumper.Type} class, can be
created by native debugger backends, usually by evaluating Debug Information
built into or shipped alongside the debugged binary, or created on-the-fly
by the debugging helper.
\QC uses the possibility to provide type information on-the-fly for most Qt
classes, obliterating the need to use \e Debug builds of Qt for the purpose
of object introspection.
The member functions of the \c{Dumper.Type} class are the following:
\list
\li \c{name} - The name of this type as a string, or \c None if the type
is anonymous.
\li \c{size(self)} - Returns the size of an object of this type in
bytes.
\li \c{bitsize(self)} - Returns the size of an object of this type in
bits.
\li \c{(alignment(self)} - Returns the required alignment for objects of
this type in bytes.
\li \c{deference(self)} - Returns the dereferences type for pointer
type, \c None otherwise.
\li \c{pointer(self)} - Returns a pointer type that can be dereferenced
to this type.
\li \c{target(self)} - A convenience function that returns the item type
for array types and the dereferenced type for pointers and
references.
\li \c{stripTypedefs(self)} - Returns the underlying type if this type
is an alias.
\li \c{templateArgument(self, position, numeric = False)} - Returns the
template parameter located at \c{position} if this is a templated
type. If \c numeric is \c True, returns the parameter as an integral
value.
\li \c{fields(self)} - Returns a list of \c{Dumper:Fields} describing
the base classes and data members of this type.
\endlist
\section3 Dumper.Field Class
The \c{Dumper.Field} class describes a base class or a data member of a type
object.
The member function and properties of the \c{Dumper.Field} class are the
following:
\list
\li \c{isBaseClass} - Distinguishes between base classes and data
members.
\li \c{fieldType(self)} - Returns the type of this base class or data
member.
\li \c{parentType(self)} - Returns the owning type.
\li \c{bitsize(self)} - Returns the size of this field in bits.
\li \c{bitpos(self)} - Returns the offset of this field in the owning
type in bits.
\endlist
\section3 Dumper.Value Class
The \c{Dumper.Value} class describes a piece of data, such as instances of
C++ classes or primitive data types. It can also be used to describe
artificial items that have no direct representation in memory, such as
file contents, non-contiguous objects, or collections.
A \c{Dumper.Value} has always an associated \c{Dumper.Type}. The two
main representations of the value's actual data are:
\list
\li Python object following the Python buffer protocol, such as a Python
\c memoryview, or a \c bytes object. The \c size() should match the
size of this value's type.
\li An integral value representing a pointer to the begin of the object
in the current address space. The size of the object is given by its
type's \c{size()}.
\endlist
Knowledge of the internal representation of a \c{Dumper.Value} is typically
not required when creating a debugger helper for it.
The member function and properties of the \c{Dumper.Value} class are the
following:
\list
\li \c{integer(self)} - Returns an interpretation of this value as a
signed integral value of a suitable size.
\li \c{pointer(self)} - Returns an interpretation of this value as a
pointer in the current address space.
\li \c{members(self)} - Returns a list of \c{Dumper.Value} objects
representing the base objects and data members of this value.
\li \c{dereference(self)} - For values describing pointers, returns the
dereferenced value, and \c None otherwise.
\li \c{cast(self, type)} - Returns a value that has the same data as
this value, but the type \c type.
\li \c{address(self)} - Returns the address of this value if it consists
of a contiguous region in the current address space, and \c None
otherwise.
\li \c{data(self)} - Returns the data of this value as a Python \c bytes
object.
\li \c{split(self, pattern)} - Returns a list of values created
according to \c pattern from this value's data. Acceptable patterns
are the same as for \c{Dumper.createType}.
\li \c{dynamicTypeName(self)} - Tries to retrieve the name of the
dynamic type of this value if this is a base class object. Returns
\c None if that is not possible.
\endlist
\section3 Children and SubItem Class
The attempt to create child items might lead to errors if data is
uninitialized or corrupted. To gracefully recover in such situations, use
@@ -1164,7 +1381,6 @@
Example:
\code
d.putNumChild(2) # Annouce children to make the item expandable in the view.
if d.isExpanded():
with Children(d):
with SubItem(d):

View File

@@ -92,6 +92,15 @@
Modeling Language (UML) style models with structured diagrams and
store them in XML format.
\li \l{Editing State Charts}
You can use \QC to create applications that embed state machines. A
project wizard creates \l{https://www.w3.org/TR/scxml/}
{State Chart XML (SCXML)} files with boilerplate code that you can
edit using an experimental SCXML editor. You can use the classes in
the Qt SCXML module to embed state machines created from the files
in Qt applications.
\endlist
*/

View File

@@ -33,7 +33,7 @@
\contentspage {Qt Creator Manual}
\previouspage creator-mime-types.html
\page creator-modeling.html
\nextpage creator-building-running.html
\nextpage creator-scxml.html
\title Modeling

View File

@@ -0,0 +1,297 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
// **********************************************************************
// NOTE: the sections are not ordered by their logical order to avoid
// reshuffling the file each time the index order changes (i.e., often).
// Run the fixnavi.pl script to adjust the links to the index order.
// **********************************************************************
/*!
\contentspage {Qt Creator Manual}
\previouspage creator-modeling.html
\page creator-scxml.html
\nextpage creator-building-running.html
\title Editing State Charts
State charts provide a graphical way of modeling how a system reacts to
stimuli. This is done by defining the possible \e states that the system can
be in, and how the system can move from one state to another (\e transitions
between states). A key characteristic of event-driven systems (such as Qt
applications) is that behavior often depends not only on the last or current
\e event, but also the events that preceded it. With state charts, this
information is easy to express.
\QC provides a project wizard for adding \l{https://www.w3.org/TR/scxml/}
{State Chart XML (SCXML)} files with boilerplate code to projects and an
experimental SCXML editor for editing the state charts. You can use the
SCXML editor to add \e states and \e transitions to the files. You can then
use the classes in the Qt SCXML module to embed the state machines created
from the files in Qt applications.
\image qtcreator-scxml-editor.png SXCML Editor
You can drag and drop states from the \uicontrol {Common States} view (1) to
the state editor (2). Select a state in the state editor and use the tool
buttons (3) to create a transition (4) and its \e {target state}.
You can view the state chart structure in the \uicontrol Structure view (5)
and specify attributes for the selected state or transition in the
\uicontrol Attributes view (6).
You can use the toolbar buttons (7) to execute functions such as editing,
zooming, magnifying, navigating, and panning state charts, as well as
taking screenshots and viewing statistics.
To zoom into and out of the whole state chart in the state editor, select
\inlineimage icon-zoom-in.png
(\uicontrol {Zoom In}) or \inlineimage icon-zoom-out.png
(\uicontrol {Zoom Out}) or press \key Ctrl and use the mouse wheel. To make
the whole state chart visible in the state editor at a time, select
\inlineimage icon-fit-screen.png
(\uicontrol {Fit to View}).
To view a particular part of a large state chart in the state editor, select
\inlineimage navigator.png
(\uicontrol {Navigator}) and move the navigator frame on the part you want
to view.
To use the magnifier to zoom into a part of the state chart, select
\inlineimage zoom.png
(\uicontrol Magnifier). To move the magnifier faster, press down the
\key Alt key.
To pan the state chart, select \inlineimage icon-pan.png
(\uicontrol Panning). To increase the pace of panning, press down the
\key Shift key.
To view statistics about the numbers of states and transitions in the state
chart, select \inlineimage statistics.png
(\uicontrol {View Statistics}).
To search from the state chart, use the \uicontrol Search pane. The search
checks the whole SCXML tree for attributes that match the search criteria.
To save the currently visible part of the state chart as an image, select
\inlineimage screenshot.png
(\uicontrol {Save Screenshot}). To save the whole state chart as an image,
select \inlineimage icon-export-canvas.png
(\uicontrol {Export Canvas to Image}).
\section1 Creating State Charts
To create a state chart:
\list 1
\li Select \uicontrol Help > \uicontrol {About Plugins} >
\uicontrol Modeling > \uicontrol ScxmlEditor and restart \QC to
enable the plugin.
\li Select \uicontrol File > \uicontrol {New File or Project} >
\uicontrol {Files and Classes} > \uicontrol Modeling >
\uicontrol {State Chart} > \uicontrol Choose to create an empty
state chart and to open it in the SCXML editor.
\li Drag and drop a state from the \uicontrol {Common States} view to
the state editor.
\li Drag and drop child states to the initial state to create a
\e {compound state} or use the tool buttons to create a transition
from the selected state and its target state.
\li Select a state to edit its attributes in the \uicontrol Attributes
view.
\li Select the transition line to add edge points to it.
\li To raise or send events, for example, use the context menu commands
to add executable content to the \c <onentry> and \c <onexit>
elements of states or to transitions.
\endlist
The following sections describe how to manage states, transitions, and
executable content.
\section1 Managing States
When the state machine enters a state in response to an event, the state
that it entered becomes the \e {active state}.
State charts are hierarchical, and therefore states can be nested inside
other states, to create compound states.
In addition to basic states, you can create the following types of states:
\list
\li \e Initial state is the state the state machine enters when it
starts.
\li \e {Parallel state} contains child states that execute in parallel
and are all active simultaneously. Events are processed
independently by each child state and may trigger different
transitions for each child.
\li \e {Final state} enables a state machine to finish. When the state
machine enters a top-level final state, it emits the finished signal
and halts. You can create final states in compound states to hide
the internal details of a compound state. The outside world can only
enter the state and get a notification when the state has finished.
A parallel state finishes when all its child states reach final
states.
\li \e {History state} is a pseudo-state that represents the child state
the parent state was in the last time the parent state was exited.
Create a history state as a child of the state for which you want to
record the current child state. When the state machine detects the
presence of such a state at runtime, it automatically records the
current (real) child state when the parent state is exited. A
transition to the history state is in fact a transition to the child
state that the state machine previously saved. The state machine
automatically forwards the transition to the real child state.
\endlist
You can add new states to the state chart in the following ways:
\list
\li Drag and drop states from the \uicontrol {Common States} view to the
state editor.
\li Select a state in the state editor, and then select the
\uicontrol State tool button to create a transition and its target
state.
\li Copy and paste states within the SCXML editor or between the SCXML
editor and the \uicontrol Edit mode.
\endlist
You can drag states on top of other states to create compound states, or
you can drag child states out of their parent state. To move child states
within their parent, press down the \key Ctrl key while moving them.
You can use toolbar buttons to align states in the state editor, to adjust
their size, and to change the default color scheme. Overlapping states are
marked in red color.
To expand or collapse the state tree structure in the \uicontrol Structure
view, double-click a state.
To view a child state of a nested state in more detail in the state editor,
select \uicontrol {Zoom to State}.
To ensure that the state ids are unique within a compound state machine,
select \inlineimage fullnamespace.png
(\uicontrol {Toggle Full Namespace}). The name of the parent state is
added to the names of the child states, separated by two colons (::).
For example:
\badcode
<state id="broken">
...
<state id="broken::blinking">
...
</state>
<state id="broken::unblinking">
...
</state>
</state>
\endcode
\section1 Managing Transitions
Transitions define how a state reacts to \e events that are generated either
by the state machine or external entities. When events occur, the state
machine checks for a matching transition defined in the active state and
moves to its target state.
To create a transition from the selected state to a new state, drag and
release the mouse at the location where you want to add the target state.
When you draw a transition to the center of another state, it points to the
center of the state, but you can also draw a transition to the edge of the
state.
To add edge points to transitions, select a transition line. Only two edge
points are permitted for each line, and unnecessary edge points are removed
automatically. To remove the selected edge point, select
\uicontrol {Remove Point} in the context menu.
To add new edge points with a mouse click, select the \uicontrol Transition
tool button.
A transition label is automatically center-aligned, but you can drag it to
another position.
To remove the selected transition, select \uicontrol Remove in the context
menu.
\section1 Adding Executable Content
You can add \e {executable content} to a state chart to enable the state
machine to modify its data model and to interact with external entities.
Use the context menu commands to add executable content to the \c <onentry>
and \c <onexit> elements or to transitions:
\list
\li \c <raise> to raise events
\li \c <send> to communicate with external entities
\li \c <script> to run scripts
\li \c <assign> to modify the data model
\li \c <cancel> to cancel action execution
\li \c <log> to record information in a log
\li \c <if> to execute actions conditionally
\li \c <foreach> to iterate over the items in a collection and execute
an action for each of them
\endlist
During a transition, the state machine executes the content that you specify
for the \c <onexit> element in the state it is leaving, then the content in
the transition, and then the content for the \c <onentry> element in the
state it is entering.
You can add attributes for the selected executable content in the
\uicontrol Attributes view.
*/

View File

@@ -84,9 +84,8 @@
\li Open a project for an application you want to develop for the
device.
\li Select \uicontrol Projects > \uicontrol {Build & Run} >
\uicontrol {Add Kit} to add a kit for building and running
applications on iOS.
\li Select \uicontrol Projects > \uicontrol {Build & Run} to select
the kit for building and running applications on iOS.
\image qtcreator-ios-add-kit.png "Build & Run Settings"

View File

@@ -119,8 +119,8 @@
\li Open a project for an application you want to develop for the
device.
\li Select \uicontrol Projects > \uicontrol {Build & Run} > \uicontrol {Add Kit} to
add the kit that you specified above.
\li Select \uicontrol Projects > \uicontrol {Build & Run} to enable
the kit that you specified above.
\endlist

View File

@@ -31,7 +31,7 @@
/*!
\contentspage {Qt Creator Manual}
\previouspage creator-modeling.html
\previouspage creator-scxml.html
\page creator-building-running.html
\nextpage creator-building-targets.html

View File

@@ -52,30 +52,30 @@
\image qtcreator-project-kits.png
To add kits for the project, select \uicontrol {Add Kit}. The list displays kits
that are configured in \uicontrol Tools > \uicontrol Options > \uicontrol {Build & Run} >
\uicontrol Kits. To add kits to the list, select \uicontrol {Manage Kits}.
For more information about adding kits, see \l{Adding Kits}.
To enable kits for the project, click them in \uicontrol {Build & Run}. The
list displays kits that are configured in \uicontrol Tools >
\uicontrol Options > \uicontrol {Build & Run} > \uicontrol Kits. To modify
kit configuration or to add kits to the list, select
\uicontrol {Manage Kits} in the context menu. For more information about
managing kits, see \l{Adding Kits}.
Each kit consists of a set of values that define one environment, such as a
device, compiler, and Qt version. For more information, see
\l{Adding Qt Versions}, \l{Adding Compilers}, and \l{Adding Debuggers}.
To copy the build and run settings for a kit to another kit, select
\uicontrol {Copy to Kit} in the kit menu.
\uicontrol {Copy Steps from Other Kit} in the context menu.
To change the kit, while preserving the build and run settings, select
\uicontrol {Change Kit}.
To remove a kit, select \uicontrol {Remove Kit}.
To disable a kit for the project, select \uicontrol {Disable Kit for Project}
in the context menu.
\section1 Specifying Settings
The project pane consists of the following tabs:
The \uicontrol Projects mode displays one of the following views:
\list
\li Build & Run
\li \uicontrol {Build & Run} settings for each configured kit:
\list
@@ -86,25 +86,27 @@
\endlist
\note If you have not configured the project for building, the
\uicontrol {Build & Run} tab is replaced by the \l{Opening Projects}
{Configure Projects} tab.
\uicontrol {Build & Run} view is replaced by the
\l{Opening Projects}{Configure Projects} view.
\li \l{Specifying Editor Settings}{Editor}
\li \uicontrol {Project Settings} for each project:
\li \l{Specifying Code Style Settings}{Code Style}
\list
\li \l{Specifying Dependencies}{Dependencies}
\li \l{Specifying Editor Settings}{Editor}
\li \l{Using Clang Static Analyzer}{Clang Static Analyzer}
\li \l{Specifying Code Style Settings}{Code Style}
\li \l{To-Do Entries}{To-Do} (experimental)
\li \l{Specifying Dependencies}{Dependencies}
\li \l{Using Clang Static Analyzer}{Clang Static Analyzer}
\li \l{To-Do Entries}{To-Do} (experimental)
\endlist
\endlist
Use the \uicontrol Build and \uicontrol Run buttons to switch between the build and
run settings for the active project.
If you have multiple projects open in \QC, use the tabs at the top of the
window to navigate between their settings.
If you have multiple projects open in \QC, select the project to configure
in the list of projects.
*/

View File

@@ -44,4 +44,11 @@
Adding a QNX Neutrino device is very similar to \l{Connecting Embedded
Linux Devices}, except you need to select \uicontrol {QNX Device} in the
\uicontrol {Device Configuration} wizard.
\section1 Adding Kits for QNX Devices
To view QNX device settings, select \uicontrol Tools > \uicontrol Options >
\uicontrol Devices > \uicontrol QNX. Select the \uicontrol {Generate kits}
check box to allow \QC to generate kits for QNX development. For more
information about how to create the kits manually, see \l {Adding Kits}.
*/

View File

@@ -84,6 +84,7 @@
\li \l{Refactoring}
\li \l{Configuring the Editor}
\li \l{Modeling}
\li \l{Editing State Charts}
\endlist
\row
\li \inlineimage creator_buildingrunning.png
@@ -227,6 +228,8 @@
\endlist
\li \l{Editing MIME Types}
\li \l{Modeling}
\li \l{Editing State Charts}
\endlist
\li \l{Building and Running}
\list

View File

@@ -60,8 +60,8 @@
\li Open a project for an application you want to develop for the
device.
\li Select \uicontrol Projects > \uicontrol {Build & Run} > \uicontrol {Add Kit} to
add a kit for building and running applications on Windows
\li Select \uicontrol Projects > \uicontrol {Build & Run} to
enable a kit for building and running applications on Windows
Runtime devices (the local computer, for now), Windows Phones,
or the Windows Phone emulator.

View File

@@ -80,6 +80,8 @@ class Value:
dereference() -> Value # Dereference if value is pointer,
# remove reference if value is reference.
hasChildren() -> bool # Whether this object has subobjects.
expand() -> bool # Make sure that children are accessible.
nativeDebuggerValue() -> string # Dumper value returned from the debugger
childFromName(string name) -> Value # (optional)
childFromField(Field field) -> Value # (optional)
@@ -122,6 +124,7 @@ class Field:
parseAndEvaluate(string: expr) -> Value # or None if not possible.
lookupType(string: name) -> Type # or None if not possible.
listOfLocals() -> [ Value ] # List of items currently in scope.
readRawMemory(ULONG64 address, ULONG size) -> bytes # Read a block of data from the virtual address space

View File

@@ -0,0 +1,198 @@
############################################################################
#
# Copyright (C) 2016 The Qt Company Ltd.
# Contact: https://www.qt.io/licensing/
#
# This file is part of Qt Creator.
#
# Commercial License Usage
# Licensees holding valid commercial Qt licenses may use this file in
# accordance with the commercial license agreement provided with the
# Software or, alternatively, in accordance with the terms contained in
# a written agreement between you and The Qt Company. For licensing terms
# and conditions see https://www.qt.io/terms-conditions. For further
# information use the contact form at https://www.qt.io/contact-us.
#
# GNU General Public License Usage
# Alternatively, this file may be used under the terms of the GNU
# General Public License version 3 as published by the Free Software
# Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
# included in the packaging of this file. Please review the following
# information to ensure the GNU General Public License requirements will
# be met: https://www.gnu.org/licenses/gpl-3.0.html.
#
############################################################################
import inspect
import os
import sys
import cdbext
sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))))
from dumper import *
class Dumper(DumperBase):
def __init__(self):
DumperBase.__init__(self)
self.outputLock = threading.Lock()
self.isCdb = True
def fromNativeValue(self, nativeValue):
val = self.Value(self)
val.nativeValue = nativeValue
val.type = self.fromNativeType(nativeValue.type())
val.lIsInScope = True
val.laddress = nativeValue.address()
return val
def fromNativeType(self, nativeType):
typeobj = self.Type(self)
typeobj.nativeType = nativeType
typeobj.name = nativeType.name()
typeobj.lbitsize = nativeType.bitsize()
typeobj.code = nativeType.code()
return typeobj
def nativeTypeFields(self, nativeType):
fields = []
for nativeField in nativeType.fields():
field = self.Field(self)
field.name = nativeField.name()
field.parentType = self.fromNativeType(nativeType)
field.ltype = self.fromNativeType(nativeField.type())
field.lbitsize = nativeField.bitsize()
field.lbitpos = nativeField.bitpos()
fields.append(field)
return fields
def nativeTypeUnqualified(self, nativeType):
return self.fromNativeType(nativeType.unqualified())
def nativeTypePointer(self, nativeType):
return self.fromNativeType(nativeType.target())
def nativeTypeStripTypedefs(self, typeobj):
return self.fromNativeType(nativeType.stripTypedef())
def nativeTypeFirstBase(self, nativeType):
return None
def nativeTypeEnumDisplay(self, nativeType, intval):
# TODO: generate fake value
return None
def enumExpression(self, enumType, enumValue):
ns = self.qtNamespace()
return ns + "Qt::" + enumType + "(" \
+ ns + "Qt::" + enumType + "::" + enumValue + ")"
def pokeValue(self, typeName, *args):
return None
def parseAndEvaluate(self, exp):
return cdbext.parseAndEvaluate(exp)
def nativeTypeTemplateArgument(self, nativeType, position, numeric = False):
return self.fromNativeType(nativeType.templateArgument(position, numeric))
def nativeTypeDereference(self, nativeType):
return self.fromNativeType(nativeType.target())
def nativeTypeTarget(self, nativeType):
return self.fromNativeType(nativeType.target())
def isWindowsTarget(self):
return True
def isQnxTarget(self):
return False
def isArmArchitecture(self):
return False
def isMsvcTarget(self):
return True
def qtVersionAndNamespace(self):
return ('', 0x50700) #FIXME: use a general approach in dumper or qttypes
def qtNamespace(self):
return self.qtVersionAndNamespace()[0]
def qtVersion(self):
self.qtVersionAndNamespace()
return self.qtVersionAndNamespace()[1]
def qtTypeInfoVersion(self):
return None
def ptrSize(self):
return cdbext.pointerSize()
def put(self, stuff):
self.output += stuff
def lookupNativeType(self, name):
return cdbext.lookupType(name)
def currentThread(self):
return None
def currentFrame(self):
return None
def reportResult(self, result, args):
self.report('result={%s}' % (result))
def readRawMemory(self, address, size):
return cdbext.readRawMemory(address, size)
def findStaticMetaObject(self, typeName):
symbolName = self.mangleName(typeName + '::staticMetaObject')
symbol = self.target.FindFirstGlobalVariable(symbolName)
return symbol.AddressOf().GetValueAsUnsigned() if symbol.IsValid() else 0
def warn(self, msg):
self.put('{name="%s",value="",type="",numchild="0"},' % msg)
def fetchVariables(self, args):
(ok, res) = self.tryFetchInterpreterVariables(args)
if ok:
self.reportResult(res, args)
return
self.setVariableFetchingOptions(args)
self.output = ''
self.currentIName = 'local'
self.put('data=[')
self.anonNumber = 0
variables = []
for val in cdbext.listOfLocals():
self.currentContextValue = val
name = val.name()
value = self.fromNativeValue(val)
value.name = name
variables.append(value)
self.handleLocals(variables)
self.handleWatches(args)
self.put('],partial="%d"' % (len(self.partialVariable) > 0))
self.reportResult(self.output, args)
def report(self, stuff):
sys.stdout.write(stuff + "\n")
def loadDumpers(self, args):
msg = self.setupDumpers()
self.reportResult(msg, args)
def findValueByExpression(self, exp):
return cdbext.parseAndEvaluate(exp)
def nativeDynamicTypeName(self, address, baseType):
return None # FIXME: Seems sufficient, no idea why.

View File

@@ -32,6 +32,7 @@ import re
import time
import json
import inspect
import threading
if sys.version_info[0] >= 3:
xrange = range
@@ -94,7 +95,7 @@ BreakpointAtJavaScriptThrow, \
= range(0, 14)
# Internal codes for types
# Internal codes for types keep in sync with cdbextensions pytype.cpp
TypeCodeTypedef, \
TypeCodeStruct, \
TypeCodeVoid, \
@@ -301,6 +302,44 @@ class DumperBase:
"personaltypes",
]
# These values are never used, but the variables need to have
# some value base for the swapping logic in Children.__enter__()
# and Children.__exit__().
self.currentIName = None
self.currentValue = None
self.currentType = None
self.currentNumChild = None
self.currentMaxNumChild = None
self.currentPrintsAddress = True
self.currentChildType = None
self.currentChildNumChild = None
def setVariableFetchingOptions(self, args):
self.resultVarName = args.get('resultvarname', '')
self.expandedINames = set(args.get('expanded', []))
self.stringCutOff = int(args.get('stringcutoff', 10000))
self.displayStringLimit = int(args.get('displaystringlimit', 100))
self.typeformats = args.get('typeformats', {})
self.formats = args.get('formats', {})
self.watchers = args.get('watchers', {})
self.useDynamicType = int(args.get('dyntype', '0'))
self.useFancy = int(args.get('fancy', '0'))
self.forceQtNamespace = int(args.get('forcens', '0'))
self.passExceptions = int(args.get('passexceptions', '0'))
self.showQObjectNames = int(args.get('qobjectnames', '0'))
self.nativeMixed = int(args.get('nativemixed', '0'))
self.autoDerefPointers = int(args.get('autoderef', '0'))
self.partialVariable = args.get('partialvar', '')
self.partialUpdate = int(args.get('partial', '0'))
self.fallbackQtVersion = 0x50200
#warn('NAMESPACE: "%s"' % self.qtNamespace())
#warn('EXPANDED INAMES: %s' % self.expandedINames)
#warn('WATCHERS: %s' % self.watchers)
# The guess does not need to be updated during a fetchVariables()
# as the result is fixed during that time (ignoring "active"
# dumpers causing loading of shared objects etc).
self.currentQtNamespaceGuess = None
def resetCaches(self):
# This is a cache mapping from 'type name' to 'display alternatives'.
@@ -772,7 +811,7 @@ class DumperBase:
continue
with SubItem(self, field.name):
self.putItem(value[field])
self.putItem(value.extractField(field))
def putMembersItem(self, value, sortorder = 10):
@@ -1015,7 +1054,8 @@ class DumperBase:
if arrayByteSize == 0:
# This should not happen. But it does, see QTCREATORBUG-14755.
# GDB/GCC produce sizeof == 0 for QProcess arr[3]
s = str(value.type)
# And in the Nim string dumper.
s = value.type.name
itemCount = s[s.find('[')+1:s.find(']')]
if not itemCount:
itemCount = '100'
@@ -2449,6 +2489,8 @@ class DumperBase:
if typeobj.code == TypeCodeTypedef:
strippedType = typeobj.stripTypedefs()
self.putItem(value.cast(strippedType))
if value.lbitsize is not None and value.lbitsize != value.type.size() * 8:
typeName += " : %s" % value.lbitsize
self.putBetterType(typeName)
return
@@ -2478,7 +2520,9 @@ class DumperBase:
#warn("INTEGER: %s %s" % (value.name, value))
self.putValue(value.value())
self.putNumChild(0)
self.putType(typeobj.name)
if value.lbitsize is not None and value.lbitsize != value.type.size() * 8:
typeName += " : %s" % value.lbitsize
self.putType(typeName)
return
if typeobj.code == TypeCodeFloat:
@@ -2579,6 +2623,7 @@ class DumperBase:
self.laddress = None
self.lIsInScope = True
self.ldisplay = None
self.lbitsize = None
def check(self):
if self.laddress is not None and not self.dumper.isInt(self.laddress):
@@ -2595,8 +2640,9 @@ class DumperBase:
def stringify(self):
addr = "None" if self.laddress is None else ("0x%x" % self.laddress)
return "Value(name='%s',type=%s,data=%s,address=%s)" \
% (self.name, self.type.stringify(), self.dumper.hexencode(self.ldata), addr)
return "Value(name='%s',type=%s,bsize=%s,data=%s,address=%s)" \
% (self.name, self.type.name, self.lbitsize,
self.dumper.hexencode(self.ldata), addr)
def display(self):
if self.type.code == TypeCodeEnum:
@@ -2686,6 +2732,7 @@ class DumperBase:
fieldBitpos = field.bitpos()
fieldOffset = fieldBitpos >> 3
fieldBitpos -= fieldOffset * 8
fieldType = field.fieldType()
val = self.dumper.Value(self.dumper)
val.name = field.name
@@ -2697,7 +2744,7 @@ class DumperBase:
else:
self.dumper.check(False)
if fieldBitsize is not None and fieldBitsize % 8 != 0:
if fieldBitsize is not None and fieldBitsize != fieldType.size() * 8:
data = val.extractInteger(fieldBitsize, True)
data = data >> fieldBitpos
data = data & ((1 << fieldBitsize) - 1)
@@ -2705,7 +2752,6 @@ class DumperBase:
val.ldata = bytes(struct.pack('Q', data))
val.type = None
fieldType = field.fieldType()
if val.laddress is not None and fieldType is not None:
if fieldType.code in (TypeCodePointer, TypeCodeReference):
baseType = fieldType.dereference()
@@ -2771,6 +2817,7 @@ class DumperBase:
self.check()
val = self.dumper.Value(self.dumper)
val.laddress = self.laddress
val.lbitsize = self.lbitsize
val.ldata = self.ldata
val.type = self.dumper.createType(typish)
return val
@@ -2889,8 +2936,8 @@ class DumperBase:
#error("Not implemented")
def stringify(self):
return "Type(name='%s',bsize=%s,bpos=%s,code=%s,native=%s)" \
% (self.name, self.lbitsize, self.lbitpos, self.code, self.nativeType is not None)
return "Type(name='%s',bsize=%s,bpos=%s,code=%s,ntype=%s)" \
% (self.name, self.lbitsize, self.lbitpos, self.code, self.nativeType)
def __getitem__(self, index):
if self.dumper.isInt(index):
@@ -2994,7 +3041,7 @@ class DumperBase:
innerType.code = TypeCodeArray
return innerType
strippedType = self.stripTypdefs()
strippedType = self.stripTypedefs()
if strippedType.name != self.name:
return strippedType.target()
error("DONT KNOW TARGET FOR: %s" % self)
@@ -3334,8 +3381,20 @@ class DumperBase:
elif c == '{':
readingTypeName = True
typeName = ""
elif c == '@': # Automatic padding.
builder.autoPadNext = True
elif c == '@':
if n is None:
# Automatic padding depending on next item
builder.autoPadNext = True
else:
# Explicit padding.
builder.currentBitsize = 8 * ((builder.currentBitsize + 7) >> 3)
padding = (int(n) - (builder.currentBitsize >> 3)) % int(n)
field = self.Field(self)
field.code = None
builder.pattern += "%ds" % padding
builder.currentBitsize += padding * 8
builder.fields.append(field)
n = None
else:
error("UNKNOWN STRUCT CODE: %s" % c)
pp = builder.pattern

View File

@@ -203,41 +203,7 @@ class Dumper(DumperBase):
def prepare(self, args):
self.output = []
self.currentIName = ""
self.currentPrintsAddress = True
self.currentChildType = ""
self.currentChildNumChild = -1
self.currentMaxNumChild = -1
self.currentNumChild = -1
self.currentValue = ReportItem()
self.currentType = ReportItem()
self.currentAddress = None
self.resultVarName = args.get("resultvarname", "")
self.expandedINames = set(args.get("expanded", []))
self.stringCutOff = int(args.get("stringcutoff", 10000))
self.displayStringLimit = int(args.get("displaystringlimit", 100))
self.typeformats = args.get("typeformats", {})
self.formats = args.get("formats", {})
self.watchers = args.get("watchers", {})
self.useDynamicType = int(args.get("dyntype", "0"))
self.useFancy = int(args.get("fancy", "0"))
self.forceQtNamespace = int(args.get("forcens", "0"))
self.passExceptions = int(args.get("passexceptions", "0"))
self.showQObjectNames = int(args.get("qobjectnames", "0"))
self.nativeMixed = int(args.get("nativemixed", "0"))
self.autoDerefPointers = int(args.get("autoderef", "0"))
self.partialUpdate = int(args.get("partial", "0"))
self.fallbackQtVersion = 0x50200
#warn("NAMESPACE: '%s'" % self.qtNamespace())
#warn("EXPANDED INAMES: %s" % self.expandedINames)
#warn("WATCHERS: %s" % self.watchers)
# The guess does not need to be updated during a fetchVariables()
# as the result is fixed during that time (ignoring "active"
# dumpers causing loading of shared objects etc).
self.currentQtNamespaceGuess = None
self.setVariableFetchingOptions(args)
def fromNativeDowncastableValue(self, nativeValue):
if self.useDynamicType:
@@ -680,6 +646,9 @@ class Dumper(DumperBase):
# We get i686-w64-mingw32
return 'mingw' in gdb.TARGET_CONFIG.lower()
def isMsvcTarget(self):
return False
def qtVersionString(self):
try:
return str(gdb.lookup_symbol("qVersion")[0].value()())

View File

@@ -61,7 +61,7 @@ class Dumper(DumperBase):
def __init__(self):
DumperBase.__init__(self)
lldb.theDumper = self
self.isLldb = True
self.outputLock = threading.Lock()
self.debugger = lldb.SBDebugger.Create()
#self.debugger.SetLoggingCallback(loggingCallback)
@@ -91,30 +91,10 @@ class Dumper(DumperBase):
#for i in range(self.debugger.GetNumCategories()):
# self.debugger.GetCategoryAtIndex(i).SetEnabled(False)
self.isLldb = True
self.process = None
self.target = None
self.eventState = lldb.eStateInvalid
self.expandedINames = {}
self.passExceptions = False
self.showQObjectNames = False
self.useLldbDumpers = False
self.autoDerefPointers = True
self.useDynamicType = True
self.useFancy = True
self.formats = {}
self.typeformats = {}
self.currentContextValue = None
self.currentIName = None
self.currentValue = ReportItem()
self.currentType = ReportItem()
self.currentNumChild = None
self.currentMaxNumChild = None
self.currentPrintsAddress = True
self.currentChildType = None
self.currentChildNumChild = -1
self.currentWatchers = {}
self.runEngineAttempted = False
self.executable_ = None
self.startMode_ = None
@@ -478,6 +458,9 @@ class Dumper(DumperBase):
def isArmArchitecture(self):
return False
def isMsvcTarget(self):
return False
def qtVersionAndNamespace(self):
for func in self.target.FindFunctions('qVersion'):
name = func.GetSymbol().GetName()
@@ -630,9 +613,13 @@ class Dumper(DumperBase):
self.target.BreakpointCreateByName("qt_qmlDebugMessageAvailable")
state = 1 if self.target.IsValid() else 0
self.reportResult('success="%s",msg="%s",exe="%s"' % (state, error, self.executable_), args)
self.reportResult('success="%s",msg="%s",exe="%s"'
% (state, error, self.executable_), args)
def runEngine(self, args):
if self.runEngineAttempted:
return
self.runEngineAttempted = True
self.prepare(args)
s = threading.Thread(target=self.loop, args=[])
s.start()
@@ -877,15 +864,7 @@ class Dumper(DumperBase):
self.reportResult(res, args)
return
self.expandedINames = set(args.get('expanded', []))
self.autoDerefPointers = int(args.get('autoderef', '0'))
self.useDynamicType = int(args.get('dyntype', '0'))
self.useFancy = int(args.get('fancy', '0'))
self.passExceptions = int(args.get('passexceptions', '0'))
self.showQObjectNames = int(args.get('qobjectnames', '0'))
self.currentWatchers = args.get('watchers', {})
self.typeformats = args.get('typeformats', {})
self.formats = args.get('formats', {})
self.setVariableFetchingOptions(args)
frame = self.currentFrame()
if frame is None:
@@ -893,9 +872,7 @@ class Dumper(DumperBase):
return
self.output = ''
self.currentAddress = None
partialVariable = args.get('partialvar', "")
isPartial = len(partialVariable) > 0
isPartial = len(self.partialVariable) > 0
self.currentIName = 'local'
self.put('data=[')

View File

@@ -33,73 +33,64 @@ from dumper import *
def qdump____m128(d, value):
d.putEmptyValue()
d.putNumChild(1)
if d.isExpanded():
d.putArrayData(value.address(), 4, d.lookupType("float"))
d.putArrayData(value.address(), 4, d.lookupType('float'))
def qdump____m256(d, value):
d.putEmptyValue()
d.putNumChild(1)
if d.isExpanded():
d.putArrayData(value.address(), 8, d.lookupType("float"))
d.putArrayData(value.address(), 8, d.lookupType('float'))
def qdump____m512(d, value):
d.putEmptyValue()
d.putNumChild(1)
if d.isExpanded():
d.putArrayData(value.address(), 16, d.lookupType("float"))
d.putArrayData(value.address(), 16, d.lookupType('float'))
def qdump____m128d(d, value):
d.putEmptyValue()
d.putNumChild(1)
if d.isExpanded():
d.putArrayData(value.address(), 2, d.lookupType("double"))
d.putArrayData(value.address(), 2, d.lookupType('double'))
def qdump____m256d(d, value):
d.putEmptyValue()
d.putNumChild(1)
if d.isExpanded():
d.putArrayData(value.address(), 4, d.lookupType("double"))
d.putArrayData(value.address(), 4, d.lookupType('double'))
def qdump____m512d(d, value):
d.putEmptyValue()
d.putNumChild(1)
if d.isExpanded():
d.putArrayData(value.address(), 8, d.lookupType("double"))
d.putArrayData(value.address(), 8, d.lookupType('double'))
def qdump____m128i(d, value):
data = d.hexencode(value.data())
d.putValue(':'.join("%04x" % int(data[i:i+4], 16) for i in xrange(0, 32, 4)))
d.putNumChild(4)
d.putValue(':'.join('%04x' % int(data[i:i+4], 16) for i in xrange(0, 32, 4)))
if d.isExpanded():
with Children(d):
addr = value.address()
d.putArrayItem("uint8x16", addr, 16, "unsigned char")
d.putArrayItem("uint16x8", addr, 8, "unsigned short")
d.putArrayItem("uint32x4", addr, 4, "unsigned int")
d.putArrayItem("uint64x2", addr, 2, "unsigned long long")
d.putArrayItem('uint8x16', addr, 16, 'unsigned char')
d.putArrayItem('uint16x8', addr, 8, 'unsigned short')
d.putArrayItem('uint32x4', addr, 4, 'unsigned int')
d.putArrayItem('uint64x2', addr, 2, 'unsigned long long')
def qdump____m256i(d, value):
data = d.hexencode(value.data())
d.putValue(':'.join("%04x" % int(data[i:i+4], 16) for i in xrange(0, 64, 4)))
d.putNumChild(4)
d.putValue(':'.join('%04x' % int(data[i:i+4], 16) for i in xrange(0, 64, 4)))
if d.isExpanded():
with Children(d):
addr = value.address()
d.putArrayItem("uint8x32", addr, 32, "unsigned char")
d.putArrayItem("uint16x16", addr, 16, "unsigned short")
d.putArrayItem("uint32x8", addr, 8, "unsigned int")
d.putArrayItem("uint64x4", addr, 4, "unsigned long long")
d.putArrayItem('uint8x32', addr, 32, 'unsigned char')
d.putArrayItem('uint16x16', addr, 16, 'unsigned short')
d.putArrayItem('uint32x8', addr, 8, 'unsigned int')
d.putArrayItem('uint64x4', addr, 4, 'unsigned long long')
def qdump____m512i(d, value):
data = d.hexencode(value.data())
d.putValue(':'.join("%04x" % int(data[i:i+4], 16) for i in xrange(0, 64, 4))
+ ', ' + ':'.join("%04x" % int(data[i:i+4], 16) for i in xrange(64, 128, 4)))
d.putNumChild(2)
d.putValue(':'.join('%04x' % int(data[i:i+4], 16) for i in xrange(0, 64, 4))
+ ', ' + ':'.join('%04x' % int(data[i:i+4], 16) for i in xrange(64, 128, 4)))
if d.isExpanded():
with Children(d):
d.putArrayItem("uint32x16", value.address(), 16, "unsigned int")
d.putArrayItem("uint64x8", value.address(), 8, "unsigned long long")
d.putArrayItem('uint32x16', value.address(), 16, 'unsigned int')
d.putArrayItem('uint64x8', value.address(), 8, 'unsigned long long')
#######################################################################
#
@@ -108,7 +99,7 @@ def qdump____m512i(d, value):
#######################################################################
#def qform__Eigen__Matrix():
# return "Transposed"
# return 'Transposed'
def qdump__Eigen__Matrix(d, value):
innerType = value.type.templateArgument(0, False)
@@ -118,7 +109,7 @@ def qdump__Eigen__Matrix(d, value):
rowMajor = (int(options) & 0x1)
# The magic dimension value is -1 in Eigen3, but 10000 in Eigen2.
# 10000 x 10000 matrices are rare, vectors of dim 10000 less so.
# So "fix" only the matrix case:
# So 'fix' only the matrix case:
if argCol == 10000 and argRow == 10000:
argCol = -1
argRow = -1
@@ -127,20 +118,20 @@ def qdump__Eigen__Matrix(d, value):
ncols = argCol
p = value.address()
else:
storage = value["m_storage"]
nrows = storage["m_rows"].integer() if argRow == -1 else argRow
ncols = storage["m_cols"].integer() if argCol == -1 else argCol
p = storage["m_data"].integer()
storage = value['m_storage']
nrows = storage['m_rows'].integer() if argRow == -1 else argRow
ncols = storage['m_cols'].integer() if argCol == -1 else argCol
p = storage['m_data'].integer()
innerSize = innerType.size()
d.putValue("(%s x %s), %s" % (nrows, ncols, ["ColumnMajor", "RowMajor"][rowMajor]))
d.putField("keeporder", "1")
d.putValue('(%s x %s), %s' % (nrows, ncols, ['ColumnMajor', 'RowMajor'][rowMajor]))
d.putField('keeporder', '1')
d.putNumChild(nrows * ncols)
limit = 10000
nncols = min(ncols, limit)
nnrows = min(nrows, limit * limit / nncols)
if d.isExpanded():
#format = d.currentItemFormat() # format == 1 is "Transposed"
#format = d.currentItemFormat() # format == 1 is 'Transposed'
with Children(d, nrows * ncols, childType=innerType):
if ncols == 1 or nrows == 1:
for i in range(0, min(nrows * ncols, 10000)):
@@ -150,17 +141,41 @@ def qdump__Eigen__Matrix(d, value):
for i in range(0, nnrows):
for j in range(0, nncols):
v = d.createValue(p + (i * ncols + j) * innerSize, innerType)
d.putNamedSubItem(s, v, "[%d,%d]" % (i, j))
d.putNamedSubItem(s, v, '[%d,%d]' % (i, j))
s = s + 1
else:
s = 0
for j in range(0, nncols):
for i in range(0, nnrows):
v = d.createValue(p + (i + j * nrows) * innerSize, innerType)
d.putNamedSubItem(s, v, "[%d,%d]" % (i, j))
d.putNamedSubItem(s, v, '[%d,%d]' % (i, j))
s = s + 1
#######################################################################
#
# Nim
#
#######################################################################
def qdump__NimStringDesc(d, value):
size, reserved = value.split('pp')
data = value.address() + 2 * d.ptrSize()
d.putCharArrayHelper(data, size, d.createType('char'), 'utf8')
def qdump__NimGenericSequence__(d, value, regex = '^TY[\d]+$'):
code = value.type.stripTypedefs().code
if code == TypeCodeStruct:
size, reserved = d.split('pp', value)
data = value.address() + 2 * d.ptrSize()
typeobj = value['data'].type.dereference()
d.putItemCount(size)
d.putArrayData(data, size, typeobj)
d.putBetterType('%s (%s[%s])' % (value.type.name, typeobj.name, size))
else:
d.putEmptyValue()
d.putPlainChildren(value)
#######################################################################
#
# D
@@ -168,15 +183,15 @@ def qdump__Eigen__Matrix(d, value):
#######################################################################
def cleanDType(type):
return str(type).replace("uns long long", "string")
return str(type).replace('uns long long', 'string')
def qdump_Array(d, value):
n = value["length"]
p = value["ptr"]
n = value['length']
p = value['ptr']
t = cleanDType(value.type)[7:]
d.putType("%s[%d]" % (t, n))
if t == "char":
d.putValue(encodeCharArray(p, 100), "local8bit")
d.putType('%s[%d]' % (t, n))
if t == 'char':
d.putValue(encodeCharArray(p, 100), 'local8bit')
d.putNumChild(0)
else:
d.putEmptyValue()
@@ -190,91 +205,64 @@ def qdump_Array(d, value):
def qdump_AArray(d, value):
#n = value["length"]
#n = value['length']
# This ends up as _AArray_<key>_<value> with a single .ptr
# member of type void *. Not much that can be done here.
p = value["ptr"]
p = value['ptr']
t = cleanDType(value.type)[8:]
d.putType("%s]" % t.replace("_", "["))
d.putType('%s]' % t.replace('_', '['))
d.putEmptyValue()
d.putNumChild(1)
if d.isExpanded():
with Children(d, 1):
d.putSubItem("ptr", p)
d.putSubItem('ptr', p)
#######################################################################
#
# Display Test
# MPI
#
#######################################################################
if False:
# FIXME: Make that work
def qdump__Color(d, value):
v = value
d.putValue("(%s, %s, %s; %s)" % (v["r"], v["g"], v["b"], v["a"]))
d.putPlainChildren(value)
def qdump__Color_(d, value):
v = value
d.putValue("(%s, %s, %s; %s)" % (v["r"], v["g"], v["b"], v["a"]))
if d.isExpanded():
with Children(d):
with SubItem(d, "0"):
d.putItem(v["r"])
with SubItem(d, "1"):
d.putItem(v["g"])
with SubItem(d, "2"):
d.putItem(v["b"])
with SubItem(d, "3"):
d.putItem(v["a"])
if False:
def qdump__tree_entry(d, value):
d.putValue("len: %s, offset: %s, type: %s" %
(value["blocklength"], value["offset"], value["type"]))
d.putValue('len: %s, offset: %s, type: %s' %
(value['blocklength'], value['offset'], value['type']))
d.putNumChild(0)
def qdump__tree(d, value):
count = value["count"]
entries = value["entries"]
base = value["base"].pointer()
count = value['count']
entries = value['entries']
base = value['base'].pointer()
d.putItemCount(count)
d.putNumChild(count)
if d.isExpanded():
with Children(d):
with SubItem(d, "tree"):
with SubItem(d, 'tree'):
d.putEmptyValue()
d.putNoType()
d.putNumChild(1)
if d.isExpanded():
with Children(d):
for i in xrange(count):
d.putSubItem(Item(entries[i], iname))
with SubItem(d, "data"):
with SubItem(d, 'data'):
d.putEmptyValue()
d.putNoType()
d.putNumChild(1)
if d.isExpanded():
with Children(d):
for i in xrange(count):
with SubItem(d, i):
entry = entries[i]
mpitype = str(entry["type"])
mpitype = str(entry['type'])
d.putType(mpitype)
length = int(entry["blocklength"])
offset = int(entry["offset"])
d.putValue("%s items at %s" % (length, offset))
if mpitype == "MPI_INT":
innerType = "int"
elif mpitype == "MPI_CHAR":
innerType = "char"
elif mpitype == "MPI_DOUBLE":
innerType = "double"
length = int(entry['blocklength'])
offset = int(entry['offset'])
d.putValue('%s items at %s' % (length, offset))
if mpitype == 'MPI_INT':
innerType = 'int'
elif mpitype == 'MPI_CHAR':
innerType = 'char'
elif mpitype == 'MPI_DOUBLE':
innerType = 'double'
else:
length = 0
d.putNumChild(length)
@@ -285,70 +273,23 @@ if False:
for j in range(length):
d.putSubItem(j, p.dereference())
#struct KRBase
#{
# enum Type { TYPE_A, TYPE_B } type;
# KRBase(Type _type) : type(_type) {}
#};
#
#struct KRA : KRBase { int x; int y; KRA():KRBase(TYPE_A),x(1),y(32) {} };
#struct KRB : KRBase { KRB():KRBase(TYPE_B) {} };
#
#void testKR()
#{
# KRBase *ptr1 = new KRA;
# KRBase *ptr2 = new KRB;
# ptr2 = new KRB;
#}
def qdump__KRBase(d, value):
if getattr(value, "__nested__", None) is None:
base = ["KRA", "KRB"][int(value["type"])]
nest = value.cast(d.lookupType(base))
nest.__nested__ = True
warn("NEST %s " % dir(nest))
d.putItem(nest)
else:
d.putName("type")
d.putValue(value["type"])
d.putNoType()
if False:
def qdump__bug5106__A5106(d, value):
d.putName("a")
d.putValue("This is the value: %s" % value["m_a"])
d.putNoType()
d.putNumChild(0)
if False:
def qdump__bug6933__Base(d, value):
d.putValue("foo")
d.putPlainChildren(value)
if False:
def qdump__gdb13393__Base(d, value):
d.putValue("Base (%s)" % value["a"])
d.putType(value.type)
d.putPlainChildren(value)
def qdump__gdb13393__Derived(d, value):
d.putValue("Derived (%s, %s)" % (value["a"], value["b"]))
d.putType(value.type)
d.putPlainChildren(value)
#######################################################################
#
# KDSoap
#
#######################################################################
def qdump__KDSoapValue1(d, value):
inner = value["d"]["d"].dereference()
d.putStringValue(inner["m_name"])
inner = value['d']['d'].dereference()
d.putStringValue(inner['m_name'])
d.putPlainChildren(inner)
def qdump__KDSoapValue(d, value):
p = (value.cast(lookupType("char*")) + 4).dereference().cast(lookupType("QString"))
p = (value.cast(lookupType('char*')) + 4).dereference().cast(lookupType('QString'))
d.putStringValue(p)
d.putPlainChildren(value["d"]["d"].dereference())
d.putPlainChildren(value['d']['d'].dereference())
#######################################################################
#

View File

@@ -2063,11 +2063,63 @@ def qdump__QV4_Object(d, value):
d.putValue("PTR: 0x%x" % objectPtr)
def qdump__QV4__Value(d, value):
if d.ptrSize() == 4:
qdump_32__QV4__Value(d, value)
else:
qdump_64__QV4__Value(d, value)
def qdump_32__QV4__Value(d, value):
# QV4_Masks_SilentNaNBit = 0x00040000
# QV4_Masks_NaN_Mask = 0x7ff80000
# QV4_Masks_NotDouble_Mask = 0x7ffa0000
# QV4_Masks_Type_Mask = 0xffffc000
ns = d.qtNamespace()
v = value.split('Q')[0]
tag = v >> 32
val = v & 0xffffffff
if (tag & 0x7fff2000) == 0x7fff2000: # Int
d.putValue(val)
d.putBetterType("%sQV4::Value (int32)" % ns)
elif (tag & 0x7fff4000) == 0x7fff4000: # Bool
d.putValue(val)
d.putBetterType("%sQV4::Value (bool)" % ns)
elif (tag & 0x7fff0000) == 0x7fff0000: # Null
d.putValue(val)
d.putBetterType("%sQV4::Value (null)" % ns)
elif (tag & 0x7ffa0000) != 0x7ffa0000: # Double
d.putValue(value.split('d')[0])
d.putBetterType("%sQV4::Value (double)" % ns)
elif tag == 0x7ffa0000:
if val == 0:
d.putValue("(undefined)")
d.putBetterType("%sQV4::Value (undefined)" % ns)
else:
managed = d.createValue(val, ns + "QV4::Heap::Base")
qdump__QV4__Heap__Base(d, managed)
#d.putValue("[0x%x]" % v)
#d.putPlainChildren(value)
if d.isExpanded():
with Children(d):
with SubItem(d, "[raw]"):
d.putValue("[0x%x]" % v)
d.putType(" ");
d.putNumChild(0)
with SubItem(d, "[val]"):
d.putValue("[0x%x]" % val)
d.putType(" ");
d.putNumChild(0)
with SubItem(d, "[tag]"):
d.putValue("[0x%x]" % tag)
d.putType(" ");
d.putNumChild(0)
#with SubItem(d, "[vtable]"):
# d.putItem(d.createValue(vtable, ns + "QV4::VTable"))
# d.putType(" ");
# d.putNumChild(0)
d.putFields(value)
def qdump_64__QV4__Value(d, value):
v = value.split('Q')[0]
if d.ptrSize() == 4:
d.putValue("[0x%x]" % v)
d.putPlainChildren(value)
return
tag = v >> QV4_Masks_Tag_Shift
vtable = v & QV4_PointerMask
ns = d.qtNamespace()
@@ -2158,15 +2210,45 @@ def qdump__QV4__ScopedString(d, value):
def qdump__QJSValue(d, value):
if d.ptrSize() == 4:
qdump_32__QJSValue(d, value)
else:
qdump_64__QJSValue(d, value)
def qdump_32__QJSValue(d, value):
ns = d.qtNamespace()
dd = value.split('Q')[0]
if dd & 1:
dd = value.split('I')[0]
d.putValue("[0x%x]" % dd)
if dd == 0:
d.putValue("(null)")
d.putType(value.type.name + " (null)")
elif dd & 1:
variant = d.createValue(dd & ~3, ns + "QVariant")
qdump__QVariant(d, variant)
d.putBetterType(d.currentType.value.replace('QVariant', 'QJSValue', 1))
elif dd == 0:
elif dd & 3 == 0:
v4value = d.createValue(dd, ns + "QV4::Value")
qdump_32__QV4__Value(d, v4value)
d.putBetterType(d.currentType.value.replace('QV4::Value', 'QJSValue', 1))
return
if d.isExpanded():
with Children(d):
with SubItem(d, "[raw]"):
d.putValue("[0x%x]" % dd)
d.putType(" ");
d.putNumChild(0)
d.putFields(value)
def qdump_64__QJSValue(d, value):
ns = d.qtNamespace()
dd = value.split('Q')[0]
if dd == 0:
d.putValue("(null)")
d.putType(value.type.name + " (null)")
elif dd & 1:
variant = d.createValue(dd & ~3, ns + "QVariant")
qdump__QVariant(d, variant)
d.putBetterType(d.currentType.value.replace('QVariant', 'QJSValue', 1))
else:
d.putEmptyValue()
#qdump__QV4__Value(d, d.createValue(dd, ns + 'QV4::Value'))

View File

@@ -529,6 +529,9 @@ def qdumpHelper_std__string(d, value, charType, format):
if d.isQnxTarget():
qdumpHelper__std__string__QNX(d, value, charType, format)
return
if d.isMsvcTarget():
qdumpHelper__std__string__MSVC(d, value, charType, format)
return
data = value.extractPointer()
# We can't lookup the std::string::_Rep type without crashing LLDB,
@@ -554,6 +557,23 @@ def qdumpHelper__std__string__QNX(d, value, charType, format):
d.check(0 <= size and size <= alloc and alloc <= 100*1000*1000)
d.putCharArrayHelper(sizePtr, size, charType, format)
def qdumpHelper__std__string__MSVC(d, value, charType, format):
val = value
try:
size = value['_Mysize'].integer()
alloc = value['_Myres'].integer()
except:
val = value['_Mypair']['_Myval2']
size = d.extractUInt64(val['_Mysize'])
alloc = d.extractUInt64(val['_Myres'])
_BUF_SIZE = int(16 / charType.size());
d.check(0 <= size and size <= alloc and alloc <= 100*1000*1000)
if _BUF_SIZE <= alloc:
data = val['_Bx']['_Ptr'].pointer()
else:
data = val['_Bx']['_Buf'].address()
d.putCharArrayHelper(data, size, charType, format)
def qdump__std____1__string(d, value):
firstByte = value.split('b')[0]

View File

@@ -85,28 +85,65 @@
#include <designersupportdelegate.h>
#include <algorithm>
namespace {
bool testImportStatements(const QStringList &importStatementList, const QUrl &url, QString *errorMessage = 0) {
QQmlEngine engine;
QQmlComponent testImportComponent(&engine);
bool testImportStatements(const QStringList &importStatementList, const QUrl &url, QString *errorMessage = 0) {
// ToDo: move engine outside of this function, this makes it expensive
QQmlEngine engine;
QQmlComponent testImportComponent(&engine);
QByteArray testComponentCode = QStringList(importStatementList).join("\n").toUtf8();
QByteArray testComponentCode = QStringList(importStatementList).join("\n").toUtf8();
testImportComponent.setData(testComponentCode.append("\nItem {}\n"), url);
testImportComponent.create();
testImportComponent.setData(testComponentCode.append("\nItem {}\n"), url);
testImportComponent.create();
if (testImportComponent.errors().isEmpty()) {
return true;
} else {
if (errorMessage) {
errorMessage->append("found not working imports: ");
errorMessage->append(testImportComponent.errorString());
if (testImportComponent.isError()) {
if (errorMessage) {
errorMessage->append("found not working imports: ");
errorMessage->append(testImportComponent.errorString());
}
return false;
}
return true;
}
void sortFilterImports(const QStringList &imports, QStringList *workingImports, QStringList *failedImports, const QUrl &url, QString *errorMessage)
{
for (const QString &import : imports) {
const QStringList alreadyTestedImports = *workingImports + *failedImports;
if (!alreadyTestedImports.contains(import)) {
QStringList readyForTestImports = *workingImports;
readyForTestImports.append(import);
QString lastErrorMessage;
if (testImportStatements(readyForTestImports, url, &lastErrorMessage)) {
Q_ASSERT(!workingImports->contains(import));
workingImports->append(import);
} else {
if (imports.endsWith(import) == false) {
// the not working import is not the last import, so there could be some
// import dependency which we try with the reorderd remaining imports
QStringList reorderedImports;
std::copy_if(imports.cbegin(), imports.cend(), std::back_inserter(reorderedImports),
[&import, &alreadyTestedImports] (const QString &checkForResortingImport){
if (checkForResortingImport == import)
return false;
return !alreadyTestedImports.contains(checkForResortingImport);
});
reorderedImports.append(import);
sortFilterImports(reorderedImports, workingImports, failedImports, url, errorMessage);
} else {
Q_ASSERT(!failedImports->contains(import));
failedImports->append(import);
if (errorMessage)
errorMessage->append(lastErrorMessage);
}
}
return false;
}
}
}
} // anonymous
namespace QmlDesigner {
@@ -415,32 +452,17 @@ void NodeInstanceServer::setupImports(const QVector<AddImportContainer> &contain
QStringList workingImportStatementList;
// check possible import statements combinations
QString errorMessage;
// maybe it just works
// but first try the current order -> maybe it just works
if (testImportStatements(importStatementList, fileUrl())) {
workingImportStatementList = importStatementList;
} else {
QString firstWorkingImportStatement; //usually this will be "import QtQuick x.x"
QStringList otherImportStatements;
foreach (const QString &importStatement, importStatementList) {
if (testImportStatements(QStringList(importStatement), fileUrl()))
firstWorkingImportStatement = importStatement;
else
otherImportStatements.append(importStatement);
}
// find the bad imports from otherImportStatements
foreach (const QString &importStatement, otherImportStatements) {
if (testImportStatements(QStringList(firstWorkingImportStatement) <<
importStatement, fileUrl(), &errorMessage)) {
workingImportStatementList.append(importStatement);
}
}
workingImportStatementList.prepend(firstWorkingImportStatement);
QString errorMessage;
QStringList failedImportList;
sortFilterImports(importStatementList, &workingImportStatementList, &failedImportList, fileUrl(), &errorMessage);
if (!errorMessage.isEmpty())
sendDebugOutput(DebugOutputCommand::WarningType, errorMessage);
}
if (!errorMessage.isEmpty())
sendDebugOutput(DebugOutputCommand::WarningType, errorMessage);
setupOnlyWorkingImports(workingImportStatementList);
}

View File

@@ -165,8 +165,10 @@ void QuickItemNodeInstance::initialize(const ObjectNodeInstance::Pointer &object
quickItem()->setParentItem(qobject_cast<QQuickItem*>(nodeInstanceServer()->quickView()->rootObject()));
}
if (s_createEffectItem || instanceId() == 0)
designerSupport()->refFromEffectItem(quickItem());
if (quickItem()->window()) {
if (s_createEffectItem || instanceId() == 0)
designerSupport()->refFromEffectItem(quickItem());
}
ObjectNodeInstance::initialize(objectNodeInstance);
quickItem()->update();
@@ -582,8 +584,7 @@ void QuickItemNodeInstance::reparent(const ObjectNodeInstance::Pointer &oldParen
if (quickItem()->parentItem()) {
refresh();
if (quickItem()->window())
DesignerSupport::updateDirtyNode(quickItem());
DesignerSupport::updateDirtyNode(quickItem());
if (instanceIsValidLayoutable(oldParentInstance, oldParentProperty))
oldParentInstance->refreshLayoutable();

View File

@@ -51,6 +51,7 @@ ConnectionClient::ConnectionClient()
connectLocalSocketError();
connectLocalSocketConnected();
connectLocalSocketDisconnected();
}
void ConnectionClient::startProcessAndConnectToServerAsynchronously()
@@ -230,6 +231,14 @@ void ConnectionClient::connectLocalSocketConnected()
&ConnectionClient::resetProcessIsStarting);
}
void ConnectionClient::connectLocalSocketDisconnected()
{
connect(&localSocket,
&QLocalSocket::disconnected,
this,
&ConnectionClient::disconnectedFromLocalSocket);
}
void ConnectionClient::finishProcess()
{
finishProcess(std::move(process_));

View File

@@ -76,6 +76,7 @@ public:
signals:
void connectedToLocalSocket();
void disconnectedFromLocalSocket();
void processFinished();
protected:
@@ -102,6 +103,7 @@ private:
void printStandardError();
void connectLocalSocketConnected();
void connectLocalSocketDisconnected();
void connectProcessFinished(QProcess *process) const;
void connectProcessStarted(QProcess *process) const;
void disconnectProcessFinished(QProcess *process) const;

View File

@@ -35,6 +35,7 @@
#ifdef WITH_PYTHON
#include <Python.h>
#include "pycdbextmodule.h"
#endif
// wdbgexts.h declares 'extern WINDBG_EXTENSION_APIS ExtensionApis;'
@@ -160,7 +161,10 @@ HRESULT ExtensionContext::initialize(PULONG Version, PULONG Flags)
*Flags = 0;
#ifdef WITH_PYTHON
initCdbextPythonModule();
Py_Initialize();
PyRun_SimpleString("import cdbext");
PyRun_SimpleString("import sys");
#endif
IInterfacePointer<CIDebugClient> client;

View File

@@ -0,0 +1,187 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "pycdbextmodule.h"
#include "extensioncontext.h"
#include "symbolgroup.h"
#include "pyfield.h"
#include "pystdoutredirect.h"
#include "pytype.h"
#include "pyvalue.h"
#include <Python.h>
#include <structmember.h>
// cdbext python module
static PyObject *cdbext_parseAndEvaluate(PyObject *, PyObject *args) // -> Value
{
char *expr;
if (!PyArg_ParseTuple(args, "s", &expr))
return NULL;
CIDebugControl *control = ExtensionCommandContext::instance()->control();
control->SetExpressionSyntax(DEBUG_EXPR_CPLUSPLUS);
DEBUG_VALUE value;
if (FAILED(control->Evaluate(expr, DEBUG_VALUE_INT64, &value, NULL)))
Py_RETURN_NONE;
return Py_BuildValue("K", value.I64);
}
static PyObject *cdbext_lookupType(PyObject *, PyObject *args) // -> Type
{
char *type;
if (!PyArg_ParseTuple(args, "s", &type))
return NULL;
return lookupType(type);
}
static PyObject *cdbext_listOfLocals(PyObject *, PyObject *) // -> [ Value ]
{
ExtensionCommandContext *extCmdCtx = ExtensionCommandContext::instance();
ULONG frame;
if (FAILED(extCmdCtx->symbols()->GetCurrentScopeFrameIndex(&frame)))
return NULL;
std::string errorMessage;
LocalsSymbolGroup *sg = ExtensionContext::instance().symbolGroup(
extCmdCtx->symbols(), extCmdCtx->threadId(), int(frame), &errorMessage);
if (!sg)
return NULL;
const auto children = sg->root()->children();
auto locals = PyList_New(0);
for (AbstractSymbolGroupNode *abstractChild : children) {
Value *childValue = PyObject_New(Value, value_pytype());
if (childValue != NULL) {
if (SymbolGroupNode* child = abstractChild->asSymbolGroupNode()) {
childValue->m_index = child->index();
childValue->m_symbolGroup = sg->debugSymbolGroup();
}
}
PyList_Append(locals, reinterpret_cast<PyObject*>(childValue));
}
return locals;
}
static PyObject *cdbext_pointerSize(PyObject *, PyObject *)
{
HRESULT isPointer64Bit = ExtensionCommandContext::instance()->control()->IsPointer64Bit();
return Py_BuildValue("i", isPointer64Bit == S_OK ? 8 : 4);
}
static PyObject *cdbext_readRawMemory(PyObject *, PyObject *args)
{
ULONG64 address = 0;
ULONG size = 0;
if (!PyArg_ParseTuple(args, "Kk", &address, &size))
return NULL;
char *buffer = new char[size];
CIDebugDataSpaces *data = ExtensionCommandContext::instance()->dataSpaces();
ULONG bytesWritten = 0;
HRESULT hr = data->ReadVirtual(address, buffer, size, &bytesWritten);
if (FAILED(hr))
bytesWritten = 0;
PyObject *ret = Py_BuildValue("y#", buffer, bytesWritten);
delete[] buffer;
return ret;
}
static PyMethodDef cdbextMethods[] = {
{"parseAndEvaluate", cdbext_parseAndEvaluate, METH_VARARGS,
"Returns value of expression or None if the expression can not be resolved"},
{"lookupType", cdbext_lookupType, METH_VARARGS,
"Returns type object or None if the type can not be resolved"},
{"listOfLocals", cdbext_listOfLocals, METH_NOARGS,
"Returns list of values that are currently in scope"},
{"pointerSize", cdbext_pointerSize, METH_NOARGS,
"Returns the size of a pointer"},
{"readRawMemory", cdbext_readRawMemory, METH_VARARGS,
"Read a block of data from the virtual address space"},
{NULL, NULL, 0,
NULL} /* Sentinel */
};
static struct PyModuleDef cdbextModule = {
PyModuleDef_HEAD_INIT,
"cdbext", /* name of module */
"bridge to the creator cdb extension", /* module documentation */
-1, /* size of per-interpreter state of the module,
or -1 if the module keeps state in global variables. */
cdbextMethods
};
PyMODINIT_FUNC
PyInit_cdbext(void)
{
if (PyType_Ready(field_pytype()) < 0)
return NULL;
if (PyType_Ready(type_pytype()) < 0)
return NULL;
if (PyType_Ready(value_pytype()) < 0)
return NULL;
stdoutRedirect_pytype()->tp_new = PyType_GenericNew;
if (PyType_Ready(stdoutRedirect_pytype()) < 0)
return NULL;
PyObject *module = PyModule_Create(&cdbextModule);
if (module == NULL)
return NULL;
Py_INCREF(field_pytype());
Py_INCREF(stdoutRedirect_pytype());
Py_INCREF(type_pytype());
Py_INCREF(value_pytype());
PyModule_AddObject(module, "Field",
reinterpret_cast<PyObject *>(field_pytype()));
PyModule_AddObject(module, "StdoutRedirect",
reinterpret_cast<PyObject *>(stdoutRedirect_pytype()));
PyModule_AddObject(module, "Type",
reinterpret_cast<PyObject *>(type_pytype()));
PyModule_AddObject(module, "Value",
reinterpret_cast<PyObject *>(value_pytype()));
return module;
}
void initCdbextPythonModule()
{
PyImport_AppendInittab("cdbext", PyInit_cdbext);
}
PyObject *pyBool(bool b)
{
if (b)
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
}

View File

@@ -0,0 +1,40 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <Python.h>
void initCdbextPythonModule();
PyObject *pyBool(bool);
/* TODO's
class Field:
isBaseClass() -> bool # Whether this is a base class or normal member
parseAndEvaluate(string: expr) -> Value # or None if not possible.
*/

View File

@@ -0,0 +1,167 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "pyfield.h"
#include "pytype.h"
#include "extensioncontext.h"
PyObject *field_Name(Field *self)
{
return Py_BuildValue("s", self->m_name);
}
PyObject *field_isBaseClass(Field *)
{
return NULL;
}
bool initTypeAndOffset(Field *field)
{
auto extcmd = ExtensionCommandContext::instance();
field->m_initialized = SUCCEEDED(extcmd->symbols()->GetFieldTypeAndOffset(
field->m_module, field->m_parentTypeId,
field->m_name, &field->m_typeId, &field->m_offset));
return field->m_initialized;
}
PyObject *field_Type(Field *self)
{
if (!self->m_initialized)
if (!initTypeAndOffset(self))
return NULL;
return createType(self->m_module, self->m_typeId);
}
PyObject *field_ParentType(Field *self)
{
return createType(self->m_module, self->m_parentTypeId);
}
PyObject *field_Bitsize(Field *self)
{
if (!self->m_initialized)
if (!initTypeAndOffset(self))
return NULL;
ULONG byteSize;
auto extcmd = ExtensionCommandContext::instance();
if (FAILED(extcmd->symbols()->GetTypeSize(self->m_module, self->m_typeId, &byteSize)))
return NULL;
return Py_BuildValue("k", byteSize * 8);
}
PyObject *field_Bitpos(Field *self)
{
if (!self->m_initialized)
if (!initTypeAndOffset(self))
return NULL;
return Py_BuildValue("k", self->m_offset * 8);
}
PyObject *field_New(PyTypeObject *type, PyObject *, PyObject *)
{
Field *self = reinterpret_cast<Field *>(type->tp_alloc(type, 0));
if (self != NULL)
initField(self);
return reinterpret_cast<PyObject *>(self);
}
void field_Dealloc(Field *self)
{
delete[] self->m_name;
}
void initField(Field *field)
{
field->m_name = 0;
field->m_initialized = false;
field->m_typeId = 0;
field->m_offset = 0;
field->m_module = 0;
field->m_parentTypeId = 0;
}
static PyMethodDef fieldMethods[] = {
{"name", PyCFunction(field_Name), METH_NOARGS,
"Return the name of this field or None for anonymous fields"},
{"isBaseClass", PyCFunction(field_isBaseClass), METH_NOARGS,
"Whether this is a base class or normal member"},
{"type", PyCFunction(field_Type), METH_NOARGS,
"Type of this member"},
{"parentType", PyCFunction(field_ParentType), METH_NOARGS,
"Type of class this member belongs to"},
{"bitsize", PyCFunction(field_Bitsize), METH_NOARGS,
"Size of member in bits"},
{"bitpos", PyCFunction(field_Bitpos), METH_NOARGS,
"Offset of member in parent type in bits"},
{NULL} /* Sentinel */
};
PyTypeObject *field_pytype()
{
static PyTypeObject cdbext_FieldType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cdbext.Field", /* tp_name */
sizeof(Field), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)field_Dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"Field objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
fieldMethods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
field_New, /* tp_new */
};
return &cdbext_FieldType;
}

View File

@@ -0,0 +1,46 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <Python.h>
#include <string>
struct Field
{
PyObject_HEAD
const char *m_name; // owned
bool m_initialized;
unsigned long m_typeId;
unsigned long m_offset;
unsigned long m_parentTypeId;
ULONG64 m_module;
};
PyTypeObject *field_pytype();
void initField(Field *field);
bool initTypeAndOffset(Field *field);

View File

@@ -0,0 +1,116 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "pystdoutredirect.h"
static std::string output;
static PyObject *stdoutRedirect = nullptr;
struct StdoutRedirect
{
PyObject_HEAD
};
PyObject *stdoutRedirect_write(PyObject * /*self*/, PyObject *args)
{
char *string;
PyArg_ParseTuple(args, "s", &string);
output += string;
return Py_BuildValue("");
}
PyObject *stdoutRedirect_flush(PyObject * /*self*/, PyObject * /*args*/)
{
return Py_BuildValue("");
}
static PyMethodDef StdoutRedirectMethods[] =
{
{"write", stdoutRedirect_write, METH_VARARGS, "sys.stdout.write"},
{"flush", stdoutRedirect_flush, METH_VARARGS, "sys.stdout.flush"},
{0, 0, 0, 0} // sentinel
};
PyTypeObject *stdoutRedirect_pytype()
{
static PyTypeObject cdbext_StdoutRedirectType =
{
PyVarObject_HEAD_INIT(NULL, 0)
"cdbext.StdoutRedirect", /* tp_name */
sizeof(StdoutRedirect), /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"stdout redirector", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
StdoutRedirectMethods, /* tp_methods */
};
return &cdbext_StdoutRedirectType;
}
void startCapturePyStdout()
{
if (stdoutRedirect != nullptr)
endCapturePyStdout();
stdoutRedirect = _PyObject_New(stdoutRedirect_pytype());
if (PySys_SetObject("stdout", stdoutRedirect) != 0)
PySys_SetObject("stdout", PySys_GetObject("__stdout__"));
if (PySys_SetObject("stderr", stdoutRedirect) != 0)
PySys_SetObject("stderr", PySys_GetObject("__stderr__"));
PyObject_CallMethod(stdoutRedirect, "write", "s", "text");
output.clear();
}
std::string getPyStdout()
{
return output;
}
void endCapturePyStdout()
{
PySys_SetObject("stdout", PySys_GetObject("__stdout__"));
PySys_SetObject("stderr", PySys_GetObject("__stderr__"));
Py_DecRef(stdoutRedirect);
stdoutRedirect = nullptr;
}

View File

@@ -0,0 +1,35 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <Python.h>
#include <string>
PyTypeObject *stdoutRedirect_pytype();
void startCapturePyStdout();
std::string getPyStdout();
void endCapturePyStdout();

View File

@@ -0,0 +1,356 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "pytype.h"
#include <Python.h>
#include "extensioncontext.h"
#include "pycdbextmodule.h"
#include "pyfield.h"
#include "stringutils.h"
#include "symbolgroupvalue.h"
enum TypeCodes {
TypeCodeTypedef,
TypeCodeStruct,
TypeCodeVoid,
TypeCodeIntegral,
TypeCodeFloat,
TypeCodeEnum,
TypeCodePointer,
TypeCodeArray,
TypeCodeComplex,
TypeCodeReference,
TypeCodeFunction,
TypeCodeMemberPointer,
TypeCodeFortranString
};
PyObject *lookupType(const std::string &typeNameIn)
{
std::string typeName = typeNameIn;
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
ULONG64 module;
ULONG typeId;
if (FAILED(symbols->GetSymbolTypeId(typeName.c_str(), &typeId, &module)))
Py_RETURN_NONE;
return createType(module, typeId);
}
char *getTypeName(ULONG64 module, ULONG typeId)
{
char *typeName = 0;
auto symbols = ExtensionCommandContext::instance()->symbols();
ULONG size = 0;
symbols->GetTypeName(module, typeId, NULL, 0, &size);
if (size > 0) {
typeName = new char[size];
if (FAILED(symbols->GetTypeName(module, typeId, typeName, size, &size))) {
delete[] typeName;
typeName = new char[1];
typeName[0] = 0;
}
}
return typeName;
}
const char *getTypeName(Type *type)
{
if (type->m_name == 0)
type->m_name = getTypeName(type->m_module, type->m_typeId);
return type->m_name;
}
PyObject *type_Name(Type *self)
{
return Py_BuildValue("s", getTypeName(self));
}
PyObject *type_bitSize(Type *self)
{
ULONG size;
auto extcmd = ExtensionCommandContext::instance();
if (FAILED(extcmd->symbols()->GetTypeSize(self->m_module, self->m_typeId, &size)))
return NULL;
return Py_BuildValue("k", size * 8);
}
bool isType(const std::string &typeName, const std::vector<std::string> &types)
{
return std::find(types.begin(), types.end(), typeName) != types.end();
}
PyObject *type_Code(Type *self)
{
static const std::vector<std::string> integralTypes({"bool",
"char", "unsigned char", "char16_t", "char32_t", "wchar_t",
"short", "unsigned short", "int", "unsigned int",
"long", "unsigned long", "int64", "unsigned int64"});
static const std::vector<std::string> floatTypes({"float", "double"});
TypeCodes code = TypeCodeStruct;
const char *typeNameCstr = getTypeName(self);
if (typeNameCstr == 0)
Py_RETURN_NONE;
const std::string typeName(typeNameCstr);
if (SymbolGroupValue::isArrayType(typeName))
code = TypeCodeArray;
else if (endsWith(typeName, "*"))
code = TypeCodePointer;
else if (typeName.find("<function>") != std::string::npos)
code = TypeCodeFunction;
else if (isType(typeName, integralTypes))
code = TypeCodeIntegral;
else if (isType(typeName, floatTypes))
code = TypeCodeFloat;
return Py_BuildValue("k", code);
}
PyObject *type_Unqualified(Type *self)
{
Py_XINCREF(self);
return (PyObject *)self;
}
PyObject *type_Target(Type *self)
{
std::string typeName(getTypeName(self));
if (!endsWith(typeName, "*")) {
Py_XINCREF(self);
return (PyObject *)self;
}
typeName = typeName.substr(0, typeName.length() - 1);
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
ULONG typeId;
if (FAILED(symbols->GetTypeId(self->m_module, typeName.c_str(), &typeId)))
return NULL;
return createType(self->m_module, typeId);
}
PyObject *type_StripTypedef(Type *self)
{
Py_XINCREF(self);
return (PyObject *)self;
}
PyObject *type_Fields(Type *self)
{
CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
auto fields = PyList_New(0);
for (ULONG fieldIndex = 0;; ++fieldIndex) {
ULONG fieldNameSize = 0;
symbols->GetFieldName(self->m_module, self->m_typeId, fieldIndex, NULL, 0, &fieldNameSize);
if (fieldNameSize == 0)
break;
char *name = new char[fieldNameSize];
if (FAILED(symbols->GetFieldName(self->m_module, self->m_typeId, fieldIndex, name,
fieldNameSize, NULL))) {
delete[] name;
break;
}
Field *field = PyObject_New(Field, field_pytype());
if (field == NULL)
return fields;
initField(field);
field->m_name = name;
field->m_parentTypeId = self->m_typeId;
field->m_module = self->m_module;
PyList_Append(fields, reinterpret_cast<PyObject*>(field));
}
return fields;
}
std::vector<std::string> innerTypesOf(const std::string &t)
{
std::vector<std::string> rc;
std::string::size_type pos = t.find('<');
if (pos == std::string::npos)
return rc;
rc.reserve(5);
const std::string::size_type size = t.size();
// Record all elements of level 1 to work correctly for
// 'std::map<std::basic_string< .. > >'
unsigned level = 0;
std::string::size_type start = 0;
for ( ; pos < size ; pos++) {
const char c = t.at(pos);
switch (c) {
case '<':
if (++level == 1)
start = pos + 1;
break;
case '>':
if (--level == 0) { // last element
std::string innerType = t.substr(start, pos - start);
trimFront(innerType);
trimBack(innerType);
rc.push_back(innerType);
return rc;
}
break;
case ',':
if (level == 1) { // std::map<a, b>: start anew at ','.
std::string innerType = t.substr(start, pos - start);
trimFront(innerType);
trimBack(innerType);
rc.push_back(innerType);
start = pos + 1;
}
break;
}
}
return rc;
}
PyObject *type_TemplateArgument(Type *self, PyObject *args)
{
unsigned int index;
bool numeric;
if (!PyArg_ParseTuple(args, "Ib", &index, &numeric))
return NULL;
std::vector<std::string> innerTypes = innerTypesOf(getTypeName(self));
if (innerTypes.size() <= index)
Py_RETURN_NONE;
const std::string &innerType = innerTypes.at(index);
if (numeric) {
try {
return Py_BuildValue("i", std::stoi(innerType));
}
catch (std::invalid_argument) {
return NULL;
}
}
return lookupType(innerType);
}
PyObject *type_New(PyTypeObject *type, PyObject *, PyObject *)
{
Type *self = reinterpret_cast<Type *>(type->tp_alloc(type, 0));
if (self != NULL) {
self->m_name = nullptr;
self->m_typeId = 0;
self->m_module = 0;
}
return reinterpret_cast<PyObject *>(self);
}
void type_Dealloc(Type *self)
{
delete[] self->m_name;
}
PyObject *createType(ULONG64 module, ULONG typeId)
{
Type *type = PyObject_New(Type, type_pytype());
type->m_module = module;
type->m_typeId = typeId;
type->m_name = nullptr;
return reinterpret_cast<PyObject *>(type);
}
static PyMethodDef typeMethods[] = {
{"name", PyCFunction(type_Name), METH_NOARGS,
"Return the type name"},
{"bitsize", PyCFunction(type_bitSize), METH_NOARGS,
"Return the size of the type in bits"},
{"code", PyCFunction(type_Code), METH_NOARGS,
"Return type code"},
{"unqualified", PyCFunction(type_Unqualified), METH_NOARGS,
"Type without const/volatile"},
{"target", PyCFunction(type_Target), METH_NOARGS,
"Type dereferenced if it is a pointer type, element if array etc"},
{"stripTypedef", PyCFunction(type_StripTypedef), METH_NOARGS,
"Type with typedefs removed"},
{"fields", PyCFunction(type_Fields), METH_NOARGS,
"List of fields (member and base classes) of this type"},
{"templateArgument", PyCFunction(type_TemplateArgument), METH_VARARGS,
"Returns template argument at position"},
{NULL} /* Sentinel */
};
static PyMemberDef typeMembers[] = {
{const_cast<char *>("id"), T_ULONG, offsetof(Type, m_typeId), 0,
const_cast<char *>("type id")},
{const_cast<char *>("moduleBase"), T_ULONGLONG, offsetof(Type, m_module), 0,
const_cast<char *>("module base address")},
{NULL} /* Sentinel */
};
PyTypeObject *type_pytype()
{
static PyTypeObject cdbext_TypeType = {
PyVarObject_HEAD_INIT(NULL, 0)
"cdbext.Type", /* tp_name */
sizeof(Type), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)type_Dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"Type objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
typeMethods, /* tp_methods */
typeMembers, /* tp_members (just for debugging)*/
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
type_New, /* tp_new */
};
return &cdbext_TypeType;
}

View File

@@ -0,0 +1,47 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "symbolgroup.h"
#include <Python.h>
#include "structmember.h"
#include <string>
struct Type
{
PyObject_HEAD
ULONG m_typeId;
ULONG64 m_module;
char *m_name; // owned
};
PyTypeObject *type_pytype();
char *getTypeName(ULONG64 module, ULONG typeId);
PyObject *lookupType(const std::string &typeName);
PyObject *createType(ULONG64 module, ULONG typeId);

View File

@@ -0,0 +1,372 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "pyvalue.h"
#include "extensioncontext.h"
#include "pycdbextmodule.h"
#include "pytype.h"
#include "pyfield.h"
#include "stringutils.h"
std::string getSymbolName(CIDebugSymbolGroup *sg, ULONG index)
{
ULONG size = 0;
sg->GetSymbolName(index, NULL, 0, &size);
if (size == 0)
return std::string();
std::string name(size, '\0');
sg->GetSymbolName(index, &name[0], size, &size);
return name;
}
PyObject *value_Name(Value *self)
{
if (!self->m_symbolGroup)
return NULL;
const std::string &symbolName = getSymbolName(self->m_symbolGroup, self->m_index);
if (symbolName.empty())
Py_RETURN_NONE;
return Py_BuildValue("s", symbolName.c_str());
}
PyObject *value_Type(Value *self)
{
if (!self->m_symbolGroup)
return NULL;
DEBUG_SYMBOL_PARAMETERS params;
const HRESULT hr = self->m_symbolGroup->GetSymbolParameters(self->m_index, 1, &params);
if (FAILED(hr))
return NULL;
return createType(params.Module, params.TypeId);
}
PyObject *value_AsBytes(Value *self)
{
if (!self->m_symbolGroup)
return NULL;
ULONG64 address = 0;
if (FAILED(self->m_symbolGroup->GetSymbolOffset(self->m_index, &address)))
return NULL;
ULONG size;
if (FAILED(self->m_symbolGroup->GetSymbolSize(self->m_index, &size)))
return NULL;
char *buffer = new char[size];
auto data = ExtensionCommandContext::instance()->dataSpaces();
ULONG received = 0;
if (FAILED(data->ReadVirtual(address, buffer, size, &received)))
return NULL;
return PyByteArray_FromStringAndSize(buffer, received);
}
ULONG64 valueAddress(Value *value)
{
ULONG64 address = 0;
if (value->m_symbolGroup)
value->m_symbolGroup->GetSymbolOffset(value->m_index, &address);
return address;
}
PyObject *value_Address(Value *self)
{
const ULONG64 address = valueAddress(self);
return address == 0 ? NULL : Py_BuildValue("K", address);
}
bool expandValue(Value *v)
{
DEBUG_SYMBOL_PARAMETERS params;
if (FAILED(v->m_symbolGroup->GetSymbolParameters(v->m_index, 1, &params)))
return false;
if (params.Flags & DEBUG_SYMBOL_EXPANDED)
return true;
return SUCCEEDED(v->m_symbolGroup->ExpandSymbol(v->m_index, TRUE));
}
ULONG numberOfChildren(Value *v)
{
DEBUG_SYMBOL_PARAMETERS params;
HRESULT hr = v->m_symbolGroup->GetSymbolParameters(v->m_index, 1, &params);
return SUCCEEDED(hr) ? params.SubElements : 0;
}
PyObject *value_Dereference(Value *self)
{
if (!self->m_symbolGroup)
return NULL;
DEBUG_SYMBOL_PARAMETERS params;
const HRESULT hr = self->m_symbolGroup->GetSymbolParameters(self->m_index, 1, &params);
if (FAILED(hr))
return NULL;
char *name = getTypeName(params.Module, params.TypeId);
Value *ret = self;
if (endsWith(std::string(name), "*")) {
if (numberOfChildren(self) > 0 && expandValue(self)) {
ULONG symbolCount = 0;
self->m_symbolGroup->GetNumberSymbols(&symbolCount);
if (symbolCount > self->m_index + 1) {
ret = PyObject_New(Value, value_pytype());
if (ret != NULL) {
ret->m_index = self->m_index + 1;
ret->m_symbolGroup = self->m_symbolGroup;
}
}
}
}
delete[] name;
return reinterpret_cast<PyObject*>(ret);
}
PyObject *value_HasChildren(Value *self)
{
if (!self->m_symbolGroup)
return NULL;
return pyBool(numberOfChildren(self) != 0);
}
PyObject *value_Expand(Value *self)
{
if (!self->m_symbolGroup)
return NULL;
return pyBool(expandValue(self));
}
PyObject *value_NativeDebuggerValue(Value *self)
{
if (!self->m_symbolGroup)
return NULL;
ULONG size = 0;
self->m_symbolGroup->GetSymbolValueText(self->m_index, NULL, 0, &size);
char *name = new char[size];
if (FAILED(self->m_symbolGroup->GetSymbolValueText(self->m_index, name, size, &size))) {
delete[] name;
Py_RETURN_NONE;
}
PyObject *ret = Py_BuildValue("s", name);
delete[] name;
return ret;
}
PyObject *value_ChildFromName(Value *self, PyObject *args)
{
if (!self->m_symbolGroup)
return NULL;
char *name;
if (!PyArg_ParseTuple(args, "s", &name))
return NULL;
const ULONG childCount = numberOfChildren(self);
if (childCount == 0 || !expandValue(self))
Py_RETURN_NONE;
for (ULONG childIndex = self->m_index + 1 ; childIndex <= self->m_index + childCount; ++childIndex) {
if (getSymbolName(self->m_symbolGroup, childIndex) == name) {
Value *childValue = PyObject_New(Value, value_pytype());
if (childValue != NULL) {
childValue->m_index = childIndex;
childValue->m_symbolGroup = self->m_symbolGroup;
}
return reinterpret_cast<PyObject*>(childValue);
}
}
Py_RETURN_NONE;
}
std::string pointedToSymbolName(ULONG64 address, const std::string &type)
{
std::ostringstream str;
str << "*(" << type;
if (!type.empty() && type.at(type.size() - 1) == '*')
str << ' ';
str << "*)" << std::showbase << std::hex << address;
return str.str();
}
PyObject *value_ChildFromField(Value *self, PyObject *args)
{
if (!self->m_symbolGroup)
return NULL;
Field *field;
if (!PyArg_ParseTuple(args, "O", &field))
return NULL;
if (!field->m_initialized && !initTypeAndOffset(field))
return NULL;
ULONG64 address = valueAddress(self);
if (address == 0)
return NULL;
address += field->m_offset;
auto symbols = ExtensionCommandContext::instance()->symbols();
ULONG childTypeNameSize = 0;
symbols->GetTypeName(field->m_module, field->m_typeId, NULL, 0, &childTypeNameSize);
std::string childTypeName(childTypeNameSize, '\0');
symbols->GetTypeName(field->m_module, field->m_typeId, &childTypeName[0],
childTypeNameSize, &childTypeNameSize);
if (childTypeName.empty())
return NULL;
std::string name = pointedToSymbolName(address, childTypeName);
ULONG index = DEBUG_ANY_ID;
if (FAILED(self->m_symbolGroup->AddSymbol(name.c_str(), &index)))
return NULL;
Value *childValue = PyObject_New(Value, value_pytype());
if (childValue != NULL) {
childValue->m_index = index;
childValue->m_symbolGroup = self->m_symbolGroup;
}
return reinterpret_cast<PyObject*>(childValue);
}
PyObject *value_ChildFromIndex(Value *self, PyObject *args)
{
if (!self->m_symbolGroup)
return NULL;
unsigned int index;
if (!PyArg_ParseTuple(args, "I", &index))
return NULL;
if (index < 0)
return NULL;
const ULONG childCount = numberOfChildren(self);
if (childCount <= index || !expandValue(self))
Py_RETURN_NONE;
Value *childValue = PyObject_New(Value, value_pytype());
if (childValue != NULL) {
childValue->m_index = self->m_index + index + 1;
childValue->m_symbolGroup = self->m_symbolGroup;
}
return reinterpret_cast<PyObject*>(childValue);
}
void value_Dealloc(Value *)
{ }
PyObject *value_New(PyTypeObject *type, PyObject *, PyObject *)
{
Value *self = reinterpret_cast<Value *>(type->tp_alloc(type, 0));
if (self != NULL)
initValue(self);
return reinterpret_cast<PyObject *>(self);
}
void initValue(Value *value)
{
value->m_index = 0;
value->m_symbolGroup = nullptr;
}
static PyMethodDef valueMethods[] = {
{"name", PyCFunction(value_Name), METH_NOARGS,
"Name of this thing or None"},
{"type", PyCFunction(value_Type), METH_NOARGS,
"Type of this value"},
{"asBytes", PyCFunction(value_AsBytes), METH_NOARGS,
"Memory contents of this object, or None"},
{"address", PyCFunction(value_Address), METH_NOARGS,
"Address of this object, or None"},
{"dereference", PyCFunction(value_Dereference), METH_NOARGS,
"Dereference if value is pointer"},
{"hasChildren", PyCFunction(value_HasChildren), METH_NOARGS,
"Whether this object has subobjects"},
{"expand", PyCFunction(value_Expand), METH_NOARGS,
"Make sure that children are accessible."},
{"nativeDebuggerValue", PyCFunction(value_NativeDebuggerValue), METH_NOARGS,
"Value string returned by the debugger"},
{"childFromName", PyCFunction(value_ChildFromName), METH_VARARGS,
"Return the name of this value"},
{"childFromField", PyCFunction(value_ChildFromField), METH_VARARGS,
"Return the name of this value"},
{"childFromIndex", PyCFunction(value_ChildFromIndex), METH_VARARGS,
"Return the name of this value"},
{NULL} /* Sentinel */
};
static PyMemberDef valueMembers[] = {
{const_cast<char *>("index"), T_ULONG, offsetof(Value, m_index), 0,
const_cast<char *>("value index in symbolgroup")},
{NULL} /* Sentinel */
};
PyTypeObject *value_pytype()
{
static PyTypeObject cdbext_ValueType =
{
PyVarObject_HEAD_INIT(NULL, 0)
"cdbext.Value", /* tp_name */
sizeof(Value), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)value_Dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"Value objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
valueMethods, /* tp_methods */
valueMembers, /* tp_members (just for debugging)*/
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
value_New, /* tp_new */
};
return &cdbext_ValueType;
}

View File

@@ -0,0 +1,42 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "symbolgroupnode.h"
#include "symbolgroup.h"
#include <Python.h>
#include "structmember.h"
struct Value
{
PyObject_HEAD
ULONG m_index;
CIDebugSymbolGroup *m_symbolGroup; // not owned
};
PyTypeObject *value_pytype();
void initValue(Value *value);

View File

@@ -103,6 +103,20 @@ exists($$PYTHON_INSTALL_DIR) {
INCLUDEPATH += $$PYTHON_INSTALL_DIR/include
DEPENDPATH += $$PYTHON_INSTALL_DIR/include
SOURCES += \
pycdbextmodule.cpp \
pyfield.cpp \
pystdoutredirect.cpp \
pytype.cpp \
pyvalue.cpp
HEADERS += \
pycdbextmodule.h \
pyfield.h \
pystdoutredirect.h \
pytype.h \
pyvalue.h
#TODO: parse version number for a generic approach
CONFIG(release, debug|release): LIBS += -L$$PYTHON_INSTALL_DIR/libs -lpython35
else:CONFIG(debug, debug|release): LIBS += -L$$PYTHON_INSTALL_DIR/libs -lpython35_d

View File

@@ -33,6 +33,7 @@
#ifdef WITH_PYTHON
#include <Python.h>
#include "pystdoutredirect.h"
#endif
#include <cstdio>
@@ -579,26 +580,17 @@ extern "C" HRESULT CALLBACK script(CIDebugClient *client, PCSTR argsIn)
for (std::string arg : commandTokens<StringList>(argsIn, &token))
command << arg << ' ';
if (PyRun_SimpleString(command.str().c_str()) == 0) {
ExtensionContext::instance().reportLong('R', token, "script", "");
} else {
ExtensionContext::instance().report('N', token, 0, "script",
"Error while executing Python code.");
}
_Py_IDENTIFIER(stdout);
_Py_IDENTIFIER(flush);
PyObject *fout = _PySys_GetObjectId(&PyId_stdout);
PyObject *tmp;
if (fout != NULL && fout != Py_None) {
tmp = _PyObject_CallMethodId(fout, &PyId_flush, "");
if (tmp == NULL)
PyErr_WriteUnraisable(fout);
else
Py_DECREF(tmp);
}
PyObject *ptype = NULL;
PyObject *pvalue = NULL;
PyObject *ptraceback = NULL;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
startCapturePyStdout();
const char result = (PyRun_SimpleString(command.str().c_str()) == 0) ? 'R' : 'N';
if (PyErr_Occurred())
PyErr_Print();
ExtensionContext::instance().reportLong(result, token, "script", getPyStdout().c_str());
endCapturePyStdout();
PyErr_Restore(ptype, pvalue, ptraceback);
#else
commandTokens<StringList>(argsIn, &token);
ExtensionContext::instance().report('N', token, 0, "script",

View File

@@ -318,6 +318,17 @@ Rectangle {
}
}
TimelineRulers {
contentX: buttonsBar.width - content.x - content.flickableItem.x + content.contentX
anchors.left: buttonsBar.right
anchors.right: parent.right
anchors.top: parent.top
height: content.flickableItem.height + buttonsBar.height
windowStart: zoomControl.windowStart
viewTimePerPixel: selectionRange.viewTimePerPixel
scaleHeight: buttonsBar.height
}
SelectionRangeDetails {
z: 3
x: 200

View File

@@ -0,0 +1,128 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
import QtQuick 2.0
Item {
id: rulersParent
property int scaleHeight
property double viewTimePerPixel: 1
property double contentX
property double windowStart
clip: true
ListModel {
id: rulersModel
}
MouseArea {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: scaleHeight
onClicked: {
rulersModel.append({
timestamp: (mouse.x + contentX) * viewTimePerPixel + windowStart
});
}
}
Item {
id: dragDummy
property int index: -1
onXChanged: {
if (index >= 0) {
rulersModel.setProperty(
index, "timestamp",
(x + contentX) * viewTimePerPixel + windowStart);
}
}
}
Repeater {
model: rulersModel
Item {
id: ruler
x: (timestamp - windowStart) / viewTimePerPixel - 1 - contentX
y: 0
width: 2
height: rulersParent.height
Rectangle {
id: arrow
height: scaleHeight
width: scaleHeight
rotation: 45
anchors.verticalCenter: parent.top
anchors.horizontalCenter: parent.horizontalCenter
color: creatorTheme.Timeline_HandleColor
MouseArea {
cursorShape: pressed ? Qt.DragMoveCursor : Qt.OpenHandCursor
anchors.fill: parent
drag.target: dragDummy
drag.axis: Drag.XAxis
drag.smoothed: false
onPressedChanged: {
if (!pressed) {
dragDummy.index = -1
} else {
dragDummy.x = ruler.x + 1
dragDummy.index = index
}
}
}
}
Rectangle {
anchors.left: parent.left
anchors.top: arrow.bottom
anchors.bottom: parent.bottom
width: 2
color: creatorTheme.Timeline_HandleColor
}
Rectangle {
anchors.top: arrow.bottom
anchors.horizontalCenter: ruler.horizontalCenter
width: scaleHeight / 4
height: width
color: creatorTheme.Timeline_PanelBackgroundColor
Rectangle {
anchors.centerIn: parent
width: parent.width - 2
height: 1
color: creatorTheme.Timeline_TextColor
}
MouseArea {
anchors.fill: parent
onClicked: rulersModel.remove(index, 1)
}
}
}
}
}

View File

@@ -30,5 +30,6 @@
<file>SynchronousReloader.qml</file>
<file>TimelineText.qml</file>
<file>ImageToolButton.qml</file>
<file>TimelineRulers.qml</file>
</qresource>
</RCC>

View File

@@ -471,6 +471,22 @@ bool FileSaverBase::setResult(QXmlStreamWriter *stream)
FileSaver::FileSaver(const QString &filename, QIODevice::OpenMode mode)
{
m_fileName = filename;
// Workaround an assert in Qt -- and provide a useful error message, too:
if (HostOsInfo::isWindowsHost()) {
// Taken from: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
static const QStringList reservedNames
= { "CON", "PRN", "AUX", "NUL",
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" };
const QString fn = QFileInfo(filename).baseName().toUpper();
for (const QString &rn : reservedNames) {
if (fn == rn) {
m_errorString = tr("%1: Is a reserved filename on Windows. Cannot save.").arg(filename);
m_hasError = true;
return;
}
}
}
if (mode & (QIODevice::ReadOnly | QIODevice::Append)) {
m_file = new QFile(filename);
m_isSafe = false;

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

View File

@@ -542,7 +542,7 @@ bool PathChooser::validatePath(FancyLineEdit *edit, QString *errorMessage) const
}
if (!fi.isFile()) {
if (errorMessage)
*errorMessage = tr("The path <b>%1</b> is not a file.").arg(QDir::toNativeSeparators(expandedPath));
*errorMessage = tr("The path \"%1\" is not a file.").arg(QDir::toNativeSeparators(expandedPath));
return false;
}
break;
@@ -554,7 +554,7 @@ bool PathChooser::validatePath(FancyLineEdit *edit, QString *errorMessage) const
}
if (fi.exists() && fi.isDir()) {
if (errorMessage)
*errorMessage = tr("The path <b>%1</b> is not a file.").arg(QDir::toNativeSeparators(fi.absolutePath()));
*errorMessage = tr("The path \"%1\" is not a file.").arg(QDir::toNativeSeparators(fi.absolutePath()));
return false;
}
break;
@@ -566,7 +566,7 @@ bool PathChooser::validatePath(FancyLineEdit *edit, QString *errorMessage) const
}
if (!fi.isFile() || !fi.isExecutable()) {
if (errorMessage)
*errorMessage = tr("The path <b>%1</b> is not an executable file.").arg(QDir::toNativeSeparators(expandedPath));
*errorMessage = tr("The path \"%1\" is not an executable file.").arg(QDir::toNativeSeparators(expandedPath));
return false;
}
break;
@@ -590,7 +590,7 @@ bool PathChooser::validatePath(FancyLineEdit *edit, QString *errorMessage) const
}
if (errorMessage)
*errorMessage = tr("Full path: <b>%1</b>").arg(QDir::toNativeSeparators(expandedPath));
*errorMessage = tr("Full path: \"%1\"").arg(QDir::toNativeSeparators(expandedPath));
return true;
}

View File

@@ -138,5 +138,17 @@
<file>images/collapse@2x.png</file>
<file>images/expand.png</file>
<file>images/expand@2x.png</file>
<file>images/iconoverlay_add.png</file>
<file>images/iconoverlay_add@2x.png</file>
<file>images/iconoverlay_add_background.png</file>
<file>images/iconoverlay_add_background@2x.png</file>
<file>images/iconoverlay_error.png</file>
<file>images/iconoverlay_error@2x.png</file>
<file>images/iconoverlay_error_background.png</file>
<file>images/iconoverlay_error_background@2x.png</file>
<file>images/iconoverlay_warning.png</file>
<file>images/iconoverlay_warning@2x.png</file>
<file>images/iconoverlay_warning_background.png</file>
<file>images/iconoverlay_warning_background@2x.png</file>
</qresource>
</RCC>

View File

@@ -181,9 +181,15 @@ const Icon COLLAPSE({
const Icon COLLAPSE_TOOLBAR({
{QLatin1String(":/utils/images/collapse.png"), Theme::IconsBaseColor}});
const Icon EMPTY14(":/utils/images/empty14.png");
const Icon ENABLE_KIT_OVERLAY({
{":/projectexplorer/images/enablekitbackground.png", Theme::IconsRunColor},
{":/projectexplorer/images/enablekitforeground.png", Theme::BackgroundColorNormal}}, Icon::Tint);
const Icon OVERLAY_ADD({
{":/utils/images/iconoverlay_add_background.png", Theme::BackgroundColorNormal},
{":/utils/images/iconoverlay_add.png", Theme::IconsRunColor}}, Icon::Tint);
const Icon OVERLAY_WARNING({
{":/utils/images/iconoverlay_warning_background.png", Theme::BackgroundColorNormal},
{":/utils/images/iconoverlay_warning.png", Theme::IconsWarningColor}}, Icon::Tint);
const Icon OVERLAY_ERROR({
{":/utils/images/iconoverlay_error_background.png", Theme::BackgroundColorNormal},
{":/utils/images/iconoverlay_error.png", Theme::IconsErrorColor}}, Icon::Tint);
} // namespace Icons
} // namespace Utils

View File

@@ -107,7 +107,9 @@ QTCREATOR_UTILS_EXPORT extern const Icon EXPAND_TOOLBAR;
QTCREATOR_UTILS_EXPORT extern const Icon COLLAPSE;
QTCREATOR_UTILS_EXPORT extern const Icon COLLAPSE_TOOLBAR;
QTCREATOR_UTILS_EXPORT extern const Icon EMPTY14;
QTCREATOR_UTILS_EXPORT extern const Icon ENABLE_KIT_OVERLAY;
QTCREATOR_UTILS_EXPORT extern const Icon OVERLAY_ADD;
QTCREATOR_UTILS_EXPORT extern const Icon OVERLAY_WARNING;
QTCREATOR_UTILS_EXPORT extern const Icon OVERLAY_ERROR;
} // namespace Icons
} // namespace Utils

View File

@@ -31,6 +31,7 @@ SOURCES += \
gtest/gtestvisitors.cpp \
gtest/gtestframework.cpp \
gtest/gtestsettings.cpp \
gtest/gtestsettingspage.cpp \
qtest/qttesttreeitem.cpp \
qtest/qttestvisitors.cpp \
qtest/qttestconfiguration.cpp \
@@ -39,6 +40,7 @@ SOURCES += \
qtest/qttestparser.cpp \
qtest/qttestframework.cpp \
qtest/qttestsettings.cpp \
qtest/qttestsettingspage.cpp \
quick/quicktestconfiguration.cpp \
quick/quicktestparser.cpp \
quick/quicktesttreeitem.cpp \
@@ -80,6 +82,8 @@ HEADERS += \
gtest/gtestvisitors.h \
gtest/gtestframework.h \
gtest/gtestsettings.h \
gtest/gtestsettingspage.h \
gtest/gtestconstants.h \
qtest/qttesttreeitem.h \
qtest/qttest_utils.h \
qtest/qttestresult.h \
@@ -89,6 +93,8 @@ HEADERS += \
qtest/qttestparser.h \
qtest/qttestframework.h \
qtest/qttestsettings.h \
qtest/qttestsettingspage.h \
qtest/qttestconstants.h \
quick/quicktestconfiguration.h \
quick/quicktestparser.h \
quick/quicktesttreeitem.h \
@@ -102,7 +108,9 @@ RESOURCES += \
autotest.qrc
FORMS += \
testsettingspage.ui
testsettingspage.ui \
qtest/qttestsettingspage.ui \
gtest/gtestsettingspage.ui
equals(TEST, 1) {
HEADERS += autotestunittests.h

View File

@@ -39,7 +39,10 @@ const char AUTOTEST_CONTEXT[] = "Auto Tests";
const char TASK_INDEX[] = "AutoTest.Task.Index";
const char TASK_PARSE[] = "AutoTest.Task.Parse";
const char AUTOTEST_SETTINGS_CATEGORY[] = "ZY.Tests";
const char AUTOTEST_SETTINGS_TR[] = QT_TRANSLATE_NOOP("AutoTest", "Test Settings");
const char FRAMEWORK_PREFIX[] = "AutoTest.Framework.";
const char SETTINGSGROUP[] = "Autotest";
} // namespace Constants
} // namespace Autotest

View File

@@ -135,7 +135,7 @@ bool AutotestPlugin::initialize(const QStringList &arguments, QString *errorStri
m_frameworkManager->registerTestFramework(new QuickTestFramework);
m_frameworkManager->registerTestFramework(new GTestFramework);
m_settings->fromSettings(ICore::settings());
m_frameworkManager->synchronizeSettings(ICore::settings());
addAutoReleasedObject(new TestSettingsPage(m_settings));
addAutoReleasedObject(new TestNavigationWidgetFactory);
addAutoReleasedObject(TestResultsPane::instance());

View File

@@ -24,8 +24,10 @@
****************************************************************************/
#include "gtestconfiguration.h"
#include "gtestconstants.h"
#include "gtestoutputreader.h"
#include "../testsettings.h"
#include "gtestsettings.h"
#include "../testframeworkmanager.h"
namespace Autotest {
namespace Internal {
@@ -36,25 +38,32 @@ TestOutputReader *GTestConfiguration::outputReader(const QFutureInterface<TestRe
return new GTestOutputReader(fi, app, buildDirectory());
}
QStringList GTestConfiguration::argumentsForTestRunner(const TestSettings &settings) const
QStringList GTestConfiguration::argumentsForTestRunner() const
{
static const Core::Id id
= Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(GTest::Constants::FRAMEWORK_NAME);
QStringList arguments;
const QStringList &testSets = testCases();
if (testSets.size())
arguments << "--gtest_filter=" + testSets.join(':');
if (settings.gTestSettings.runDisabled)
TestFrameworkManager *manager = TestFrameworkManager::instance();
auto gSettings = qSharedPointerCast<GTestSettings>(manager->settingsForTestFramework(id));
if (gSettings.isNull())
return arguments;
if (gSettings->runDisabled)
arguments << "--gtest_also_run_disabled_tests";
if (settings.gTestSettings.repeat)
arguments << QString("--gtest_repeat=%1").arg(settings.gTestSettings.iterations);
if (settings.gTestSettings.shuffle) {
arguments << "--gtest_shuffle"
<< QString("--gtest_random_seed=%1").arg(settings.gTestSettings.seed);
}
if (settings.gTestSettings.throwOnFailure)
if (gSettings->repeat)
arguments << QString("--gtest_repeat=%1").arg(gSettings->iterations);
if (gSettings->shuffle)
arguments << "--gtest_shuffle" << QString("--gtest_random_seed=%1").arg(gSettings->seed);
if (gSettings->throwOnFailure)
arguments << "--gtest_throw_on_failure";
if (runMode() == DebuggableTestConfiguration::Debug) {
if (settings.gTestSettings.breakOnFailure)
if (gSettings->breakOnFailure)
arguments << "--gtest_break_on_failure";
}
return arguments;

View File

@@ -36,7 +36,7 @@ public:
explicit GTestConfiguration() {}
TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const override;
QStringList argumentsForTestRunner(const TestSettings &settings) const override;
QStringList argumentsForTestRunner() const override;
};
} // namespace Internal

View File

@@ -0,0 +1,40 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QtGlobal>
namespace Autotest {
namespace GTest {
namespace Constants {
const char FRAMEWORK_NAME[] = "GTest";
const char FRAMEWORK_SETTINGS_CATEGORY[] = QT_TRANSLATE_NOOP("GTestFramework", "Google Test");
const unsigned FRAMEWORK_PRIORITY = 10;
} // namespace Constants
} // namespace GTest
} // namespace AutoTest

View File

@@ -24,6 +24,9 @@
****************************************************************************/
#include "gtestframework.h"
#include "gtestconstants.h"
#include "gtestsettings.h"
#include "gtestsettingspage.h"
#include "gtesttreeitem.h"
#include "gtestparser.h"
@@ -37,18 +40,35 @@ ITestParser *GTestFramework::createTestParser() const
TestTreeItem *GTestFramework::createRootNode() const
{
return new GTestTreeItem(QCoreApplication::translate("GTestFramework", "Google Tests"),
QString(), TestTreeItem::Root);
return new GTestTreeItem(
QCoreApplication::translate("GTestFramework",
GTest::Constants::FRAMEWORK_SETTINGS_CATEGORY),
QString(), TestTreeItem::Root);
}
const char *GTestFramework::name() const
{
return "GTest";
return GTest::Constants::FRAMEWORK_NAME;
}
unsigned GTestFramework::priority() const
{
return 10;
return GTest::Constants::FRAMEWORK_PRIORITY;
}
IFrameworkSettings *GTestFramework::createFrameworkSettings() const
{
return new GTestSettings;
}
Core::IOptionsPage *GTestFramework::createSettingsPage(QSharedPointer<IFrameworkSettings> settings) const
{
return new GTestSettingsPage(settings);
}
bool GTestFramework::hasFrameworkSettings() const
{
return true;
}
} // namespace Internal

View File

@@ -36,7 +36,9 @@ public:
GTestFramework() : ITestFramework(true) {}
const char *name() const override;
unsigned priority() const override;
IFrameworkSettings *createFrameworkSettings() const override;
Core::IOptionsPage *createSettingsPage(QSharedPointer<IFrameworkSettings> settings) const override;
bool hasFrameworkSettings() const override;
protected:
ITestParser *createTestParser() const override;
TestTreeItem *createRootNode() const override;

View File

@@ -41,7 +41,7 @@ QString GTestSettings::name() const
return QString("GTest");
}
void GTestSettings::fromSettings(const QSettings *s)
void GTestSettings::fromFrameworkSettings(const QSettings *s)
{
runDisabled = s->value(runDisabledKey, false).toBool();
repeat = s->value(repeatKey, false).toBool();
@@ -52,7 +52,7 @@ void GTestSettings::fromSettings(const QSettings *s)
throwOnFailure = s->value(throwOnFailureKey, false).toBool();
}
void GTestSettings::toSettings(QSettings *s) const
void GTestSettings::toFrameworkSettings(QSettings *s) const
{
s->setValue(runDisabledKey, runDisabled);
s->setValue(repeatKey, repeat);

View File

@@ -35,8 +35,6 @@ class GTestSettings : public IFrameworkSettings
public:
GTestSettings() {}
QString name() const override;
void fromSettings(const QSettings *s) override;
void toSettings(QSettings *s) const override;
int iterations = 1;
int seed = 0;
@@ -45,6 +43,10 @@ public:
bool repeat = false;
bool throwOnFailure = false;
bool breakOnFailure = true;
protected:
void fromFrameworkSettings(const QSettings *s) override;
void toFrameworkSettings(QSettings *s) const override;
};
} // namespace Internal

View File

@@ -0,0 +1,100 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "../autotestconstants.h"
#include "gtestconstants.h"
#include "gtestsettingspage.h"
#include "gtestsettings.h"
#include <coreplugin/icore.h>
namespace Autotest {
namespace Internal {
GTestSettingsWidget::GTestSettingsWidget(QWidget *parent)
: QWidget(parent)
{
m_ui.setupUi(this);
connect(m_ui.repeatGTestsCB, &QCheckBox::toggled, m_ui.repetitionSpin, &QSpinBox::setEnabled);
connect(m_ui.shuffleGTestsCB, &QCheckBox::toggled, m_ui.seedSpin, &QSpinBox::setEnabled);
}
void GTestSettingsWidget::setSettings(const GTestSettings &settings)
{
m_ui.runDisabledGTestsCB->setChecked(settings.runDisabled);
m_ui.repeatGTestsCB->setChecked(settings.repeat);
m_ui.shuffleGTestsCB->setChecked(settings.shuffle);
m_ui.repetitionSpin->setValue(settings.iterations);
m_ui.seedSpin->setValue(settings.seed);
m_ui.breakOnFailureCB->setChecked(settings.breakOnFailure);
m_ui.throwOnFailureCB->setChecked(settings.throwOnFailure);
}
GTestSettings GTestSettingsWidget::settings() const
{
GTestSettings result;
result.runDisabled = m_ui.runDisabledGTestsCB->isChecked();
result.repeat = m_ui.repeatGTestsCB->isChecked();
result.shuffle = m_ui.shuffleGTestsCB->isChecked();
result.iterations = m_ui.repetitionSpin->value();
result.seed = m_ui.seedSpin->value();
result.breakOnFailure = m_ui.breakOnFailureCB->isChecked();
result.throwOnFailure = m_ui.throwOnFailureCB->isChecked();
return result;
}
GTestSettingsPage::GTestSettingsPage(QSharedPointer<IFrameworkSettings> settings)
: m_settings(qSharedPointerCast<GTestSettings>(settings)), m_widget(0)
{
setId("A.AutoTest.10.GTest"); // FIXME
setDisplayName(QCoreApplication::translate("GTestFramework",
GTest::Constants::FRAMEWORK_SETTINGS_CATEGORY));
setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
setDisplayCategory(QCoreApplication::translate("AutoTest", Constants::AUTOTEST_SETTINGS_TR));
}
GTestSettingsPage::~GTestSettingsPage()
{
}
QWidget *GTestSettingsPage::widget()
{
if (!m_widget) {
m_widget = new GTestSettingsWidget;
m_widget->setSettings(*m_settings);
}
return m_widget;
}
void GTestSettingsPage::apply()
{
if (!m_widget) // page was not shown at all
return;
*m_settings = m_widget->settings();
m_settings->toSettings(Core::ICore::settings());
}
} // namespace Internal
} // namespace Autotest

View File

@@ -0,0 +1,70 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "ui_gtestsettingspage.h"
#include <coreplugin/dialogs/ioptionspage.h>
#include <QPointer>
namespace Autotest {
namespace Internal {
class IFrameworkSettings;
class GTestSettings;
class GTestSettingsWidget : public QWidget
{
Q_OBJECT
public:
explicit GTestSettingsWidget(QWidget *parent = 0);
void setSettings(const GTestSettings &settings);
GTestSettings settings() const;
private:
Ui::GTestSettingsPage m_ui;
};
class GTestSettingsPage : public Core::IOptionsPage
{
Q_OBJECT
public:
explicit GTestSettingsPage(QSharedPointer<IFrameworkSettings> settings);
~GTestSettingsPage();
QWidget *widget() override;
void apply() override;
void finish() override { }
private:
QSharedPointer<GTestSettings> m_settings;
QPointer<GTestSettingsWidget> m_widget;
};
} // namespace Internal
} // namespace Autotest

View File

@@ -0,0 +1,219 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Autotest::Internal::GTestSettingsPage</class>
<widget class="QWidget" name="Autotest::Internal::GTestSettingsPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>397</width>
<height>205</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="runDisabledGTestsCB">
<property name="toolTip">
<string>Executes disabled tests when performing a test run.</string>
</property>
<property name="text">
<string>Run disabled tests</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="breakOnFailureCB">
<property name="toolTip">
<string>Turn failures into debugger breakpoints.</string>
</property>
<property name="text">
<string>Break on failure while debugging</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="repeatGTestsCB">
<property name="toolTip">
<string>Repeats a test run (you might be required to increase the timeout to avoid canceling the tests).</string>
</property>
<property name="text">
<string>Repeat tests</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Iterations:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="repetitionSpin">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QCheckBox" name="shuffleGTestsCB">
<property name="toolTip">
<string>Shuffle tests automatically on every iteration by the given seed.</string>
</property>
<property name="text">
<string>Shuffle tests</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Seed:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="seedSpin">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>A seed of 0 generates a seed based on the current timestamp.</string>
</property>
<property name="specialValueText">
<string/>
</property>
<property name="maximum">
<number>99999</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="throwOnFailureCB">
<property name="toolTip">
<string>Turn assertion failures into C++ exceptions.</string>
</property>
<property name="text">
<string>Throw on failure</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -25,6 +25,8 @@
#pragma once
#include "autotestconstants.h"
#include <QSettings>
namespace Autotest {
@@ -37,8 +39,28 @@ public:
virtual ~IFrameworkSettings() {}
virtual QString name() const = 0;
virtual void toSettings(QSettings *s) const = 0;
virtual void fromSettings(const QSettings *s) = 0;
void toSettings(QSettings *s) const
{
s->beginGroup(Constants::SETTINGSGROUP);
s->beginGroup(name());
toFrameworkSettings(s);
s->endGroup();
s->endGroup();
}
void fromSettings(QSettings *s)
{
s->beginGroup(Constants::SETTINGSGROUP);
s->beginGroup(name());
fromFrameworkSettings(s);
s->endGroup();
s->endGroup();
}
protected:
virtual void toFrameworkSettings(QSettings *s) const = 0;
virtual void fromFrameworkSettings(const QSettings *s) = 0;
};
} // namespace Internal

View File

@@ -28,9 +28,13 @@
#include "testtreeitem.h"
#include "itestparser.h"
namespace Core { class IOptionsPage; }
namespace Autotest {
namespace Internal {
class IFrameworkSettings;
class ITestFramework
{
public:
@@ -43,6 +47,13 @@ public:
virtual const char *name() const = 0;
virtual unsigned priority() const = 0; // should this be modifyable?
virtual bool hasFrameworkSettings() const { return false; }
virtual IFrameworkSettings *createFrameworkSettings() const { return 0; }
virtual Core::IOptionsPage *createSettingsPage(QSharedPointer<IFrameworkSettings> settings) const
{
Q_UNUSED(settings);
return 0;
}
TestTreeItem *rootNode()
{ if (!m_rootNode)

View File

@@ -24,8 +24,10 @@
****************************************************************************/
#include "qttestconfiguration.h"
#include "qttestconstants.h"
#include "qttestoutputreader.h"
#include "../testsettings.h"
#include "qttestsettings.h"
#include "../testframeworkmanager.h"
namespace Autotest {
namespace Internal {
@@ -36,19 +38,26 @@ TestOutputReader *QtTestConfiguration::outputReader(const QFutureInterface<TestR
return new QtTestOutputReader(fi, app, buildDirectory());
}
QStringList QtTestConfiguration::argumentsForTestRunner(const TestSettings &settings) const
QStringList QtTestConfiguration::argumentsForTestRunner() const
{
QStringList arguments("-xml");
static const Core::Id id
= Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(QtTest::Constants::FRAMEWORK_NAME);
const QString &metricsOption
= QtTestSettings::metricsTypeToOption(settings.qtTestSettings.metrics);
if (!metricsOption.isEmpty())
arguments << metricsOption;
QStringList arguments("-xml");
if (testCases().count())
arguments << testCases();
TestFrameworkManager *manager = TestFrameworkManager::instance();
auto qtSettings = qSharedPointerCast<QtTestSettings>(manager->settingsForTestFramework(id));
if (qtSettings.isNull())
return arguments;
const QString &metricsOption = QtTestSettings::metricsTypeToOption(qtSettings->metrics);
if (!metricsOption.isEmpty())
arguments << metricsOption;
if (runMode() == DebuggableTestConfiguration::Debug) {
if (settings.qtTestSettings.noCrashHandler)
if (qtSettings->noCrashHandler)
arguments << "-nocrashhandler";
}

View File

@@ -36,7 +36,7 @@ public:
explicit QtTestConfiguration() {}
TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const override;
QStringList argumentsForTestRunner(const TestSettings &settings) const override;
QStringList argumentsForTestRunner() const override;
};
} // namespace Internal

View File

@@ -0,0 +1,40 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QtGlobal>
namespace Autotest {
namespace QtTest {
namespace Constants {
const char FRAMEWORK_NAME[] = "QtTest";
const char FRAMEWORK_SETTINGS_CATEGORY[] = QT_TRANSLATE_NOOP("QtTestFramework", "Qt Test");
const unsigned FRAMEWORK_PRIORITY = 1;
} // namespace Constants
} // namespace QtTest
} // namespace Autotest

View File

@@ -24,7 +24,10 @@
****************************************************************************/
#include "qttestframework.h"
#include "qttestconstants.h"
#include "qttestparser.h"
#include "qttestsettings.h"
#include "qttestsettingspage.h"
#include "qttesttreeitem.h"
namespace Autotest {
@@ -37,18 +40,35 @@ ITestParser *QtTestFramework::createTestParser() const
TestTreeItem *QtTestFramework::createRootNode() const
{
return new QtTestTreeItem(QCoreApplication::translate("QtTestFramework", "Qt Tests"),
QString(), TestTreeItem::Root);
return new QtTestTreeItem(
QCoreApplication::translate("QtTestFramework",
QtTest::Constants::FRAMEWORK_SETTINGS_CATEGORY),
QString(), TestTreeItem::Root);
}
IFrameworkSettings *QtTestFramework::createFrameworkSettings() const
{
return new QtTestSettings;
}
Core::IOptionsPage *QtTestFramework::createSettingsPage(QSharedPointer<IFrameworkSettings> settings) const
{
return new QtTestSettingsPage(settings);
}
bool QtTestFramework::hasFrameworkSettings() const
{
return true;
}
const char *QtTestFramework::name() const
{
return "QtTest";
return QtTest::Constants::FRAMEWORK_NAME;
}
unsigned QtTestFramework::priority() const
{
return 1;
return QtTest::Constants::FRAMEWORK_PRIORITY;
}
} // namespace Internal

View File

@@ -36,6 +36,9 @@ public:
QtTestFramework() : ITestFramework(true) {}
const char *name() const override;
unsigned priority() const override;
IFrameworkSettings *createFrameworkSettings() const override;
Core::IOptionsPage *createSettingsPage(QSharedPointer<IFrameworkSettings> settings) const override;
bool hasFrameworkSettings() const override;
protected:
ITestParser *createTestParser() const override;

View File

@@ -54,13 +54,13 @@ QString QtTestSettings::name() const
return QString("QtTest");
}
void QtTestSettings::fromSettings(const QSettings *s)
void QtTestSettings::fromFrameworkSettings(const QSettings *s)
{
metrics = intToMetrics(s->value(metricsKey, Walltime).toInt());
noCrashHandler = s->value(noCrashhandlerKey, true).toBool();
}
void QtTestSettings::toSettings(QSettings *s) const
void QtTestSettings::toFrameworkSettings(QSettings *s) const
{
s->setValue(metricsKey, metrics);
s->setValue(noCrashhandlerKey, noCrashHandler);

View File

@@ -44,12 +44,14 @@ class QtTestSettings : public IFrameworkSettings
public:
QtTestSettings() {}
QString name() const override;
void fromSettings(const QSettings *s) override;
void toSettings(QSettings *s) const override;
static QString metricsTypeToOption(const MetricsType type);
MetricsType metrics = Walltime;
bool noCrashHandler = true;
protected:
void fromFrameworkSettings(const QSettings *s) override;
void toFrameworkSettings(QSettings *s) const override;
};
} // namespace Internal

View File

@@ -0,0 +1,121 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "../autotestconstants.h"
#include "qttestconstants.h"
#include "qttestsettingspage.h"
#include "qttestsettings.h"
#include <coreplugin/icore.h>
#include <utils/hostosinfo.h>
namespace Autotest {
namespace Internal {
QtTestSettingsWidget::QtTestSettingsWidget(QWidget *parent)
: QWidget(parent)
{
m_ui.setupUi(this);
m_ui.callgrindRB->setEnabled(Utils::HostOsInfo::isAnyUnixHost()); // valgrind available on UNIX
m_ui.perfRB->setEnabled(Utils::HostOsInfo::isLinuxHost()); // according to docs perf Linux only
}
void QtTestSettingsWidget::setSettings(const QtTestSettings &settings)
{
m_ui.disableCrashhandlerCB->setChecked(settings.noCrashHandler);
switch (settings.metrics) {
case MetricsType::Walltime:
m_ui.walltimeRB->setChecked(true);
break;
case MetricsType::TickCounter:
m_ui.tickcounterRB->setChecked(true);
break;
case MetricsType::EventCounter:
m_ui.eventCounterRB->setChecked(true);
break;
case MetricsType::CallGrind:
m_ui.callgrindRB->setChecked(true);
break;
case MetricsType::Perf:
m_ui.perfRB->setChecked(true);
break;
default:
m_ui.walltimeRB->setChecked(true);
}
}
QtTestSettings QtTestSettingsWidget::settings() const
{
QtTestSettings result;
result.noCrashHandler = m_ui.disableCrashhandlerCB->isChecked();
if (m_ui.walltimeRB->isChecked())
result.metrics = MetricsType::Walltime;
else if (m_ui.tickcounterRB->isChecked())
result.metrics = MetricsType::TickCounter;
else if (m_ui.eventCounterRB->isChecked())
result.metrics = MetricsType::EventCounter;
else if (m_ui.callgrindRB->isChecked())
result.metrics = MetricsType::CallGrind;
else if (m_ui.perfRB->isChecked())
result.metrics = MetricsType::Perf;
return result;
}
QtTestSettingsPage::QtTestSettingsPage(QSharedPointer<IFrameworkSettings> settings)
: m_settings(qSharedPointerCast<QtTestSettings>(settings)), m_widget(0)
{
setId("A.AutoTest.1.QtTest"); // FIXME
setDisplayName(QCoreApplication::translate("QtTestFramework",
QtTest::Constants::FRAMEWORK_SETTINGS_CATEGORY));
setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
setDisplayCategory(QCoreApplication::translate("AutoTest", Constants::AUTOTEST_SETTINGS_TR));
}
QtTestSettingsPage::~QtTestSettingsPage()
{
}
QWidget *QtTestSettingsPage::widget()
{
if (!m_widget) {
m_widget = new QtTestSettingsWidget;
m_widget->setSettings(*m_settings);
}
return m_widget;
}
void QtTestSettingsPage::apply()
{
if (!m_widget) // page was not shown at all
return;
*m_settings = m_widget->settings();
m_settings->toSettings(Core::ICore::settings());
}
} // namespace Internal
} // namespace Autotest

View File

@@ -0,0 +1,70 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "ui_qttestsettingspage.h"
#include <coreplugin/dialogs/ioptionspage.h>
#include <QPointer>
namespace Autotest {
namespace Internal {
class IFrameworkSettings;
class QtTestSettings;
class QtTestSettingsWidget : public QWidget
{
Q_OBJECT
public:
explicit QtTestSettingsWidget(QWidget *parent = 0);
void setSettings(const QtTestSettings &settings);
QtTestSettings settings() const;
private:
Ui::QtTestSettingsPage m_ui;
};
class QtTestSettingsPage : public Core::IOptionsPage
{
Q_OBJECT
public:
explicit QtTestSettingsPage(QSharedPointer<IFrameworkSettings> settings);
~QtTestSettingsPage();
QWidget *widget() override;
void apply() override;
void finish() override { }
private:
QSharedPointer<QtTestSettings> m_settings;
QPointer<QtTestSettingsWidget> m_widget;
};
} // namespace Internal
} // namespace Autotest

View File

@@ -0,0 +1,169 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Autotest::Internal::QtTestSettingsPage</class>
<widget class="QWidget" name="Autotest::Internal::QtTestSettingsPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>327</width>
<height>266</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="disableCrashhandlerCB">
<property name="toolTip">
<string>Enables interrupting tests on assertions.</string>
</property>
<property name="text">
<string>Disable crash handler while debugging</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Benchmark Metrics</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QRadioButton" name="walltimeRB">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Uses walltime metrics for executing benchmarks (default).</string>
</property>
<property name="text">
<string>Walltime</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="tickcounterRB">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Uses tick counter when executing benchmarks.</string>
</property>
<property name="text">
<string>Tick counter</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="eventCounterRB">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Uses event counter when executing benchmarks.</string>
</property>
<property name="text">
<string>Event counter</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="callgrindRB">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Uses Valgrind Callgrind when executing benchmarks (it must be installed).</string>
</property>
<property name="text">
<string>Callgrind</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="perfRB">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Uses Perf when executing benchmarks (it must be installed).</string>
</property>
<property name="text">
<string>Perf</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -24,8 +24,10 @@
****************************************************************************/
#include "quicktestconfiguration.h"
#include "../qtest/qttestconstants.h"
#include "../qtest/qttestoutputreader.h"
#include "../testsettings.h"
#include "../qtest/qttestsettings.h"
#include "../testframeworkmanager.h"
namespace Autotest {
namespace Internal {
@@ -36,16 +38,23 @@ TestOutputReader *QuickTestConfiguration::outputReader(const QFutureInterface<Te
return new QtTestOutputReader(fi, app, buildDirectory());
}
QStringList QuickTestConfiguration::argumentsForTestRunner(const TestSettings &settings) const
QStringList QuickTestConfiguration::argumentsForTestRunner() const
{
QStringList arguments({"-xml"});
static const Core::Id id
= Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(QtTest::Constants::FRAMEWORK_NAME);
const QString &metricsOption
= QtTestSettings::metricsTypeToOption(settings.qtTestSettings.metrics);
if (!metricsOption.isEmpty())
arguments << metricsOption;
QStringList arguments("-xml");
if (testCases().count())
arguments << testCases();
TestFrameworkManager *manager = TestFrameworkManager::instance();
auto qtSettings = qSharedPointerCast<QtTestSettings>(manager->settingsForTestFramework(id));
if (qtSettings.isNull())
return arguments;
const QString &metricsOption = QtTestSettings::metricsTypeToOption(qtSettings->metrics);
if (!metricsOption.isEmpty())
arguments << metricsOption;
return arguments;
}

View File

@@ -36,7 +36,7 @@ public:
explicit QuickTestConfiguration() {}
TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const override;
QStringList argumentsForTestRunner(const TestSettings &settings) const override;
QStringList argumentsForTestRunner() const override;
void setUnnamedOnly(bool unnamedOnly);
bool unnamedOnly() const { return m_unnamedOnly; }

View File

@@ -27,7 +27,6 @@
#include "testoutputreader.h"
#include "testrunconfiguration.h"
#include "testrunner.h"
#include "testsettings.h"
#include <cpptools/cppmodelmanager.h>
#include <cpptools/projectinfo.h>

View File

@@ -45,7 +45,6 @@ namespace Internal {
class TestOutputReader;
class TestResult;
class TestRunConfiguration;
struct TestSettings;
using TestResultPtr = QSharedPointer<TestResult>;
@@ -86,7 +85,7 @@ public:
virtual TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const = 0;
virtual QStringList argumentsForTestRunner(const TestSettings &settings) const = 0;
virtual QStringList argumentsForTestRunner() const = 0;
private:
QStringList m_testCases;

View File

@@ -25,6 +25,8 @@
#include "testframeworkmanager.h"
#include "autotestconstants.h"
#include "autotestplugin.h"
#include "iframeworksettings.h"
#include "itestframework.h"
#include "itestparser.h"
#include "testrunner.h"
@@ -32,10 +34,12 @@
#include "testtreeitem.h"
#include "testtreemodel.h"
#include <coreplugin/dialogs/ioptionspage.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <QLoggingCategory>
#include <QSettings>
static Q_LOGGING_CATEGORY(LOG, "qtc.autotest.frameworkmanager")
@@ -74,6 +78,15 @@ bool TestFrameworkManager::registerTestFramework(ITestFramework *framework)
// TODO check for unique priority before registering
qCDebug(LOG) << "Registering" << id;
m_registeredFrameworks.insert(id, framework);
AutotestPlugin *plugin = AutotestPlugin::instance();
if (framework->hasFrameworkSettings()) {
QSharedPointer<IFrameworkSettings> frameworkSettings(framework->createFrameworkSettings());
m_frameworkSettings.insert(id, frameworkSettings);
if (auto page = framework->createSettingsPage(frameworkSettings))
plugin->addAutoReleasedObject(page);
}
return true;
}
@@ -145,6 +158,23 @@ ITestParser *TestFrameworkManager::testParserForTestFramework(const Core::Id &fr
return testParser;
}
QSharedPointer<IFrameworkSettings> TestFrameworkManager::settingsForTestFramework(
const Core::Id &frameworkId) const
{
return m_frameworkSettings.contains(frameworkId) ? m_frameworkSettings.value(frameworkId)
: QSharedPointer<IFrameworkSettings>();
}
void TestFrameworkManager::synchronizeSettings(QSettings *s)
{
AutotestPlugin::instance()->settings()->fromSettings(s);
for (const Core::Id &id : m_frameworkSettings.keys()) {
QSharedPointer<IFrameworkSettings> fSettings = settingsForTestFramework(id);
if (!fSettings.isNull())
fSettings->fromSettings(s);
}
}
bool TestFrameworkManager::isActive(const Core::Id &frameworkId) const
{
ITestFramework *framework = m_registeredFrameworks.value(frameworkId);

View File

@@ -28,11 +28,16 @@
#include <QHash>
#include <QSharedPointer>
QT_BEGIN_NAMESPACE
class QSettings;
QT_END_NAMESPACE
namespace Core { class Id; }
namespace Autotest {
namespace Internal {
class IFrameworkSettings;
class ITestFramework;
class ITestParser;
class TestRunner;
@@ -55,6 +60,8 @@ public:
TestTreeItem *rootNodeForTestFramework(const Core::Id &frameworkId) const;
ITestParser *testParserForTestFramework(const Core::Id &frameworkId) const;
QSharedPointer<IFrameworkSettings> settingsForTestFramework(const Core::Id &frameworkId) const;
void synchronizeSettings(QSettings *s);
bool isActive(const Core::Id &frameworkId) const;
bool hasActiveFrameworks() const;
@@ -62,6 +69,7 @@ private:
QVector<Core::Id> activeFrameworkIds() const;
explicit TestFrameworkManager();
QHash<Core::Id, ITestFramework *> m_registeredFrameworks;
QHash<Core::Id, QSharedPointer<IFrameworkSettings> > m_frameworkSettings;
TestTreeModel *m_testTreeModel;
TestRunner *m_testRunner;

View File

@@ -64,8 +64,7 @@ public:
ProjectExplorer::StandardRunnable r;
QTC_ASSERT(m_testConfig, return r);
r.executable = m_testConfig->targetFile();
r.commandLineArguments = m_testConfig->argumentsForTestRunner(
*AutotestPlugin::instance()->settings()).join(' ');
r.commandLineArguments = m_testConfig->argumentsForTestRunner().join(' ');
r.workingDirectory = m_testConfig->workingDirectory();
r.environment = m_testConfig->environment();
r.runMode = ProjectExplorer::ApplicationLauncher::Gui;

View File

@@ -138,7 +138,7 @@ static void performTestRun(QFutureInterface<TestResultPtr> &futureInterface,
continue;
}
testProcess.setArguments(testConfiguration->argumentsForTestRunner(settings));
testProcess.setArguments(testConfiguration->argumentsForTestRunner());
testProcess.setWorkingDirectory(testConfiguration->workingDirectory());
if (Utils::HostOsInfo::isWindowsHost())
environment.insert("QT_LOGGING_TO_CONSOLE", "1");
@@ -304,8 +304,7 @@ void TestRunner::debugTests()
Debugger::DebuggerStartParameters sp;
sp.inferior.executable = commandFilePath;
sp.inferior.commandLineArguments = config->argumentsForTestRunner(
*AutotestPlugin::instance()->settings()).join(' ');
sp.inferior.commandLineArguments = config->argumentsForTestRunner().join(' ');
sp.inferior.environment = config->environment();
sp.inferior.workingDirectory = config->workingDirectory();
sp.displayName = config->displayName();

View File

@@ -24,6 +24,7 @@
****************************************************************************/
#include "testsettings.h"
#include "autotestconstants.h"
#include "testframeworkmanager.h"
#include <coreplugin/id.h>
@@ -33,7 +34,6 @@
namespace Autotest {
namespace Internal {
static const char group[] = "Autotest";
static const char timeoutKey[] = "Timeout";
static const char omitInternalKey[] = "OmitInternal";
static const char omitRunConfigWarnKey[] = "OmitRCWarnings";
@@ -50,7 +50,7 @@ TestSettings::TestSettings()
void TestSettings::toSettings(QSettings *s) const
{
s->beginGroup(group);
s->beginGroup(Constants::SETTINGSGROUP);
s->setValue(timeoutKey, timeout);
s->setValue(omitInternalKey, omitInternalMssg);
s->setValue(omitRunConfigWarnKey, omitRunConfigWarn);
@@ -60,20 +60,12 @@ void TestSettings::toSettings(QSettings *s) const
// store frameworks and their current active state
for (const Core::Id &id : frameworks.keys())
s->setValue(QLatin1String(id.name()), frameworks.value(id));
s->beginGroup(qtTestSettings.name());
qtTestSettings.toSettings(s);
s->endGroup();
s->beginGroup(gTestSettings.name());
gTestSettings.toSettings(s);
s->endGroup();
s->endGroup();
}
void TestSettings::fromSettings(QSettings *s)
{
s->beginGroup(group);
s->beginGroup(Constants::SETTINGSGROUP);
timeout = s->value(timeoutKey, defaultTimeout).toInt();
omitInternalMssg = s->value(omitInternalKey, true).toBool();
omitRunConfigWarn = s->value(omitRunConfigWarnKey, false).toBool();
@@ -88,14 +80,6 @@ void TestSettings::fromSettings(QSettings *s)
frameworks.insert(id, s->value(QLatin1String(id.name()),
frameworkManager->isActive(id)).toBool());
}
s->beginGroup(qtTestSettings.name());
qtTestSettings.fromSettings(s);
s->endGroup();
s->beginGroup(gTestSettings.name());
gTestSettings.fromSettings(s);
s->endGroup();
s->endGroup();
}

Some files were not shown because too many files have changed in this diff Show More