Commit Graph

86 Commits

Author SHA1 Message Date
Ulf Hermann e69a4b17cd QmlCompiler: Rename sequences' "valueType" to "elementType"
"valueType" is ambiguous. The prevailing meaning is a type that's passed
by value in QML. We mean the type of the list contents (or elements)
here.

Change-Id: Iaf4c0efe272dc6ec7511d2361e7e5ce475936fba
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
2025-08-31 09:41:56 +02:00
Ulf Hermann 527e108c9f qmltc: Don't crash on missing type information
Pick-to: 6.10 6.9 6.8
Fixes: QTBUG-136355
Change-Id: I0cf56674b451187a3483f4dfefbf6e1ccb275d04
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Semih Yavuz <semih.yavuz@qt.io>
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
2025-08-05 17:06:31 +02:00
Olivier De Cannière 405fb70437 qmltc: Add READ before WRITE in generated Q_PROPERTYs
We currently have two orderings for the READ and WRITE elements of the
macro depending on whether we compile a property or an alias. Make them
uniform by having READ before WRITE in both cases.

Change-Id: I1dd308c921b8948347029c603bc3bca2be87abda
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2025-01-14 19:15:40 +01:00
Ulf Hermann 7afeee48d5 QmlCompiler: Rename attachingType() to attachedType()
That's what it actually is. It doesn't return the attacher but rather
the attachment!

Change-Id: I05e391d9d56ec0b8f56811eba491654dfa386bd9
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
2024-11-11 10:49:58 +01:00
Ulf Hermann de1101c3ab qmltc: Fix usage of namespaced attached types
We can't have a '.' in the variable name. Use '_' instead. In addition,
disambiguate the names by always prepending a number to the part
extracted from QML. This is safe because QML names can't start with
numbers.

Pick-to: 6.8
Fixes: QTBUG-130838
Change-Id: I1243070a3cb901bc4c2c108ecbec0c9cbbc57a55
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
2024-11-08 12:37:47 +01:00
Olivier De Cannière 37c525c6aa qmltc: Wrap raw string literal in QStringLiteral
This fixes build failures with QT_NO_CAST_FROM_ASCII.

Pick-to: 6.8
Task-number: QTBUG-130081
Change-Id: I0c46005b9eda58cf6ab44ea4dd95043b8851af51
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2024-10-21 14:03:02 +02:00
Olivier De Cannière 95b039747f qmltc: Wrap raw string literal in QStringLiteral
Without this, QT_NO_CAST_FROM_ASCII builds would fail.

Amends 361b601620

Pick-to: 6.8
Fixes: QTBUG-130081
Change-Id: Ifd5a4194a989953b7f0bc5f882b877eccb62cce8
Reviewed-by: Semih Yavuz <semih.yavuz@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
2024-10-21 14:03:00 +02:00
Ulf Hermann e0dd6d0810 QmlCompiler: Assume missing return types to be "void"
qmltyperegistrar leaves out "void" return types when generating methods
and signals. Add those back when reading the files so that we don't have
to special-case "void" in the compilers.

Also, explicitly set the return type of QML signals to "void", for the
same reason.

Change-Id: I94cd9d005c458fe37160eccf5c14f02c53fc300a
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
2024-06-20 21:58:31 +02:00
Ulf Hermann e068324912 Fix coverity warnings
* Make things const where we can
* Avoid copies where we can
* Clarify some types
* Remove dead code

Coverity-Id: 454277
Coverity-Id: 454278
Coverity-Id: 454287
Coverity-Id: 454288
Coverity-Id: 454291
Coverity-Id: 454292
Coverity-Id: 454294
Coverity-Id: 454295
Change-Id: I56150aea78ea2b188083f99bf83816b121ef867a
Reviewed-by: Semih Yavuz <semih.yavuz@qt.io>
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
2024-04-11 15:47:21 +02:00
Luca Di Sera fe6f283a5b qmltc: Enforce basic required properties
Types in QML can expose "required" properties.

A required property is a property that should be initialized when an
instance of the type is built.

Instantiating a type without initializing its required properties is an
hard error.

Currently, `qmltc` generated types do not respect the semantic of
"required" properties.

Instead, `qmltc` will generally default-initialize a required property
without notifying the user of the error.

`qmtlc`, so as to respect the semantic of required properties, will now
require the user to pass an initial value for all required properties at
construction time.

To do so, `qmltc` will now generate a new inner record,
`RequiredPropertiesBundle`, for each compiled top-level type, that
contains the required amount of data to initialize each top-level
required property that is reachable from the compiled type.

An instance of `RequiredPropertiesBundle` will be required, as long as
the type presents at least one required property, in the user-facing
constructor for the generated type.

The information stored in the instance will later be used to provide an
initial value for each required property during the construction of the
component.

An intermediate representation for `RequiredPropertiesBundle` was added
to "qmltcoutputir.h".
`QmltcCodeWriter`, the component responsible for writing the final C++
code, was modified to take into consideration the presence, or lack
thereof, of a `RequiredPropertiesBundle` and output the necessary code
when required.

The code taking care of populating the various IRs was modified to
populate a `RequiredPropertiesBundle` for top-level components as
necessary.
Similarly, the code populating the parameters of the user-facing
constructor was modified to require an instance of
`RequiredPropertiesBundle` when necessary.

The code that populates the body of the user-facing constructor for
top-level types was modified to make use of the parameter by tying into
the existing structure for setting initial values.

`qmltc` uses a user-provided callback to allow the user to set the
initial values for properties when constructing a top-level component.

The body of the user-facing constructor was modified to compose the
user-provided callback with a callable that sets the initial values for
top-level required properties based on the bundle of data in the new
`RequiredPropertiesBundle` instance.

The code that populates the body of the user-facing constructor was
moved into its own free-function, `compileRootExternalConstructorBody`,
to be slightly more explicit about the structure of the code.

A new test was provided to evaluate, some basic cases for the new
behavior. Some pre-existing tests, which made use of required
properties, were modified to comply with the new generated API.

The documentation for `qmltc` was modified with a note about the new
behavior.

Task-number: QTBUG-120698
Change-Id: I1e916dcd91ae976629dad8adc7eacc6390bce7e9
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
2024-04-09 18:17:03 +02:00
Luca Di Sera 9a67465e9e qmltc: Ensure usage of generated setters in `PropertyInitializer`
When `qmltc` compiles a QML type to C++, it generates a proxy object for
the compiled type, `PropertyInitializer`, that knows how to set the
top-level property of the component.

A user can then pass a call-back to the constructor for the compiled
type and use an instance of the generated `PropertyInitializer` to set
the initial values for the top-level properties of the component.

For each top-level property, the generated `PropertyInitializer`
generates a setter.

Based on various parameters, the generated setter can have a different
body.

Generally, the generated setter will prefer calling back to the
component setter for the properties when that is available.

When that is not the case, the generated setter would fall-back to a
more general approach based on `QObject::setProperty`, which has
additional overhead.

This second approach will currently be chosen, when generating the
setter for an owned property of the compiled type.

While `qmltc` will generate a typed setter for those properties, on the
C++ side, at the
point where `PropertyInitializer` is compiled, the inspected owned properties,
that come from the QML side, will not have a write accessor, which in
turn makes the generated code fall-back to the more general
implementation for the setter of those properties.

To ensure that the generated setters for `PropertyInitializer` use a
write accessor when present, `compilePropertyInitializer`, which takes
care of producing the code for the generated `PropertyInitializer`, was
modified to special case the generation of the setter for properties
that are owned by the compiled type, ensuring that the generated setter
will be used to set the initial value for the property.

Change-Id: I0c34d6dd9d85a613d1e8909e94a584bf976a009f
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2024-03-21 21:00:18 +01:00
Luca Di Sera d1241024e6 qmltc: Support setting initial values for reference list properties
When `qmltc` compiles a QML type to C++, it generates a proxy object for
the compiled type, `PropertyInitializer`, that knowns how to set the
top-level property of the component.

A user can then pass a call-back to the constructor for the compiled
type and use an instance of the generated `PropertyInitializer` to set
the initial values for the top-level properties of the component.

Currently, the generated `PropertyInitializer` would refuse to generate
a setter for properties whose type is a list of object types, impeding
the user from being able to set the initial values for properties of
this kind.

To allow setting the initial values for properties whose type is a list
of object types, `qmltc` will generate a setter for those properties
when generating the `PropertyInitializer` class for a type.

The free function `compilePropertyInitializer` in "qmltccompiler.cpp",
that is responsible for generating the `PropertyInitializer` class for a
type, was modified to produce a setter for properties whose type is a
list of object types.

The test that verifies the initial values behavior was modified to have
representative cases for the modified feature.

Fixes: QTBUG-120700
Change-Id: I4a023263ca3dfa3c77c11d1522b8be47b7958109
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2024-03-21 21:00:14 +01:00
Luca Di Sera 48d1c27c89 qmltc: Avoid befriending the root component twice
When `qmltc` compiles a type to C++, if the type is not the root of the
document, it will generate code to befriend the root component.

Similarly, it will generate code to befriend the direct parent of the
component.

In both cases this is done as the component may be created from those
other generated types by accessing some private members of the generated
API.

When a component is not the root of the document, is not an inline
component and its parent is the root of the document, `qmltc` will
generate the same friend declaration twice, once to befriend the root of
the document and once to befriend the direct parent of the type.

For example, if we have some component `Foo` and a root component that
refers to it, say:

```
Window {
    Foo {}
}
```

The generated code for `Foo` will befriend the generated type for the
root component twice.

