Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. General talk
  3. Blog
  4. QML Tooling in 6.11 blog post series
Qt 6.11 is out! See what's new in the release blog

QML Tooling in 6.11 blog post series

Scheduled Pinned Locked Moved Unsolved Blog
3 Posts 1 Posters 318 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    Sami Shalayel
    wrote on last edited by Sami Shalayel
    #1

    Hello!

    I started writing a blog post series on the new features available in QML Tooling for Qt 6.11. You can find part 1 on qmlls at
    https://www.qt.io/blog/whats-new-in-qml-language-server-in-6.11 (I copy-pasted it also below)
    Parts 2 and 3 will be about context property warnings and a qmllint warning overview.
    Feel free to ask any question on QML Tooling in 6.11 here :)

    Best,
    Sami


    The latest Qt release, Qt 6.11, is just around the corner. This short blog post series presents the new features that QML tooling brings in Qt 6.11, starting with qmlls in this part 1. Parts 2 and 3 will present newly added qmllint warnings since the last blog post on QML tooling and context property configuration support for QML Tooling.

    Go to C++ definition

    qmlls shipped with 6.11 supports jumping to C++ definition on projects targeting Qt 6.10 or later. To use this feature, enable qmlls in your editor via this guide for Qt Creator or this guide for VS Code.
    I will use Qt Creator for the screenshots.

    Let's say you have a project that contains a QML element defined in C++:

    class MyItem : public QObject {
        Q_OBJECT
        QML_ELEMENT
        ...
    };
    

    For qmlls to find its C++ definition, the file defining MyItem should be in the QML module's qt_add_qml_module call in CMakeLists.txt:

     qt_add_qml_module(appuntitled12
        ...
        SOURCES myitem.h myitem.cpp
    )
    

    In your editor, open a QML file that uses MyItem, right-click MyItem and use Follow symbol under cursor in Qt Creator or Go to Definition in VS Code. Alternatively you can also do Ctrl+Click (or Cmd+Click on macOS) on MyItem.

    Opening a file that uses MyItem
    qmlls should make your editor open the C++ file that defines MyItem and position the cursor on the line where MyItem is defined.

    Definition of MyItem

    The same should also work for properties, methods, and other members of QML components defined in C++.

    You can use the standalone qmlls release to try out this new feature before the Qt 6.11 release. Both Qt Creator and VS Code
    have an option to download the standalone qmlls version, see here for Qt Creator and here for VS Code.

    Multiple project support

    Before 6.11, a single instance of qmlls could not support working on multiple QML projects at the same time. Project-specific information, such as import and build paths, was previously global and shared across all opened projects. This used to lead to bugs, such as bogus import warnings during linting, caused by the use of incorrect or unrelated import paths.

    With 6.11, we added a way for editors to open multiple projects in qmlls without all the previously mentioned bugs. This provides better support
    for editors that can't spawn multiple instances of qmlls, such as Visual Studio.

    To make qmlls properly open multiple projects in the same instance, editors need to declare the root project folder for each opened project and pass the build path information for each project.

    Declaring the root project folder

    Editors can use the Language Server Protocol Workspace
    folder
    feature to communicate the "project root folders" to language servers like qmlls. Each project root folder has its own settings, including import paths, and QML files are mapped to their project root folder via their file paths.

    For example, if there are three workspace folders:

    • ~/projects/projectA
    • ~/projects/projectA/subproject
    • ~/projects/projectB

    Then qmlls will open

    • ~/projects/projectA/MyComponent.qml in the ~/projects/projectA
      workspace
    • ~/projects/projectA/subproject/MyComponent.qml in the
      ~/projects/projectA/subproject workspace
    • ~/projects/projectA/subproject/subfolder/MyComponent.qml in the
      ~/projects/projectA/subproject workspace

    QML files belonging to no project end up in a fallback workspace folder.

    Passing the build path information

    Passing build path information is a bit harder when opening multiple projects in the same qmlls instance: information passed via command-line parameters and environment variables is applied to all workspace folders. Therefore, qmlls clients need to pass the build paths for each project separately.

    To pass the build path information, the editor can send a $/addBuildDirs notification with an AddBuildDirsParams parameter that contains the mapping from workspace folder to build path.

    export interface UriToBuildDir {
        baseUri: URI;
        buildDirs: string[];
    }
    export interface AddBuildDirsParams {
        buildDirsToSet: UriToBuildDir[];
    }
    

    With this information, qmlls loads the project-specific information from the build folders for each workspace folder without mixing up type definitions and import paths across workspaces.

    Multiple project support

    Imagine the following situation: You have a QML component defined in C++ called MyComponent that you use in a QML file, and you want to modify MyComponent. qmlls can't know about any changes to MyComponent until after a project build. For instance, a recently added property in MyComponent will not be recognized. In this situation, this means that every time you modify MyComponent, you have to build the project before being able to use or adapt the QML usages. This can lead to the following iterative loop:

    1. Modify MyComponent
    2. Build the project
    3. Adapt MyComponent usage in .qml file
    4. Go to 1. for the next MyComponent modification

    where step 2 is likely to be forgotten and adds friction to the development process. Outdated warnings, such as the newly added property not existing, might appear in step 3 if step 2 was forgotten. With the CMake Calls feature, step 2 is automatically done by qmlls.

    Triggering a CMake Call

    qmlls triggers CMake calls during startup and on C++ header changes. It uses the type information in the build folder to locate and watch headers that define C++ components. A file watcher informs qmlls whenever a C++ header is modified or saved to disk.

    The CMake call builds the all_qmltyperegistration CMake target to generate the type information required by qmlls. This target is lighter than a complete project build because it tries to avoid building QML-unrelated parts of the project. To avoid using up too many resources, qmlls uses one job for the CMake calls by default; see here on how to customize it.

    For Qt 6.12, it is planned to make qmlls pop up a progress indicator in your editor, if your editor supports it, once a CMake call starts. Qt Creator and VS Code already support the progress indicator functionality.  You can cancel the background build from inside your editor via the (x) button on the progress bar. qmlls closes the progress bar once the build finishes, and reloads the information from the build folder to generate new up-to-date qmllint warnings, go-to-definition locations, etc.

    Enabling CMake Calls

    The feature is disabled by default in Qt Creator and should be enabled by default in VS Code and other editors.

    To enable or disable the feature,

    • Set the "Enable qmlls's CMake integration" checkbox for Qt Creator.
    • Set the "Use no C Make Calls" checkbox for VS Code.
    • See the qmlls documentation for other editors.

    Summary

    We took a look at the new features of qmlls in Qt 6.11: go to C++ definition, multiple project support, and the CMake calls feature, including a small peek at the CMake calls progress indicator coming in Qt 6.12.

    Feel free to open a bug report at https://qt-project.atlassian.net/jira/for-you in case you encounter anything weird or not working as expected.

    1 Reply Last reply
    0
    • S Offline
      S Offline
      Sami Shalayel
      wrote on last edited by
      #2

      Part 2 is out at https://www.qt.io/blog/whats-new-in-qml-tooling-for-qt-6.11-part-2 ! Attaching the content below:


      The latest Qt release, Qt 6.11, is just around the corner. This short blog post series presents the new features that QML tooling brings in Qt 6.11. You can find part 1 on new qmlls features here
      .

      qmllint got a lot of new features since our last blog post on qmllint warnings, so this blog post will go through the list of qmllint warnings added between Qt 6.6 and Qt 6.11. A list of all existing qmllint warnings, including examples, can be found in the documentation . We will link to the specific warning documentation for each warning listed here so you can easily find more information and examples on how to trigger and fix the warning.

      Shadowing QML members

      Shadowing happens when your QML component redefines an id, property, signal, or method that already exists in a base class. It is both a powerful and dangerous construct that can lead to weird unexpected behaviors and reduces performance.

      In Qt 6.11, we added the virtual and override keywords to mark properties that shadow or can be shadowed. In Qt 6.10, we added the final keyword to mark properties that can't be shadowed. Altogether, we have:

      • virtual for properties that can be shadowed.
      • override for properties that must shadow another property.
      • final for properties that must not be shadowed.

      Properties that have neither virtual nor override might shadow silently: no warning would be emitted by the QML runtime or qmllint. Can you spot which property is shadowing in the following code snippet?

      // Building.qml
      import QtQuick
      
      Item 
          property int floors
          property string rotation // like CSS rotate, "-120deg"
          property date constructionDate
      
      

      Would you have noticed the shadowing property if I hadn't told you there was one? The property rotation already exists in the base type Code that expects to see the rotation property from the base type will see a string instead and probably won't work with the Building component. To fix this, we could rename the rotation property in Building.qml to cssRotation, for example:

      // Building.qml
      import QtQuick
      
      Item 
          property int floors
          property string cssRotation // like CSS rotate, "-120deg"
          property date constructionDate
      
      

      Can you guess what the next code snippet outputs?

      import QtQuick
      
      Item 
          clip: true
          Component.onCompleted: console.log(clip) // what does this print?
          /* ... */
          function clip() 
      
      

      This snippet prints out

      function clip() 
      

      at runtime, instead of an expected true, because the clip method shadows the property of the same name. This example shows that shadowing does not only happen between properties. It can also happen between any combination of properties, signals, methods, and ids. Especially shadowing with ids can easily become confusing, can you guess what the output of this snippet is?

      import QtQuick
      
      Item 
          x: 42
          Component.onCompleted: console.log(x) // what does this print?
          /* ... */
          Item 
      
      

      You probably guessed correctly that the output is probably not 42. The lookup to x gives a higher priority to ids than to properties, which makes console.log(x) print out the Item with id x. This is hard to see and debug. Luckily, in Qt 6.12, this won't be a problem anymore with the new [id-shadows-member] qmllint warning.

      qmllint will warn for situations where:

      • A property incorrectly overrides another one. ([property-override]
      • Multiple inline components have the same name. ([duplicate-inline-components]
      • Multiple members defined in the same type have the same name. ([duplicated-name]
      • An id shadows another member if the member is in use. ([id-shadows-member]*)
      • A member shadows another one. ([shadow]**)

      (*) This warning will be available starting with Qt 6.12.

      (**) To get the full set of shadowing warnings, enable the [shadow] category by adding Shadow=warning inside the .qmllint.ini settings file. The category is disabled by default as not all shadowing cases can currently be fixed. For example, there is currently no way to mark a method as shadowing a property in QML. You can add the // qmllint disable shadow comment to silence the warning for each occurrence.

      New JavaScript-specific warnings

      We added new JavaScript-specific warnings to qmllint to bring it on par with the embedded Qt Creator QML code model. Those warnings are not really QML-specific, and more about the general usage of JavaScript:

      • var declarations in JavaScript blocks. ([var-used-in-block-scope]
      • Comma expression usage. ([comma]
      • Expression statements that do nothing. ([confusing-expression-statement]
      • Expressions like ---x or +++x. ([confusing-minuses] and [confusing-pluses]
      • void operator and eval() function usage. ([void] and [eval]
      • == operator usage with value coercion. ([equality-type-coercion]
      • Usage of ?. on elements that can't be null. ([redundant-optional-chaining]
      • Usage of empty JavaScript blocks in bindings that don't return any value. ([unintentional-empty-block]
      • Code that never runs. ([unreachable-code]
      • Case blocks not ending with return, break, throw, or continue. ([unterminated-case]
      • Usage of variables before their definition. ([var-used-before-declaration]
      • Usage of assignment operators in conditionals. ([assignment-in-condition]
      • With statement usage. ([with]
      • Usage of literal constructors, like new Boolean(). ([literal-constructor]
      • Usage of functions before their definition. ([function-used-before-declaration]*)

      (*) This warning is not enabled by default.

      New enumerations warnings

      We added multiple warnings on the usage and definition of enumerations in QML:

      • Incorrect usage of enum as a type name. ([enums-are-not-types]
      • Enumerations defined at the wrong places. ([non-root-enums]
        and [inline-component-enums]
      • Usage of non-existing enumeration entries. ([missing-enum-entry]
      • Lowercase enumerations. ([enum-key-case]
      • Enumerations with name collisions. ([enum-entry-matches-enum]

      We removed a warning for unscoped enumerations defined in C++ ([restricted-type]) that warned on enum accesses like ComponentName.EnumName.key. Accessing enums by enum name in QML is allowed in Qt 6.11 and was added by https://codereview.qt-project.org/c/qt/qtdeclarative/+/646544

      New property warnings

      We also added some warnings when assigning or binding values to a property:

      • Assigning multiple times to the same non-list property. ([non-list-property]
      • Calling a property as if it were a function. ([use-proper-function]
      • Preferring specific types instead of var in property definitions. ([prefer-non-var-properties]
      • Accessing a singleton instead of an attached property. ([access-singleton-via-object]
      • Forgetting to set a required property. ([required]
      • Binding more or fewer than one child in a Component. ([component-children-count]
      • Forgetting to make a non-constant C++ property notifiable. ([stale-property-read]

      New miscellaneous warnings

      Last but not least, we also added warnings that didn't relate to the previous categories:

      • Using invalid qmllint comment directives. ([invalid-lint-directive]
      • Using Component as a top-level type in a QML file. ([top-level-component]
      • Instantiating uncreatable types. ([uncreatable-type]
      • Importing QML modules using file selectors. ([import-file-selector]*)

      (*) This warning is not enabled by default.

      Summary

      We described the shadowing warning newly introduced in Qt 6.11, with a short outlook to 6.12, and took a look at the long list of newly added warnings since Qt 6.6.

      You can find the documentation for all warnings in this list. Feel free to open a bug report in JIRA in case you encounter a warning that is not working as expected or is insufficiently documented.

      1 Reply Last reply
      0
      • S Offline
        S Offline
        Sami Shalayel
        wrote on last edited by
        #3

        Part 3 is out at: https://www.qt.io/blog/whats-new-in-qmllint-for-qt-6.11-part-3


        The latest Qt release, Qt 6.11, is just around the corner. This short blog post series presents the new features that QML tooling brings in Qt 6.11. You can find part 1 on new qmlls features here, and part 2 on new qmllint warnings here{rel="noopener" target="_blank"}.
        In this blog post, we will start with a short recap on the context property and go through the new context property support in qmllint and QML Language Server.

        Recap on context properties

        What are they?

        Context properties embed C++ objects into QML. They are defined at runtime on the QQmlContext of a QObject, and can be accessed from QML. Here is an example:
        Don't do this at home: context properties.
        The C++ code uses engine.rootContext()->setContextProperty(...) to define the context property at runtime, and the QML code accesses it via myProperty. Running the above program will print out the date and time obtained from QDateTime::currentDateTime() during the setContextProperty()-call.

        Why are they bad?

        The above example suffers from multiple problems because of its use of context properties.

        Limited reusability of the QML files

        QML files with context property usages have a dependency on a specific QQmlContext, even if there is nothing in the QML files that states that dependency. Therefore, anyone trying to reuse your code will have difficulty determining whether the reuse location has a QQmlContext sufficient for your code.
        In our previous example, reusing Main.qml in another place with a different context triggers these runtime errors:
        qrc:/qt/qml/contextproperties/Main.qml:6: ReferenceError: myProperty is not defined qrc:/qt/qml/contextproperties/Main.qml:4: ReferenceError: myProperty is not defined

        Limited QML tooling support

        QML tooling doesn't know about the context property definition and can't discern unqualified accesses from context property usages. You might have seen in the previous screenshot that QML Language Server warns that usages of myProperty are unqualified accesses

        How to replace them?

        You can find a guide on how to replace them with singletons or required properties in the documentation (warning: might contains spoilers!) .

        What if replacing them is not an option?

        Sometimes replacing context property usages might not be feasible, for example, because they are too widespread or come from a third-party API. The rest of the blog post explains how to teach QML tooling about context properties to avoid all those "unqualified access"-warnings when using context properties.

        Configurable context properties warnings

        qmllint adds basic support for context properties in Qt 6.11. Prior to 6.11, qmllint treated unqualified accesses and context property accesses identically. This meant that warnings about the use of context properties couldn't be silenced without losing actual relevant unqualified access warnings.
        To separate actual unqualified accesses from context property accesses, we added a new configuration file that allows you to declare the context properties that exist in your code. To use the new context property configuration file, create a .contextProperties.ini file with the following content inside your project source folder.
        [General] disableUnqualifiedAccess = "myContextProperty1,myContextProperty2" warnOnUsage = "myContextProperty3,myContextProperty4,myContextProperty5" disableHeuristic = false
        We will explain each setting key in this example in the next sections. Here is how the warning looks without any .contextProperties.ini file.
        "Unqualified access"-warning on myProperty usages

        Disable unqualified access

        If you have decided that a context property can't or won't be replaced with a better alternative, and if you want to silence all unqualified access warnings on that context property, then disableUnqualifiedAccess was made for you. That setting key should contain all the context property names where unqualified access warnings should be silenced. Use "," to separate multiple context property names.
        qmllint silences all unqualified access warnings on those property names, allowing you to focus on the other relevant unqualified access warnings.
        In our example, adding our context property name to disableUnqualifiedAccess silences the warning:
        Disabling the unqualified access warning

        Warn on usage

        You might have (rightfully!) decided that you still want to get rid of your context property usages, so silencing the warning via disableUnqualifiedAccess and forgetting about the context properties might not be feasible for you. In that case, you might want unqualified accesses to emit unqualified access warnings and context property accesses to emit context property-related warnings. To do so, add the context property name to the warnOnUsage key. Use "," to separate multiple context property names.
        qmllint will emit a different warning with a different warning category for unqualified accesses on properties in the warnOnUsage-list. This allows you to unclutter the unqualified warning category.
        In our example, adding our context property name to warnOnUsage makes qmllint emit a different warning:
        Enabling the context property warning
        You might ask yourself now, "This is all good, but do I really have to type all of my context property names inside this configuration file? What if I can't remember how I named my context properties ages ago?" Fortunately, there is a heuristic that can help you find your context properties.

        Find context property definitions

        The CMake scripts in 6.11 include a heuristic search for context property definitions in C++ code. It greps your source folder for setContextProperty() calls and saves the result into your build folder. This way, qmllint picks up the context property definitions at runtime and can warn when accessing them.
        Grepping the source folder with the heuristic takes some time on bigger projects and is therefore disabled by default. To run the heuristic manually, call the dump_qml_context_properties CMake target. The results of the heuristic search are saved in the build folder and read by qmllint during linting.
        To run the heuristic search automatically during the CMake linting targets, like all_qmllint, for example, set the QT_QMLLINT_CONTEXT_PROPERTY_DUMP CMake variable to ON before calling the linting target.
        After running the dump_qml_context_properties target via the editor's CMake extension, for example, by typing cm dump_qml_context_properties in Qt Creator's locator and hitting enter, we get the following warnings on our context property usage:
        Linting warnings on our context property usage
        The unqualified warning is no longer the only one: a new warning has been added about a potential context property access being detected. It also contains the location of the "definition" for the context property that can be seen when looking at the entire warning message:
        Zooming in on the linting warnings on our context property usage
        The location of the "definition" we can use to check whether myProperty is really a context property or a false positive. If it really is a context property, we can add it to warnOnUsage in the .contextProperties.ini to remove the unqualified access warning. The entire list of context property names found by the heuristic is in the build folder at <build>/.qt/.contextPropertyDump.ini.

        Disable the heuristic

        To disable warnings about context property names found by the heuristic, set the disableHeuristic key in the configuration file to true, or delete the .contextPropertyDump.ini file from the build folder.

        Summary

        We started with a recap on what context properties are and went through the new context property support in QML tooling. This was the last part of this series. We hope that you enjoyed it. Remember to open a bug report in JIRA if anything is not working as expected or is insufficiently documented.

        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved