diff options
author | Eike Ziller <eike.ziller@qt.io> | 2023-06-27 15:20:18 +0200 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2023-06-27 15:20:18 +0200 |
commit | 3e65778d6632027a932e78a771ec877f72042cff (patch) | |
tree | 8ad63a32967e477e482c4199c2ddefb70cba7af4 | |
parent | a8cab6f5a19f1355e9de1d95354cb25baf62515d (diff) | |
parent | 372e2ba6155a37c94d534d9176bb4c9a3b8024fe (diff) |
Merge remote-tracking branch 'origin/11.0'
Change-Id: I8be5a00000a6699346ed1c44c0711d1f017462a7
20 files changed, 532 insertions, 92 deletions
diff --git a/doc/qtcreator/config/qtcreator-project.qdocconf b/doc/qtcreator/config/qtcreator-project.qdocconf index 6d0690a134..ec98529c14 100644 --- a/doc/qtcreator/config/qtcreator-project.qdocconf +++ b/doc/qtcreator/config/qtcreator-project.qdocconf @@ -70,4 +70,9 @@ macro.see = "\\sa" macro.function = "\\fn" navigation.landingpage = "$IDE_DISPLAY_NAME Manual" + +# Auto-generate navigation linking based on "All Topics": +navigation.toctitles = "All Topics" +navigation.toctitles.inclusive = false + buildversion = "$IDE_DISPLAY_NAME Manual $QTC_VERSION" diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index 2a41f472d7..f1e72a7dc2 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -2003,10 +2003,20 @@ bool Check::visit(TypeOfExpression *ast) /// ### Maybe put this into the context as a helper function. const Value *Check::checkScopeObjectMember(const UiQualifiedId *id) { - if (!_importsOk) return nullptr; + if (!id) + return nullptr; // ### error? + + if (id->name.isEmpty()) // possible after error recovery + return nullptr; + + QString propertyName = id->name.toString(); + + if (propertyName == "id" && !id->next) + return nullptr; // ### should probably be a special value + QList<const ObjectValue *> scopeObjects = _scopeChain.qmlScopeObjects(); if (scopeObjects.isEmpty()) return nullptr; @@ -2021,24 +2031,9 @@ const Value *Check::checkScopeObjectMember(const UiQualifiedId *id) return isAttachedProperty; }; - - if (! id) - return nullptr; // ### error? - - if (id->name.isEmpty()) // possible after error recovery - return nullptr; - - QString propertyName = id->name.toString(); - - if (propertyName == "id" && !id->next) - return nullptr; // ### should probably be a special value - // attached properties bool isAttachedProperty = getAttachedTypes(propertyName); - if (scopeObjects.isEmpty()) - return nullptr; - // global lookup for first part of id const Value *value = nullptr; for (int i = scopeObjects.size() - 1; i >= 0; --i) { @@ -2053,7 +2048,14 @@ const Value *Check::checkScopeObjectMember(const UiQualifiedId *id) return nullptr; if (!value) { - addMessage(ErrInvalidPropertyName, id->identifierToken, propertyName); + // We omit M16 messages if the type using ImmediateProperties + // Ideally, we should obtain them through metaobject information + const bool omitMessage = !m_typeStack.isEmpty() + && ((m_typeStack.last() == "PropertyChanges") + || m_typeStack.last() == "Binding") + && !m_idStack.isEmpty() && m_idStack.last().contains(propertyName); + if (!omitMessage) + addMessage(ErrInvalidPropertyName, id->identifierToken, propertyName); return nullptr; } diff --git a/src/libs/solutions/tasking/barrier.h b/src/libs/solutions/tasking/barrier.h index 705ddd5f5b..64a59ec873 100644 --- a/src/libs/solutions/tasking/barrier.h +++ b/src/libs/solutions/tasking/barrier.h @@ -82,7 +82,7 @@ public: "is not reachable in the running tree. " "It is possible that no barrier was added to the tree, " "or the storage is not reachable from where it is referenced. " - "The WaitForBarrier task will finish with error. "); + "The WaitForBarrier task finishes with an error. "); return SetupResult::StopWithError; } Barrier *activeSharedBarrier = activeBarrier->barrier(); diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index b9417a6e46..ff43b3a612 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -139,6 +139,369 @@ private: */ /*! + \class Tasking::GroupItem + \inheaderfile solutions/tasking/tasktree.h + \inmodule TaskingSolution + \brief GroupItem represents the basic element that may be a part of any + \l {Tasking::Group} {Group}. + + GroupItem is a basic element that may be a part of any \l {Tasking::Group} {Group}. + It encapsulates the functionality provided by any GroupItem's subclass. + It is a value type and it is safe to copy the GroupItem instance, + even when it is originally created via the subclass' constructor. + + There are four main kinds of GroupItem: + \table + \header + \li GroupItem Kind + \li Brief Description + \row + \li \l CustomTask + \li Defines asynchronous task type and task's start, done, and error handlers. + Aliased with a unique task name, such as, \c ConcurrentCallTask<ResultType> + or \l NetworkQueryTask. Asynchronous tasks are the main reason for using a task tree. + \row + \li \l Group + \li A container for other group items. Since the group is of the GroupItem type, + it's possible to nest it inside another group. The group is seen by its parent + as a single asynchronous task. + \row + \li \l Storage + \li Enables the child tasks of a group to exchange data. + When Storage is placed inside a group, the task tree instantiates + the storage object just before the group is entered, + and destroys it just after the group is finished. + \row + \li Other group control items + \li The items returned by \l {Tasking::parallelLimit()} {parallelLimit()} or + \l {Tasking::workflowPolicy()} {workflowPolicy()} influence the group's behavior. + The items returned by \l {Tasking::onGroupSetup()} {onGroupSetup()}, + \l {Tasking::onGroupDone()} {onGroupDone()} or + \l {Tasking::onGroupError()} {onGroupError()} define custom handlers called when + the group starts or ends execution. + \endtable +*/ + +/*! + \class Tasking::Group + \inheaderfile solutions/tasking/tasktree.h + \inmodule TaskingSolution + \brief Group represents the basic element for composing declarative recipes describing + how to execute and handle a nested tree of asynchronous tasks. + + Group is a container for other group items. It encloses child tasks into one unit, + which is seen by the group's parent as a single, asynchronous task. + Since Group is of the GroupItem type, it may also be a child of Group. + + Insert child tasks into the group by using aliased custom task names, such as, + \c ConcurrentCallTask<ResultType> or \c NetworkQueryTask: + + \code + const Group group { + NetworkQueryTask(...), + ConcurrentCallTask<int>(...) + }; + \endcode + + The group's behavior may be customized by inserting the items returned by + \l {Tasking::parallelLimit()} {parallelLimit()} or + \l {Tasking::workflowPolicy()} {workflowPolicy()} functions: + + \code + const Group group { + parallel, + continueOnError, + NetworkQueryTask(...), + NetworkQueryTask(...) + }; + \endcode + + The group may contain nested groups: + + \code + const Group group { + finishAllAndDone, + NetworkQueryTask(...), + Group { + NetworkQueryTask(...), + Group { + parallel, + NetworkQueryTask(...), + NetworkQueryTask(...), + } + ConcurrentCallTask<QString>(...) + } + }; + \endcode + + The group may dynamically instantiate a custom storage structure, which may be used for + inter-task data exchange: + + \code + struct MyCustomStruct { QByteArray data; }; + + TreeStorage<MyCustomStruct> storage; + + const auto onFirstSetup = [](NetworkQuery &task) { ... }; + const auto onFirstDone = [storage](const NetworkQuery &task) { + // storage-> gives a pointer to MyCustomStruct instance, + // created dynamically by the running task tree. + storage->data = task.reply()->readAll(); + }; + const auto onSecondSetup = [storage](ConcurrentCall<QImage> &task) { + // storage-> gives a pointer to MyCustomStruct. Since the group is sequential, + // the stored MyCustomStruct was already updated inside the onFirstDone handler. + const QByteArray storedData = storage->data; + }; + + const Group group { + // When the group is entered by a running task tree, it creates MyCustomStruct + // instance dynamically. It is later accessible from all handlers via + // the *storage or storage-> operators. + sequential, + Storage(storage), + NetworkQueryTask(onFirstSetup, onFirstDone), + ConcurrentCallTask<QImage>(onSecondSetup) + }; + \endcode +*/ + +/*! + \fn Group::Group(const QList<GroupItem> &children) + + Constructs a group with a given list of \a children. + + This constructor is useful when the child items of the group are not known at compile time, + but later, at runtime: + + \code + const QStringList sourceList = ...; + + QList<GroupItem> groupItems { parallel }; + + for (const QString &source : sourceList) { + const NetworkQueryTask task(...); // use source for setup handler + groupItems << task; + } + + const Group group(groupItems); + \endcode +*/ + +/*! + \fn Group::Group(std::initializer_list<GroupItem> children) + + Constructs a group from std::initializer_list given by \a children. + + This constructor is useful when all child items of the group are known at compile time: + + \code + const Group group { + finishAllAndDone, + NetworkQueryTask(...), + Group { + NetworkQueryTask(...), + Group { + parallel, + NetworkQueryTask(...), + NetworkQueryTask(...), + } + ConcurrentCallTask<QString>(...) + } + }; + \endcode +*/ + +/*! + \fn GroupItem Group::withTimeout(std::chrono::milliseconds timeout, const GroupEndHandler &handler) const + + Attaches \c TimeoutTask to a copy of \c this group, elapsing after \a timeout in milliseconds, + with an optionally provided timeout \a handler, and returns the coupled item. + + When the group finishes before \a timeout passes, + the returned item finishes immediately with the group's result. + Otherwise, the \a handler is invoked (if provided), the group is stopped, + and the returned item finishes with an error. +*/ + +/*! + \class Tasking::CustomTask + \inheaderfile solutions/tasking/tasktree.h + \inmodule TaskingSolution + \brief A class template used for declaring task items and defining their setup, + done, and error handlers. + + The CustomTask class template is used inside TaskTree for describing custom task items. + + Custom task names are aliased with unique names inside the \l Tasking namespace + via the TASKING_DECLARE_TASK or TASKING_DECLARE_TEMPLATE_TASK macros. + For example, \c ConcurrentCallTask<T> is an alias to the CustomTask that is defined + to work with \c ConcurrentCall<T> as an associated task class. + The following table contains all the built-in tasks and their associated task classes: + + \table + \header + \li Aliased Task Name (Tasking Namespace) + \li Associated Task Class + \li Brief Description + \row + \li ConcurrentCallTask<ReturnType> + \li ConcurrentCall<ReturnType> + \li Starts an asynchronous task. Runs in a separate thread. + \row + \li NetworkQueryTask + \li NetworkQuery + \li Sends a network query. + \row + \li TaskTreeTask + \li TaskTree + \li Starts a nested task tree. + \row + \li TimeoutTask + \li \c std::chrono::milliseconds + \li Starts a timer. + \row + \li WaitForBarrierTask + \li MultiBarrier<Limit> + \li Starts an asynchronous task waiting for the barrier to pass. + \endtable +*/ + +/*! + \typealias CustomTask::Task + + Type alias for \c Adapter::Type. + + This is the associated task's type. +*/ + +/*! + \typealias CustomTask::EndHandler + + Type alias for \c std::function<void(const Task &)>. +*/ + +/*! + \fn template <typename Adapter> template <typename SetupHandler> CustomTask<Adapter>::CustomTask<Adapter>(SetupHandler &&setup, const EndHandler &done, const EndHandler &error) + + Constructs the CustomTask instance and attaches the \a setup, \a done, and \a error + handlers to the task. When the running task tree is about to start the task, + it instantiates the associated \l Task object, invokes \a setup handler with a \e reference + to the created task, and starts it. When the running task finishes with success or an error, + the task tree invokes \a done or \a error handler, respectively, + with a \e {const reference} to the created task. + + The passed \a setup handler is either of the \c std::function<SetupResult(Task &)> or + \c std::function<void(Task &)> type. For example: + + \code + static void parseAndLog(const QString &input); + + ... + + const QString input = ...; + + const auto onFirstSetup = [input](ConcurrentCall<void> &task) { + if (input == "Skip") + return SetupResult::StopWithDone; // This task won't start, the next one will + if (input == "Error") + return SetupResult::StopWithError; // This task and the next one won't start + task.setConcurrentCallData(parseAndLog, input); + // This task will start, and the next one will start after this one finished with success + return SetupResult::Continue; + }; + + const auto onSecondSetup = [input](ConcurrentCall<void> &task) { + task.setConcurrentCallData(parseAndLog, input); + }; + + const Group group { + ConcurrentCallTask<void>(onFirstSetup), + ConcurrentCallTask<void>(onSecondSetup) + }; + \endcode + + When the passed \a setup handler is of the \c std::function<SetupResult(Task &)> type, + the return value of the handler instructs the running tree on how to proceed after + the handler's invocation is finished. The default return value of SetupResult::Continue + instructs the tree to continue running, i.e. to execute the associated \c Task. + The return value of SetupResult::StopWithDone or SetupResult::StopWithError instructs + the tree to skip the task's execution and finish immediately with success or an error, + respectively. + When the return type is either SetupResult::StopWithDone or SetupResult::StopWithError, + the task's \a done or \a error handler (even if provided) are not called afterwards. + + The \a setup handler may be of a shortened form of std::function<void(Task &)>, + i.e. the return value is void. In this case it's assumed that the return value is + SetupResult::Continue by default. + + When the running task finishes, one of \a done or \a error handlers is called, + depending on whether it finished with success or an error, respectively. + Both handlers are of std::function<void(const Task &)> type. + + \sa onSetup(), onDone(), onError() +*/ + +/*! + \fn template <typename Adapter> template <typename SetupHandler> CustomTask<Adapter> &CustomTask<Adapter>::onSetup(SetupHandler &&handler) + + Attaches the setup \a handler to \c this task. + The \a handler is invoked when the task is about to be started. + + This function enables defining the task's details with a + \l {https://en.wikipedia.org/wiki/Fluent_interface}{fluent interface} style: + + \code + const auto onQuerySetup = [](NetworkQuery &task) { ... }; + const auto onQueryError = [](const NetworkQuery &task) { ... }; + + const Group group { + NetworkQueryTask(onQuerySetup, {}, onQueryError), + NetworkQueryTask().onSetup(onQuerySetup).onError(onQueryError), // fluent interface style + NetworkQueryTask(onQuerySetup, {}, onQueryError).withTimeout(500ms) + } + \endcode + + \sa CustomTask(), onDone(), onError() +*/ + +/*! + \fn template <typename Adapter> CustomTask<Adapter> &CustomTask<Adapter>::onDone(const EndHandler &handler) + + Attaches the done \a handler to \c this task. + The handler is invoked when the task finishes with success. + + This function enables defining the task's details with a fluent interface style. + + \sa CustomTask(), onSetup(), onError() +*/ + +/*! + \fn template <typename Adapter> CustomTask<Adapter> &CustomTask<Adapter>::onError(const EndHandler &handler) + + Attaches the error \a handler to \c this task. + The handler is invoked when the task finishes with an error. + + This function enables defining the task's details with a fluent interface style. + + \sa CustomTask(), onSetup(), onDone() +*/ + +/*! + \fn template <typename Adapter> GroupItem CustomTask<Adapter>::withTimeout(std::chrono::milliseconds timeout, const GroupItem::GroupEndHandler &handler) const + + Attaches \c TimeoutTask to a copy of \c this task, elapsing after \a timeout in milliseconds, + with an optionally provided timeout \a handler, and returns the coupled item. + + When the task finishes before \a timeout passes, + the returned item finishes immediately with the task's result. + Otherwise, the \a handler is invoked (if provided), the task is stopped, + and the returned item finishes with an error. + + \sa onSetup() +*/ + +/*! \macro TASKING_DECLARE_TASK(CustomTaskName, TaskAdapterClass) \relates Tasking @@ -159,13 +522,6 @@ private: */ /*! - \class Tasking::GroupItem - \inheaderfile solutions/tasking/tasktree.h - \inmodule TaskingSolution - \brief The GroupItem class represents the basic element for composing nested tree structures. -*/ - -/*! \enum Tasking::WorkflowPolicy This enum describes the possible behavior of the Group element when any group's child task diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 47ad221728..88f89ef0c5 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -321,14 +321,14 @@ public: using EndHandler = std::function<void(const Task &)>; static Adapter *createAdapter() { return new Adapter; } CustomTask() : GroupItem({&createAdapter}) {} - template <typename SetupFunction> - CustomTask(SetupFunction &&function, const EndHandler &done = {}, const EndHandler &error = {}) - : GroupItem({&createAdapter, wrapSetup(std::forward<SetupFunction>(function)), + template <typename SetupHandler> + CustomTask(SetupHandler &&setup, const EndHandler &done = {}, const EndHandler &error = {}) + : GroupItem({&createAdapter, wrapSetup(std::forward<SetupHandler>(setup)), wrapEnd(done), wrapEnd(error)}) {} - template <typename SetupFunction> - CustomTask &onSetup(SetupFunction &&function) { - setTaskSetupHandler(wrapSetup(std::forward<SetupFunction>(function))); + template <typename SetupHandler> + CustomTask &onSetup(SetupHandler &&handler) { + setTaskSetupHandler(wrapSetup(std::forward<SetupHandler>(handler))); return *this; } CustomTask &onDone(const EndHandler &handler) { @@ -346,20 +346,20 @@ public: } private: - template<typename SetupFunction> - static GroupItem::TaskSetupHandler wrapSetup(SetupFunction &&function) { + template<typename SetupHandler> + static GroupItem::TaskSetupHandler wrapSetup(SetupHandler &&handler) { static constexpr bool isDynamic = std::is_same_v<SetupResult, - std::invoke_result_t<std::decay_t<SetupFunction>, typename Adapter::Type &>>; + std::invoke_result_t<std::decay_t<SetupHandler>, typename Adapter::Type &>>; constexpr bool isVoid = std::is_same_v<void, - std::invoke_result_t<std::decay_t<SetupFunction>, typename Adapter::Type &>>; + std::invoke_result_t<std::decay_t<SetupHandler>, typename Adapter::Type &>>; static_assert(isDynamic || isVoid, "Task setup handler needs to take (Task &) as an argument and has to return " "void or SetupResult. The passed handler doesn't fulfill these requirements."); return [=](TaskInterface &taskInterface) { Adapter &adapter = static_cast<Adapter &>(taskInterface); if constexpr (isDynamic) - return std::invoke(function, *adapter.task()); - std::invoke(function, *adapter.task()); + return std::invoke(handler, *adapter.task()); + std::invoke(handler, *adapter.task()); return SetupResult::Continue; }; }; diff --git a/src/plugins/autotest/boost/boosttestsettings.cpp b/src/plugins/autotest/boost/boosttestsettings.cpp index ed0bad6bca..4cf9225173 100644 --- a/src/plugins/autotest/boost/boosttestsettings.cpp +++ b/src/plugins/autotest/boost/boosttestsettings.cpp @@ -66,22 +66,22 @@ BoostTestSettings::BoostTestSettings(Id settingsId) seed.setEnabler(&randomize); randomize.setSettingsKey("Randomize"); - randomize.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); + randomize.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); randomize.setLabelText(Tr::tr("Randomize")); randomize.setToolTip(Tr::tr("Randomize execution order.")); systemErrors.setSettingsKey("SystemErrors"); - systemErrors.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); + systemErrors.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); systemErrors.setLabelText(Tr::tr("Catch system errors")); systemErrors.setToolTip(Tr::tr("Catch or ignore system errors.")); fpExceptions.setSettingsKey("FPExceptions"); - fpExceptions.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); + fpExceptions.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); fpExceptions.setLabelText(Tr::tr("Floating point exceptions")); fpExceptions.setToolTip(Tr::tr("Enable floating point exception traps.")); memLeaks.setSettingsKey("MemoryLeaks"); - memLeaks.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); + memLeaks.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); memLeaks.setDefaultValue(true); memLeaks.setLabelText(Tr::tr("Detect memory leaks")); memLeaks.setToolTip(Tr::tr("Enable memory leak detection.")); diff --git a/src/plugins/autotest/ctest/ctestsettings.cpp b/src/plugins/autotest/ctest/ctestsettings.cpp index a2f3e90427..70016f7920 100644 --- a/src/plugins/autotest/ctest/ctestsettings.cpp +++ b/src/plugins/autotest/ctest/ctestsettings.cpp @@ -44,6 +44,7 @@ CTestSettings::CTestSettings(Id settingsId) outputOnFail.setSettingsKey("OutputOnFail"); outputOnFail.setLabelText(Tr::tr("Output on failure")); + outputOnFail.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); outputOnFail.setDefaultValue(true); outputMode.setSettingsKey("OutputMode"); @@ -70,9 +71,11 @@ CTestSettings::CTestSettings(Id settingsId) scheduleRandom.setSettingsKey("ScheduleRandom"); scheduleRandom.setLabelText(Tr::tr("Schedule random")); + scheduleRandom.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); stopOnFailure.setSettingsKey("StopOnFail"); stopOnFailure.setLabelText(Tr::tr("Stop on failure")); + stopOnFailure.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); parallel.setSettingsKey("Parallel"); parallel.setToolTip(Tr::tr("Run tests in parallel mode using given number of jobs.")); diff --git a/src/plugins/autotest/gtest/gtestsettings.cpp b/src/plugins/autotest/gtest/gtestsettings.cpp index ca31c99f12..7fa1e53479 100644 --- a/src/plugins/autotest/gtest/gtestsettings.cpp +++ b/src/plugins/autotest/gtest/gtestsettings.cpp @@ -26,6 +26,7 @@ GTestSettings::GTestSettings(Id settingsId) setLayouter([this] { return Row { Form { runDisabled, br, + throwOnFailure, br, breakOnFailure, br, repeat, iterations, br, shuffle, seed, br, @@ -49,24 +50,29 @@ GTestSettings::GTestSettings(Id settingsId) runDisabled.setSettingsKey("RunDisabled"); runDisabled.setLabelText(Tr::tr("Run disabled tests")); + runDisabled.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); runDisabled.setToolTip(Tr::tr("Executes disabled tests when performing a test run.")); shuffle.setSettingsKey("Shuffle"); shuffle.setLabelText(Tr::tr("Shuffle tests")); + shuffle.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); shuffle.setToolTip(Tr::tr("Shuffles tests automatically on every iteration by the given seed.")); repeat.setSettingsKey("Repeat"); repeat.setLabelText(Tr::tr("Repeat tests")); + repeat.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); repeat.setToolTip(Tr::tr("Repeats a test run (you might be required to increase the timeout to " "avoid canceling the tests).")); throwOnFailure.setSettingsKey("ThrowOnFailure"); throwOnFailure.setLabelText(Tr::tr("Throw on failure")); + throwOnFailure.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); throwOnFailure.setToolTip(Tr::tr("Turns assertion failures into C++ exceptions.")); breakOnFailure.setSettingsKey("BreakOnFailure"); breakOnFailure.setDefaultValue(true); breakOnFailure.setLabelText(Tr::tr("Break on failure while debugging")); + breakOnFailure.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); breakOnFailure.setToolTip(Tr::tr("Turns failures into debugger breakpoints.")); groupMode.setSettingsKey("GroupMode"); diff --git a/src/plugins/autotest/testresultmodel.cpp b/src/plugins/autotest/testresultmodel.cpp index f03cd8c685..fcb02ec595 100644 --- a/src/plugins/autotest/testresultmodel.cpp +++ b/src/plugins/autotest/testresultmodel.cpp @@ -296,9 +296,8 @@ void TestResultModel::addTestResult(const TestResult &testResult, bool autoExpan if (parentItem) { parentItem->appendChild(newItem); if (autoExpand) { - parentItem->expand(); - newItem->expand(); - newItem->forAllChildren([](TreeItem *it) { it->expand(); }); + QMetaObject::invokeMethod(this, [parentItem]{ parentItem->expand(); }, + Qt::QueuedConnection); } updateParent(newItem); } else { diff --git a/src/plugins/autotest/testresultspane.cpp b/src/plugins/autotest/testresultspane.cpp index 3dbad31ea9..457b273a4a 100644 --- a/src/plugins/autotest/testresultspane.cpp +++ b/src/plugins/autotest/testresultspane.cpp @@ -142,7 +142,7 @@ TestResultsPane::TestResultsPane(QObject *parent) : onCopyItemTriggered(getTestResult(m_treeView->currentIndex())); }); connect(m_model, &TestResultModel::requestExpansion, this, [this](const QModelIndex &idx) { - m_treeView->expand(m_filterModel->mapFromSource(idx)); + m_treeView->expandRecursively(m_filterModel->mapFromSource(idx)); }); connect(TestRunner::instance(), &TestRunner::testRunStarted, this, &TestResultsPane::onTestRunStarted); diff --git a/src/plugins/clangformat/clangformatfile.cpp b/src/plugins/clangformat/clangformatfile.cpp index 16209c3094..66eb58d6ea 100644 --- a/src/plugins/clangformat/clangformatfile.cpp +++ b/src/plugins/clangformat/clangformatfile.cpp @@ -152,14 +152,17 @@ CppEditor::CppCodeStyleSettings ClangFormatFile::toCppCodeStyleSettings( // to be false settings.indentAccessSpecifiers = (style.AccessModifierOffset != -1 * int(style.IndentWidth)); - settings.indentNamespaceBody = style.NamespaceIndentation - == FormatStyle::NamespaceIndentationKind::NI_All; - settings.indentNamespaceBraces = settings.indentNamespaceBody; - - settings.indentClassBraces = style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths; - settings.indentEnumBraces = settings.indentClassBraces; - settings.indentBlockBraces = settings.indentClassBraces; - settings.indentFunctionBraces = settings.indentClassBraces; + if (style.NamespaceIndentation == FormatStyle::NamespaceIndentationKind::NI_All) { + settings.indentNamespaceBody = true; + settings.indentNamespaceBraces = settings.indentNamespaceBody; + } + + if (style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) { + settings.indentClassBraces = true; + settings.indentEnumBraces = settings.indentClassBraces; + settings.indentBlockBraces = settings.indentClassBraces; + settings.indentFunctionBraces = settings.indentClassBraces; + } settings.indentSwitchLabels = style.IndentCaseLabels; #if LLVM_VERSION_MAJOR >= 11 diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index 949911fe5e..7b9a896fc1 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -207,13 +207,13 @@ void fromCppCodeStyleSettings(clang::format::FormatStyle &style, else style.AccessModifierOffset = -1 * style.IndentWidth; - if (settings.indentNamespaceBody || settings.indentNamespaceBraces) + if (settings.indentNamespaceBody && settings.indentNamespaceBraces) style.NamespaceIndentation = FormatStyle::NamespaceIndentationKind::NI_All; else style.NamespaceIndentation = FormatStyle::NamespaceIndentationKind::NI_None; - if (settings.indentClassBraces || settings.indentEnumBraces || settings.indentBlockBraces - || settings.indentFunctionBraces) + if (settings.indentClassBraces && settings.indentEnumBraces && settings.indentBlockBraces + && settings.indentFunctionBraces) style.BreakBeforeBraces = FormatStyle::BS_Whitesmiths; else style.BreakBeforeBraces = FormatStyle::BS_Custom; diff --git a/src/plugins/clangtools/readexporteddiagnosticstest.cpp b/src/plugins/clangtools/readexporteddiagnosticstest.cpp index d839108451..f6bf5e1118 100644 --- a/src/plugins/clangtools/readexporteddiagnosticstest.cpp +++ b/src/plugins/clangtools/readexporteddiagnosticstest.cpp @@ -64,9 +64,8 @@ static QString appendYamlSuffix(const char *filePathFragment) void ReadExportedDiagnosticsTest::testTidy() { const FilePath sourceFile = filePath("tidy.modernize-use-nullptr.cpp"); - const FilePath exportedFile = createFile( - filePath(appendYamlSuffix("tidy.modernize-use-nullptr")).toString(), - sourceFile.toString()); + const FilePath exportedFile + = createFile(filePath(appendYamlSuffix("tidy.modernize-use-nullptr")), sourceFile); Diagnostic expectedDiag; expectedDiag.name = "modernize-use-nullptr"; expectedDiag.location = {sourceFile, 2, 25}; @@ -86,9 +85,9 @@ void ReadExportedDiagnosticsTest::testTidy() void ReadExportedDiagnosticsTest::testAcceptDiagsFromFilePaths_None() { - const QString sourceFile = filePath("tidy.modernize-use-nullptr.cpp").toString(); - const FilePath exportedFile = createFile(filePath("tidy.modernize-use-nullptr.yaml").toString(), - sourceFile); + const FilePath sourceFile = filePath("tidy.modernize-use-nullptr.cpp"); + const FilePath exportedFile = createFile(filePath("tidy.modernize-use-nullptr.yaml"), + sourceFile); const auto acceptNone = [](const FilePath &) { return false; }; const expected_str<Diagnostics> diags = readExportedDiagnostics(exportedFile, acceptNone); @@ -101,8 +100,7 @@ void ReadExportedDiagnosticsTest::testTidy_ClangAnalyzer() { const FilePath sourceFile = filePath("clang-analyzer.dividezero.cpp"); const FilePath exportedFile - = createFile(filePath(appendYamlSuffix("clang-analyzer.dividezero")).toString(), - sourceFile.toString()); + = createFile(filePath(appendYamlSuffix("clang-analyzer.dividezero")), sourceFile); Diagnostic expectedDiag; expectedDiag.name = "clang-analyzer-core.DivideZero"; expectedDiag.location = {sourceFile, 4, 15}; @@ -134,8 +132,8 @@ void ReadExportedDiagnosticsTest::testTidy_ClangAnalyzer() void ReadExportedDiagnosticsTest::testClazy() { const FilePath sourceFile = filePath("clazy.qgetenv.cpp"); - const FilePath exportedFile = createFile(filePath(appendYamlSuffix("clazy.qgetenv")).toString(), - sourceFile.toString()); + const FilePath exportedFile = createFile(filePath(appendYamlSuffix("clazy.qgetenv")), + sourceFile); Diagnostic expectedDiag; expectedDiag.name = "clazy-qgetenv"; expectedDiag.location = {sourceFile, 7, 5}; @@ -259,17 +257,16 @@ void ReadExportedDiagnosticsTest::testOffsetMultiByteCodePoint2() } // Replace FILE_PATH with a real absolute file path in the *.yaml files. -FilePath ReadExportedDiagnosticsTest::createFile(const QString &yamlFilePath, - const QString &filePathToInject) const +FilePath ReadExportedDiagnosticsTest::createFile(const Utils::FilePath &yamlFilePath, + const Utils::FilePath &filePathToInject) const { - QTC_ASSERT(QDir::isAbsolutePath(filePathToInject), return {}); - const FilePath newFileName = m_baseDir->absolutePath(QFileInfo(yamlFilePath).fileName()); + QTC_ASSERT(filePathToInject.isAbsolutePath(), return {}); + const FilePath newFileName = m_baseDir->filePath().resolvePath(yamlFilePath); FileReader reader; - if (QTC_GUARD(reader.fetch(FilePath::fromString(yamlFilePath), - QIODevice::ReadOnly | QIODevice::Text))) { + if (QTC_GUARD(reader.fetch(yamlFilePath, QIODevice::ReadOnly | QIODevice::Text))) { QByteArray contents = reader.data(); - contents.replace("FILE_PATH", filePathToInject.toLocal8Bit()); + contents.replace("FILE_PATH", filePathToInject.toString().toLocal8Bit()); FileSaver fileSaver(newFileName, QIODevice::WriteOnly | QIODevice::Text); QTC_CHECK(fileSaver.write(contents)); diff --git a/src/plugins/clangtools/readexporteddiagnosticstest.h b/src/plugins/clangtools/readexporteddiagnosticstest.h index 54bde6b75c..0cf9ef3737 100644 --- a/src/plugins/clangtools/readexporteddiagnosticstest.h +++ b/src/plugins/clangtools/readexporteddiagnosticstest.h @@ -44,7 +44,8 @@ private slots: void testOffsetMultiByteCodePoint2(); private: - Utils::FilePath createFile(const QString &yamlFilePath, const QString &filePathToInject) const; + Utils::FilePath createFile(const Utils::FilePath &yamlFilePath, + const Utils::FilePath &filePathToInject) const; Utils::FilePath filePath(const QString &fileName) const; CppEditor::Tests::TemporaryCopiedDir * const m_baseDir; diff --git a/src/plugins/projectexplorer/projectwizardpage.cpp b/src/plugins/projectexplorer/projectwizardpage.cpp index 83fd4d2cba..75f573430d 100644 --- a/src/plugins/projectexplorer/projectwizardpage.cpp +++ b/src/plugins/projectexplorer/projectwizardpage.cpp @@ -298,10 +298,6 @@ ProjectWizardPage::ProjectWizardPage(QWidget *parent) scrollArea, }.attachTo(this); - connect(m_projectComboBox, &QComboBox::currentIndexChanged, - this, &ProjectWizardPage::projectChanged); - connect(m_addToVersionControlComboBox, &QComboBox::currentIndexChanged, - this, &ProjectWizardPage::versionControlChanged); connect(m_vcsManageButton, &QAbstractButton::clicked, this, &ProjectWizardPage::manageVcs); setProperty(SHORT_TITLE_PROPERTY, Tr::tr("Summary")); @@ -376,6 +372,7 @@ void ProjectWizardPage::initializeVersionControls() // 2) Directory is managed and VCS does not support "Add" -> None available // 3) Directory is not managed -> Offer all VCS that support "CreateRepository" + m_addToVersionControlComboBox->disconnect(); QList<IVersionControl *> versionControls = VcsManager::versionControls(); if (versionControls.isEmpty()) hideVersionControlUiElements(); @@ -419,6 +416,9 @@ void ProjectWizardPage::initializeVersionControls() int newIdx = m_activeVersionControls.indexOf(currentSelection) + 1; setVersionControlIndex(newIdx); } + + connect(m_addToVersionControlComboBox, &QComboBox::currentIndexChanged, + this, &ProjectWizardPage::versionControlChanged); } bool ProjectWizardPage::runVersionControl(const QList<GeneratedFile> &files, QString *errorMessage) @@ -457,6 +457,7 @@ void ProjectWizardPage::initializeProjectTree(Node *context, const FilePaths &pa IWizardFactory::WizardKind kind, ProjectAction action) { + m_projectComboBox->disconnect(); BestNodeSelector selector(m_commonDirectory, paths); TreeItem *root = m_model.rootItem(); @@ -489,6 +490,8 @@ void ProjectWizardPage::initializeProjectTree(Node *context, const FilePaths &pa setAddingSubProject(action == AddSubProject); m_projectComboBox->setEnabled(m_model.rowCount(QModelIndex()) > 1); + connect(m_projectComboBox, &QComboBox::currentIndexChanged, + this, &ProjectWizardPage::projectChanged); } void ProjectWizardPage::setNoneLabel(const QString &label) diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 5935933f64..feba07e446 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -31,7 +31,7 @@ add_qtc_library(QmlDesignerUtils STATIC ) extend_qtc_library(QmlDesignerUtils - CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR + CONDITION ENABLE_COMPILE_WARNING_AS_ERROR PROPERTIES COMPILE_WARNING_AS_ERROR ON ) @@ -84,7 +84,7 @@ endif() extend_qtc_library(QmlDesignerCore - CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR + CONDITION ENABLE_COMPILE_WARNING_AS_ERROR PROPERTIES COMPILE_WARNING_AS_ERROR ON ) @@ -481,7 +481,7 @@ add_qtc_plugin(QmlDesigner ) extend_qtc_plugin(QmlDesigner - CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR + CONDITION ENABLE_COMPILE_WARNING_AS_ERROR PROPERTIES COMPILE_WARNING_AS_ERROR ON ) @@ -1088,7 +1088,7 @@ add_qtc_plugin(assetexporterplugin ) extend_qtc_plugin(assetexporterplugin - CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR + CONDITION ENABLE_COMPILE_WARNING_AS_ERROR PROPERTIES COMPILE_WARNING_AS_ERROR ON ) @@ -1121,7 +1121,7 @@ add_qtc_plugin(componentsplugin ) extend_qtc_plugin(componentsplugin - CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR + CONDITION ENABLE_COMPILE_WARNING_AS_ERROR PROPERTIES COMPILE_WARNING_AS_ERROR ON ) @@ -1141,7 +1141,7 @@ add_qtc_plugin(qmlpreviewplugin ) extend_qtc_plugin(qmlpreviewplugin - CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR + CONDITION ENABLE_COMPILE_WARNING_AS_ERROR PROPERTIES COMPILE_WARNING_AS_ERROR ON ) @@ -1163,7 +1163,7 @@ add_qtc_plugin(qtquickplugin ) extend_qtc_plugin(qtquickplugin - CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR + CONDITION ENABLE_COMPILE_WARNING_AS_ERROR PROPERTIES COMPILE_WARNING_AS_ERROR ON ) diff --git a/src/plugins/qmldesignerbase/CMakeLists.txt b/src/plugins/qmldesignerbase/CMakeLists.txt index 628403874c..a191b6d43c 100644 --- a/src/plugins/qmldesignerbase/CMakeLists.txt +++ b/src/plugins/qmldesignerbase/CMakeLists.txt @@ -1,6 +1,12 @@ -env_with_default("QDS_DISABLE_COMPILE_WARNING_AS_ERROR" ENV_QDS_DISABLE_COMPILE_WARNING_AS_ERROR OFF) -option(DISABLE_COMPILE_WARNING_AS_ERROR "Dont treat warnings as errors" ${ENV_QDS_DISABLE_COMPILE_WARNING_AS_ERROR}) -add_feature_info("Treat warnings as errors" ${DISABLE_COMPILE_WARNING_AS_ERROR} "") +if(BUILD_DESIGNSTUDIO AND ($<CONFIG:Debug> OR WITH_TESTS)) + set(ENABLE_COMPILE_WARNING_AS_ERROR_DEFAULT ON) +else() + set(ENABLE_COMPILE_WARNING_AS_ERROR_DEFAULT OFF) +endif() +env_with_default("QDS_ENABLE_COMPILE_WARNING_AS_ERROR" ENV_ENABLE_COMPILE_WARNING_AS_ERROR + ${ENABLE_COMPILE_WARNING_AS_ERROR_DEFAULT}) +option(ENABLE_COMPILE_WARNING_AS_ERROR "Treat warnings as errors in QmlDesigner" ${ENV_ENABLE_COMPILE_WARNING_AS_ERROR}) +add_feature_info("Treat warnings as errors in QmlDesigner" ${ENABLE_COMPILE_WARNING_AS_ERROR} "") add_qtc_plugin(QmlDesignerBase CONDITION TARGET Qt::QuickWidgets @@ -12,7 +18,7 @@ add_qtc_plugin(QmlDesignerBase ) extend_qtc_plugin(QmlDesignerBase - CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR + CONDITION ENABLE_COMPILE_WARNING_AS_ERROR PROPERTIES COMPILE_WARNING_AS_ERROR ON ) diff --git a/src/plugins/qmlprojectmanager/CMakeLists.txt b/src/plugins/qmlprojectmanager/CMakeLists.txt index ad71e3fbff..a1212e8bc1 100644 --- a/src/plugins/qmlprojectmanager/CMakeLists.txt +++ b/src/plugins/qmlprojectmanager/CMakeLists.txt @@ -25,7 +25,7 @@ add_qtc_plugin(QmlProjectManager ) extend_qtc_plugin(QmlProjectManager - CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR + CONDITION ENABLE_COMPILE_WARNING_AS_ERROR PROPERTIES COMPILE_WARNING_AS_ERROR ON ) diff --git a/src/plugins/qtsupport/examplesparser.cpp b/src/plugins/qtsupport/examplesparser.cpp index 84469ca2c4..d115dcf3fe 100644 --- a/src/plugins/qtsupport/examplesparser.cpp +++ b/src/plugins/qtsupport/examplesparser.cpp @@ -301,6 +301,21 @@ expected_str<QList<ExampleItem *>> parseExamples(const QByteArray &manifestData, return items; } +// ordered list of "known" categories +// TODO this should be defined in the manifest +Q_GLOBAL_STATIC_WITH_ARGS(QList<QString>, + defaultOrder, + {QStringList() << "Application Examples" + << "Desktop" + << "Mobile" + << "Embedded" + << "Graphics" + << "Input/Output" + << "Connectivity" + << "Networking" + << "Positioning & Location" + << "Internationalization"}); + static bool sortByHighlightedAndName(ExampleItem *first, ExampleItem *second) { if (first->isHighlighted && !second->isHighlighted) @@ -350,15 +365,20 @@ QList<std::pair<Core::Section, QList<ExampleItem *>>> getCategories(const QList< } else { // All original items have been copied into a category or other, delete. qDeleteAll(items); + static const int defaultOrderSize = defaultOrder->size(); int index = 0; const auto end = categoryMap.constKeyValueEnd(); for (auto it = categoryMap.constKeyValueBegin(); it != end; ++it) { - categories.append({{it->first, index, /*maxRows=*/index == 0 ? 2 : 1}, it->second}); + // order "known" categories as wanted, others come afterwards + const int defaultIndex = defaultOrder->indexOf(it->first); + const int priority = defaultIndex >= 0 ? defaultIndex : (index + defaultOrderSize); + categories.append({{it->first, priority, /*maxRows=*/index == 0 ? 2 : 1}, it->second}); ++index; } if (!other.isEmpty()) - categories.append({{otherDisplayName, index, /*maxRows=*/1}, other}); + categories.append({{otherDisplayName, index + defaultOrderSize, /*maxRows=*/1}, other}); } + const auto end = categories.end(); for (auto it = categories.begin(); it != end; ++it) sort(it->second, sortByHighlightedAndName); diff --git a/tests/auto/qml/codemodel/check/accessById.qml b/tests/auto/qml/codemodel/check/accessById.qml new file mode 100644 index 0000000000..dd91ac671e --- /dev/null +++ b/tests/auto/qml/codemodel/check/accessById.qml @@ -0,0 +1,39 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +import QtQuick +import QtQuick.Window + +Window { + id: root + width: 640 + height: 480 + visible: true + title: qsTr("Hello World") + + Rectangle { + id: rect + + Rectangle { + id: innerRect + } + } + + Text { + id: myText + width: 50 + wrapMode: Text.WordWrap + text: "a text string that is longer than 50 pixels" + + Text { + id: innerText + } + states: State { + name: "widerText" + PropertyChanges { myText.width: undefined } + AnchorChanges { innerRect.width: undefined } // 16 29 37 + } + } + + Binding {rect.width: innerText.width} +} |