While multiple friend declaration are not an issue, they are generally
uncommon, as there is no reason to befriend something twice, so that
they may generally stand out as an error or a typo, while making the
code noisier.

Thus, to avoid befriending the document root twice for generated
non-root, non-inline components whose parent is the root of the
document, the code that generates the friend declaration for the direct
parent of such a component was conditioned on that parent not being the
document root, as we would have already befriended it at that point of
the compilation.

Change-Id: Ie6eb4b786317c3c555718b594c689c085b4f2336
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2024-03-21 21:00:02 +01:00
Luca Di Sera 361b601620 qmltc: Allow setting initial values when creating a compiled type
`qmltc`-generated types currently do not allow setting any initial
values for the property of a component during creation.

For example, some component `Foo` with a property `bar`, will have no
way to set `bar` to a specific value from the C++ side of the code
before an instance of `Foo` is obtained by the user.

This lack of control prohibits the user from interacting with certain
processes that are part of the component creation.

For example, if a component provides am `onCompleted` binding that
depends on some of the values of its properties, the user is inhibited
from varying the per-instance values that `onCompleted` depends on, as
the user would be able to vary those values only after the component is
created and the `onCompleted` signal is emitted.

This differs, from example, from the `QQmlComponent` interface, where
the user is able to provide some initialization values as part of
the creation of an instance of the component.

To allow the user to have more control in the initialization of the
instance of a component, before it is fully created, `qmltc` generated
code now allows the user to provide an initialization callback that is
processed as part of the creation cycle of an instance of the component.

The callback provides the user with a generated proxy object,
`PropertyInitializer`, that only knows how to set the writable,
non-private properties of the component.

The generated code for the public constructor of a `qmltc`-generated
type was modified to provide an optional `initializer` parameter that
stores the callback.

The private `QML_init` method that `qmltc` generates for each type, that
performs the required setup to create an instance of a component, was
modified to allow for the same optional parameter, which is passed on by
the public constructor.

The body of `QML_init` was modified to call the new parameter, after
having performed the general set-up for the created instance but before
the instance is completed and before setting up "complex bindings" such
as an `onPropertyChanged` handler.

The callback is called with an instance of the generated proxy object
that is built on-site.

The proxy-object keeps track of the properties that were actually
initialized by the callback. This information is now passed down to
`QML_setComplexBindings`, which avoids setting up any unnecessary
bindings for the properties that were initialized.

A representation for the proxy object was added to the internal IR that
is used by `qmltc` when generating code.
The representation for a compiled C++ type was modified to store an
instance of the proxy object.

The newly stored instance is now populated as part of the general
compilation of a type, by the `compilePropertyInitializer` free-function
in "qmltccompiler.cpp".

The component responsible for the final code-generation,
`QmltcCodeWriter`, was modified to be able to generate code for the new
proxy object representation.

The documentation for `QmltcCodeGenerator::generate_initCode`, which
sets up the body for `QML_init`, was updated to reflect the new body.
A pre-existing issue in the documentation of the method, which failed to
enumerate all generated steps for the body, was fixed as part of the
change.

The preamble that `qmltc` generates for all generated header files
was modified to include "QtCore/qxpfunction.h", to have access to
`qxp::function_ref`, which is used to store the new callback parameter.

A pre-existing snapshot test had its snapshot file,
"src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp", updated to
reflect the changes to the generated code.

A new basic, non-exhaustive test case was added to the
available corpus of `qmltc` tests to test the basic workflow of
providing an initialization callback.

The documentation for `qmltc` was modified to mention the new parameter.

Task-number: QTBUG-120700
Change-Id: I246c1c3634982580d66b31fd891382559a9cc3ae
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2024-03-20 16:59:30 +01:00
Michael Weghorn f7a64d2fc0 QmltcCompiler: Adhere to Compare requirement ("!(a < a)")
The Compare requirements [1] say:

> The return value of the function call operation applied to an object of
> a type satisfying Compare, when contextually converted to bool, yields
> true if the first argument of the call appears before the second in the
> strict weak ordering relation induced by this type, and false otherwise.

That requirement was violated here, because passing
the same value for both arguments would return true,
since the

    inlineComponentB->inherits(inlineComponentA)

check returns true when both inline components
are the same.

Add an equality check to fix that.

Fixes a build failure when building with
CXXFLAGS='-D_GLIBCXX_DEBUG':

    /usr/include/c++/13/bits/stl_algo.h:4892:
    In function:
        void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter =
        QList<variant<QString, monostate> >::iterator; _Compare =
        QmltcCompiler::compile(const QmltcCompilerInfo&)::<lambda(const
        QmltcCompiler::InlineComponentOrDocumentRootName&, const
        QmltcCompiler::InlineComponentOrDocumentRootName&)>]

    Error: comparison doesn't meet irreflexive requirements, assert(!(a < a)).

    Objects involved in the operation:
        instance "functor" @ 0x7ffec14329f8 {
          type = QmltcCompiler::compile(QmltcCompilerInfo const&)::{lambda(std::variant<QString, std::monostate> const&, std::variant<QString, std::monostate> const&)#1};
        }
        iterator::value_type "ordered type"  {
          type = std::variant<QString, std::monostate>;
        }
    Aborted (core dumped)
    ninja: build stopped: subcommand failed.

GDB backtrace:

    Program terminated with signal SIGABRT, Aborted.
    #0  __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at ./nptl/pthread_kill.c:44
    44      ./nptl/pthread_kill.c: No such file or directory.
    (gdb) bt
    #0  __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at ./nptl/pthread_kill.c:44
    #1  0x00007fbe6b4a815f in __pthread_kill_internal (signo=6, threadid=<optimized out>) at ./nptl/pthread_kill.c:78
    #2  0x00007fbe6b45a472 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
    #3  0x00007fbe6b4444b2 in __GI_abort () at ./stdlib/abort.c:79
    #4  0x00007fbe6b6a300d in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6
    #5  0x0000560ae899bec4 in std::sort<QList<std::variant<QString, std::monostate> >::iterator, QmltcCompiler::compile(const QmltcCompilerInfo&)::<lambda(const QmltcCompiler::InlineComponentOrDocumentRootName&, const QmltcCompiler::InlineComponentOrDocumentRootName&)> >(QList<std::variant<QString, std::monostate> >::iterator, QList<std::variant<QString, std::monostate> >::iterator, struct {...}) (__first=..., __last=..., __comp=...)
        at /usr/include/c++/13/bits/stl_algo.h:4892
    #6  0x0000560ae898bd67 in QmltcCompiler::compile (this=0x7ffec1432e80, info=...) at /home/michi/development/git/qt5/qtdeclarative/tools/qmltc/qmltccompiler.cpp:85
    #7  0x0000560ae89264b6 in main (argc=23, argv=0x7ffec1434fc8) at /home/michi/development/git/qt5/qtdeclarative/tools/qmltc/main.cpp:284

[1] https://en.cppreference.com/w/cpp/named_req/Compare

Change-Id: Ie8934b8381ef217c1f8860ee110f6fa2aa0c86fa
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
2023-12-08 13:14:50 +01:00
Ulf Hermann 608473399e QML: Allow JavaScript extension types
This is what we routinely do in the builtins. In particular:
- Add the jsroot metatypes to qmltyperegistrar so that it can validate
  the JavaScript types
- Add a special class info "ExtensionIsJavaScript"
- Pass this through metatypes and qmltyperegistrar.
- Treat it like an extension type in QQmlJSScope but give it its own
  name.
- Ignore it in qmltc. We cannot express JavaScript extensions in C++.

Now qmltyperegistrar has to deal with name conflicts between JavaScript
and C++ types. It does so by always preferring the C++ type if
available. The new class info is private and we don't want to
surprisingly inject JavaScript types into people's QML modules. For our
own types we shall make sure to avoid name conflicts. There is one
prominent name conflict, 'Qt', which we really want to be resolved
towards the C++ side.

Change-Id: Iac224f4b0df2d6398fba0124f0b52d8ddfccace1
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Semih Yavuz <semih.yavuz@qt.io>
2023-11-16 01:42:06 +01:00
Fabian Kosmale d12d7a901f QQmlSA::ScriptBindingKind: Turn into scoped enumeration
and remove the Script_ prefix from its entries. This is more aligned
with Qt's namings conventions.

Pick-to: 6.6
Change-Id: Ie97c2ce204b5532ab6bd6b136145f2a537175fbb
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Semih Yavuz <semih.yavuz@qt.io>
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
2023-08-30 14:18:17 +02:00
Sami Shalayel a1ce0596e5 Replace signal name manipulations with QQmlSignalNames
Remove custom implementations found in qqmljs* and use the
static helper methods from qqmlsignalnames_p.h instead. This sometimes
requires to move some code around to avoid bugs with property that do
not have letters in their name.
Add a warning in the JS implementation of the SignalSpy.qml that the
used heuristic might fail on certain signal names.
Add tests in in tst_qqmllanguage to see if the property change handlers
work correctly for weird names.

Change-Id: I4dc73c34df7f77f529511fa04ab5fcc5385b59fc
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2023-08-15 12:13:31 +00:00
Marc Mutz a5377f32e1 qmltc: fix GCC13 warnings "class X is implicitly friend with itself"
This happens because the generated code contains

    class X {
        ~~~~
    private:
        friend class X; // warning here
    };

Says GCC13 (e.g.):

    tests/auto/qml/qmltc/QmltcTests/.qmltc/qmltc_test_module/inlinecomponents.h:421:18: warning: class ‘QmltcTests::inlineComponents_IC0’ is implicitly friends with itself
      421 |     friend class inlineComponents_IC0;
          |                  ^~~~~~~~~~~~~~~~~~~~

It seems the intended check for documentRoot doesn't work in all
cases, so do the check on the class-name level.

There appears to be no -W flag to control this warning, therefore no
apparent way to suppress it, so we need to fix it.

Amends either b89a92053e or
0990b892ca. I didn't dig into it
further.

Pick-to: 6.6 6.5
Change-Id: I3fe653a398ea5b7a3e045fd3ea8dfb5d5c0f2e5c
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2023-08-02 16:00:47 +02:00
Sami Shalayel 9e322ea167 qmltc: remove useless std::move detected by code checker
CodeChecker is unhappy about it and the value gets copied instead of
moved.
Report-hash:225e9bdd84a57c887f5b18b9d25d625d
Amends 0978bb32a9.

Change-Id: I8d107c9c55b6b99eee5c515873f99673c3d9ee64
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2023-06-12 08:43:25 +02:00
Sami Shalayel 0978bb32a9 qmltc: do not use the implicit QUrl constructor in generated code
Instead, call the QUrl constructor explicitly when constructing url's
from stringliterals.
Add a test to show that binding string (not literal strings) to Url
already uses the explicit QUrl constructor.

Fixes: QTBUG-113875
Change-Id: I838437d9d45d57f416d78e71d718725975bee264
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2023-06-09 15:46:31 +02:00
Olivier De Cannière cdd7fe05f6 QQmlSA: Create an abstraction layer for static analysis
This patch adds abstractions for QML Elements, Bindings, Methods and
Properties. This abstraction layer avoids exposing internal details and
should be more suited for static analysis tasks. It is now possible to
write qmllint plugins without including private headers.

As a drive-by, change tst_qmllint:verifyJsRoot to open files in text
mode instead of binary. This fixes an issue where line endings cause
issues on Windows.

Fixes: QTBUG-102276
Change-Id: I6b6e53f1e0078734a18f3aa51807fbe875b375f0
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2023-05-30 13:42:35 +02:00
Ulf Hermann aa49d0f2d9 qmllint: Fix attached property re-use detection
Move the detection into the QtQuick lint plugin. It's mostly meant for
QQC, so let's auto-enable it for attached types derived from
QQuickAttachedPropertyPropagator.

To this end, two new categories are introduced: The Quick lint plugin
gets its own attached-property-reuse category which is synonymous to the
default category of the same name. Furthermore, we add a
controls-attached-property-reuse category for only checking controls.
That one is implied by either of the others.

Finally, fix the id vs. scope resolution to actually do something.
This way we can give appropriate hints when the outer type has an ID
already.

Pick-to: 6.5
Fixes: QTBUG-110834
Change-Id: Ib71a9e3bbc10bac77f36db6cc441af88df20fd33
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2023-02-14 13:32:13 +01:00
Sami Shalayel 01d84ffc74 qmltc: export generated classes
Add QMLTC_EXPORT_MACRO_NAME and QMLTC_EXPORT_FILE_NAME arguments to
qt_add_qml_module() that allows the user to export qmltc-generated code
from its library. The qmltc-generated code will include the header-file
specified in QMLTC_EXPORT_FILE_NAME and will be exported with the macro
specified by QMLTC_EXPORT_MACRO_NAME.
Leave both options unspecified to not export the code generated by
qmltc.

Describe the options in the documentation and write a test to see if the
class really has an export macro in the generated code:
1) tst_qmltc_qprocess will test if the macro and the header are correctly
inserted in the generated code.
2) tst_qmltc_{no,}diskcache will test if the generated code can still be
   used from a static library.

Fixes: QTBUG-106840
Task-number: QTBUG-96040
Change-Id: I554f03bcdf043e8114e42f51a7289a5c00de4f89
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2023-02-02 18:11:07 +01:00
Sami Shalayel ee9e3a10d9 qmltc: fix handlers for c++-signals
Allow qmltc to generate handlers for c++-defined signals with const
parameters by changing the safeguard to avoid type mismatch between
slots and signals.

First, remove the qOverload in the generated QObject::connect call to
be able the connect slots and signals with different types (namely,
pass by const references and pass by value should be interchangeable but
is not allowed by qOverload).

Second, save in QQmlJSMetaParameter when types are passed by pointer.
Like this, qqmljsimportvisitor can check if a value type is indeed
passed by value or const reference in a C++ signal. The same for reference
types that need to be passed by (const and non-const) pointer.
Print a message when an type is passed by argument in an incompatible
way instead of letting qmltc generate uncompilable code, which makes the
compiler print out cryptical messages.

Third, add a qqmlcpptypehelpers template that decides if value types
should be passed by value or reference, by letting the c++ compiler
check if sizeof(T) > 3*sizeof(void*).

Fixes: QTBUG-107625
Fixes: QTBUG-107622
Change-Id: I1a00532df591d10f74c1fd00dff5b7fccf40cb22
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2022-12-07 13:50:01 +01:00
Sami Shalayel 784367ad17 QQmlJSMetaParameter: Encapsulate parameter information
Previously, there were four lists that contained each one entry
for each parameter. There was one list responsible for the names, types,
type names and const-qualifiers but this was quite bothersome to use
(e.g. they not always had the same length).

This commit introduces QQmlJSMetaParameter to
encapsulate all the information required when manipulating parameters.
This reduce the 4 lists to one, making parameters easier to handle
and QQmlJSMetaMethod easier to read.

This is a purely refactoring change, no new functionality was added.

Task-number: QTBUG-107625
Change-Id: Ia41b823c9e6294ee26e828071b802cac6b4058ce
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2022-12-02 10:39:48 +01:00
Sami Shalayel aa3e01645d qmltc: add singleton support
Add singleton support to qmltc.

Add the QML_SINGLETON annotation to the class, generate a static T*
create(QQmlEngine*, QJSEngine*) method for the engine and also add test
this new functionality.

Fixes: QTBUG-106828
Change-Id: I7b6b39ab0c8a427b3166562c3f04cf4a7eaa20e2
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2022-11-23 10:05:30 +01:00
Tim Blechmann aadf0243c6 tooling: silence -Wextra-semi-stmt
silence clang's -Wextra-semi-stmt

Pick-to: 6.4
Change-Id: I5dee9ec46b44076f0fc0590399131b1b267e1ad2
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2022-11-16 12:57:58 +08:00
Sami Shalayel fa1a288523 qmltyperegistrar: add IsConstant for method parameters
Mark method parameters with IsConstant instead of including "const " in
the typename, which makes type resolution in the qml compilers
impossible. This also avoids a crash in qmltc happening when qmltc sees
a signal defined in C++ that has a const parameter.

When qmltyperegistrar writes out the types in the qmltypes, check if it
starts with a const, remove it and add instead IsConstant: true. The
name returned by MOC is normalized so no need to check for "volatile
const" or "const volatile" (its always the latter) and no need to
filter out for extra whitespace.

Once the const is read by the qmltypes reader, propagate the
const-information around using a newly introduced enum called
QQmlJSMetaMethod::PConstness that can currently be
Const or NonConst.

Also add the isConstant property to the Parameter.qml in the tooling
module.

Add a test to see if the IsConstant information is written into the
qmltypes.

This is also required for QTBUG-107625.

Fixes: QTBUG-108147
Task-number: QTBUG-107625
Change-Id: I13bda0a27fe83867f259b751468788128fec82ed
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2022-11-11 17:33:12 +01:00
Ulf Hermann 91c6d45559 QmlCompiler: Allow lists as arguments to methods
Since lists are allowed as property types, you should be able to pass
them as arguments to methods, too. For now we only handle QML-defined
methods, implemented by adding JavaScript functions to your QML
elements. The usual type coercion rules apply if you pass JavaScript
arrays to such methods. That is, it usually works.

We now resolve properties with the "list" flag to their actual types
(QQmlListProperty or QList) already when populating the QQmlJSScope, and
store the list types as members of QQmlJSScope rather than as a special
map in QQmlJSTypeResolver. This allows us to do the same to lists passed
as arguments and simplifies some of the type analysis.

Fixes: QTBUG-107171
Change-Id: Idf71ccdc1d59f472c17084a36b5d7879c4d959c0
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2022-11-10 15:00:11 +01:00
Sami Shalayel 1f726ea143 qmltc: Add some sugar for generated reference-type-list properties
When compiling a reference type list with qmltc into a QQmlListProperty,
also generate helper methods to make the manipulation of those lists by
the user easier in c++.

For a list myList, generate the methods myListAt(), myListAppend(), ...
as shown in the Birthdayparty example.
Also add some documentation about the ownership of the arguments, and
tests to see if the list can be accessed from C++.

Task-number: QTBUG-107570
Change-Id: Iec0041015311639ead39660fdccf147749566592
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2022-10-28 17:34:03 +02:00
Marc Mutz c2d490a238 Port from qAsConst() to std::as_const()
We've been requiring C++17 since Qt 6.0, and our qAsConst use finally
starts to bother us (QTBUG-99313), so time to port away from it
now.

Since qAsConst has exactly the same semantics as std::as_const (down
to rvalue treatment, constexpr'ness and noexcept'ness), there's really
nothing more to it than a global search-and-replace.

Task-number: QTBUG-99313
Change-Id: I601bf70f020f511019ed28731ba53b14b765dbf0
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2022-10-07 23:38:56 +02:00
Sami Shalayel b89a92053e qmltc: support basic inline components
This patch adds basic inline component support to qmltc.

Implementation details:
* added tests:
** (for all tests: see if QQmlComponent would do the same thing)
** try simple inline components
** try inline components extending other inline components
** try recursive inline components (inline component A contain a B that
itself contains a A)
** make sure ids in inline components are in their own context, and
** make sure alias inside of inline components work
** remove qmltc_qprocess that tests the error message when inline
components are encountered
** test that inline components get their own context (by aliasing a
property that they should not be able to see)
** test that also empty components work
** other tests inspired from those at tst_qqmllanguage
* separate types depending on the inline component they belong in
  qmltcvisitor and qmltccompiler
** mostly by replacing T with QHash<QString, T>, where the belonging
inline component name serves as hash key
** added a list of inline component names in qmltc
* generate correct qmltc-code for inline components
** as they sometimes have mimic a document root and sometimes not
** generate their own "typeCount"-method
** fixed naming used in qmltc generated code by using the inline
component names from the qqmljsscope.

There is one missing feature (using inline components from other files,
using QmlFileName.MyInlineComponent) that will be added in a separate
commit.

Fixes: QTBUG-106882
Change-Id: Iabe1a8b787027367d73d34bcd93c5f7b5480d217
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2022-09-26 10:59:15 +02:00
Sami Shalayel b85b545252 qmltc: append to lists in one go
Instead of calling the methods to get the elements-to-be-appended and
the append-calls alternatively, put first all the elements-to-be-appended
on the stack before appending them all one after the other.

Instead of compiling list bindings right away into an append call,
collect all consecutive elements of a same list before printing all
append calls.
This requires knowing when all bindings are processed (else the last
listbinding are collected but never compiled), such that
this changes QmltcCompiler::compileBinding to accept lists of
bindings instead of single bindings.
Added private fields to QmltcCompiler to save the property of the
current list and the list bindings collected so far.

Fixes: QTBUG-106783
Change-Id: I75f71e828875e3d95540e6f33574bee7fa8bccbf
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2022-09-22 10:19:36 +02:00
Sami Shalayel 95c155a524 qmltc: refactor compileBinding to be less unwieldy
QmltcCompiler::compileBinding was getting big and unwieldy as it was
compiling any kind of binding in a big switch-statement all by itself.

Move the binding specific logic into separate helper methods and add
a method that calls the right helper method depending on the binding
type.

This change prepares the code for QTBUG-106783.

Task-number: QTBUG-106783
Change-Id: I900e182a82ae780186ad79a5cb5db31bd0548e33
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
2022-09-22 10:19:12 +02:00
Sami Shalayel d9add5c2d4 qmltc: test support for generalized group properties
Test support for generalized group properties in qmltc.

Also, force group property bindings to be deferred when they belong to a
generalized grouped property, while "not-generalized" grouped properties
never are deferred.

Fixes: QTBUG-105378
Change-Id: Iadc64d7033f9446ccf53e305d8831c7d348f257c
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2022-09-01 22:12:32 +02:00
Sami Shalayel e26bf40513 qmltc: add some internal documentation
add some documentation to qmltc's internal behavior that is not
self-documenting enough.

Change-Id: I131ee875944e294e0472519573ace4058f4f1821
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2022-08-31 21:01:45 +02:00
Sami Shalayel 8120ec1d3d qmltc: test alias on properties with attributes
Add tests to qmltc to see if it behaves well for aliases to different
kinds of properties, and compares if the engine shares the same
behavior. Same for the attributes in the QMetaProperties.

Changes:
* add some more MOC information to aliases
** always add NOTIFY to aliases (like the engine does)
** always set DESIGNABLE to false for aliases (like the engine does)
** always set CONSTANT to false for aliases (like the engine does)
** always set STORED to false for aliases (like the engine does)

Test if:
* default aliases works when compiled via qmltc
* attributes of aliases are set correctly in QMetaProperty and compare
  it to the attributes of the QMetaProperty obtained from the engine.
* aliases can read/written/reset/notified

Fixes: QTBUG-105708
Change-Id: I66b9c43c8c8de3dbd2b33d5ce15cd42ffb377ce7
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2022-08-31 09:33:02 +02:00
Sami Shalayel 75769767ac qmltc: translation binding support
Implement and test support for translation bindings in qmltc:
* qsTr()
* QT_TR_NOOP()
* qsTrId()
* QT_TRID_NOOP()

Not compiled by qmltc, but instead interpreted as script bindings:
* combinations like qsTr(qsTr())
* qsTranslate() (as in qmlsc)
* QT_TRANSLATE_NOOP() (as in qmlsc)

Add the *.qm files directly to the resources as qt_add_translations() is
not available from qtdeclarative (the cmake function lives in qttools that
depends on qtdeclarative).

Fixes: QTBUG-104637
Task-Id: QTBUG-105346
Change-Id: Ia9433c2bcef01f3486358d963059d9779c67708c
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2022-08-25 11:35:57 +02:00
Andrei Golubev f11ad705e0 qmltc: Support CONSTANT and RESET property attributes in aliases
As a drive by, propagate CONSTANT attribute through the .qmltypes file
and qmlcompiler library

Task-number: QTBUG-91956
Change-Id: I5802fa29ddedcdadae3e505efca0c4fb4d6b2593
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2022-07-29 13:24:49 +00:00
Andrei Golubev 665bf7f10a Remove redundant parameter from generated special functions of qmltc
Finalization argument is unused in binding processing functions so
there is no need to have it in the first place

Pick-to: 6.4
Change-Id: I800b43b5114dacc54c3e852adc02bc6be66dd54e
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2022-07-28 14:58:43 +02:00
Andrei Golubev 5704970885 Separate script bindings from others in generated qmltc code
Align script binding creation to QQmlObjectCreator model: simple
bindings (e.g. literal, object, etc.) are created instantly when
encountered; complex bindings (e.g. script, translation?) are posponed
until QQmlObjectCreator::finalize() (in reality it is a bit more
complicated). Make qmltc follow this logic by creating script bindings
in a separate object creation step

Additionally, this should theoretically improve performance of the
object creation process as script bindings (that have interdependencies)
would now re-trigger less as they are all centrally created at once
(after simple bindings are already done). Note, however, that the
specific order of binding creation between children may vary in
comparison to QQmlObjectCreator

Task-number: QTBUG-91956
Task-number: QTBUG-96269
Pick-to: 6.4
Change-Id: I25067adf7b16d0f1852a5108a0b6d6597ac28a53
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2022-07-28 14:58:43 +02:00
Andrei Golubev ca2a903b55 Address TODOs in qmltc tool
Deal with low hanging fruits. Remove outdated TODOs.
Fix the rest. Many things are still open

Pick-to: 6.4
Change-Id: Ia2cd0724552b1116c34d12a30a4c911ee42e15d6
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2022-07-28 14:58:43 +02:00
Andrei Golubev 12ce728259 qmltc: Make explicit component ids accessible during object creation
Explicit components could be accessed by id like regular objects. Make
this work in qmltc by revisiting the object creation procedure - store
explicit components along with pure QML types in
QQmltcObjectCreationBase:

xxxxxxxx x'x'x'x'x'|yyyyy...
^        ^          ^
pure     explicit   types from base class
types    components

As a drive by, fix unset required property in one test file and add a
bunch of other test files to the initTestCase() check

Pick-to: 6.4
Change-Id: Ibdaa430d692c81101853f51dae1da462a57a9980
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2022-07-28 14:58:43 +02:00
Andrei Golubev e14b7fe597 qmltc: Fix alias assignment code generation
Fix subtle issue where alias assignment would cause qmltc to generate
direct property set code (doesn't work for aliases since those do not
have "real" properties)

Remove now redundant TODO and identical code path when compiling alias
assignments on types with composite bases (used to work poorly during
prototype times)

Pick-to: 6.4
Change-Id: Ifacf5872ff5432a748fb1ec16c300ec844d65e9a
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
2022-07-27 17:16:56 +02:00
Andrei Golubev 880a9c2426 qmltc: Do not generate duplicated Q_UNUSED() for endInit instruction
We already generate the Q_UNUSED() for input arguments when compiling
the common part of endInit (in QmltcCodeGenerator), no need to repeat
it elsewhere

Pick-to: 6.4
Change-Id: I2c33389ff6f1c2063db80586425b260c764905f4
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2022-07-27 11:54:48 +02:00
Andrei Golubev 2d5f3eb86e Support RegExpLiteral bindings in qmltc
Task-number: QTBUG-91956
Pick-to: 6.4
Change-Id: I02f8c6d1f0d6e4411985ffe3f22fb3c51fb36db6
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2022-07-27 11:54:48 +02:00
Andrei Golubev 1453650419 qmltc: Acknowledge BINDABLE-only properties
Task-number: QTBUG-91956
Change-Id: I4c34ccd9d6d5cf4c6a6c1b54e67374515e67861a
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2022-07-26 10:34:49 +02:00
Andrei Golubev ca68b0cde7 qmltc: Use QMetaObject hierarchy as reference for meta index calculation
qmltc needs to compute a QMetaProperty index ahead of time when creating
property bindings. This procedure has to acknowledge that extensions
exist

Change-Id: I7bf6b6c558ce78e0fec5ee880bc4d39a79fe5640
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
2022-07-26 10:34:49 +02:00
Sami Shalayel 111225b6c4 Support value type lists in qmltc
Generate list of values in qmltc when possible, by using QList<T>
instead of QQmlListProperty<T>, e.g., when T is an int or a QColor..

Fixes: QTBUG-100313
Change-Id: Ifd84cbb550437854fb156a295435240cef446e61
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2022-07-13 13:29:49 +02:00