diff --git a/src/libs/tracing/safecastable.h b/src/libs/tracing/safecastable.h new file mode 100644 index 00000000000..7c1fae2e7ab --- /dev/null +++ b/src/libs/tracing/safecastable.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +namespace Timeline { + +template +class SafeCastable +{ +public: + template + bool is() const + { + return static_cast(this)->classId() == Derived::staticClassId; + } + + template + Derived &asRef() + { + Q_ASSERT(is()); + return static_cast(*this); + } + + template + const Derived &asConstRef() const + { + Q_ASSERT(is()); + return static_cast(*this); + } + + template + Derived &&asRvalueRef() + { + Q_ASSERT(is()); + return static_cast(*this); + } +}; + +} // namespace Timeline diff --git a/src/libs/tracing/traceevent.h b/src/libs/tracing/traceevent.h index 780ebf7ad91..7f097315eb1 100644 --- a/src/libs/tracing/traceevent.h +++ b/src/libs/tracing/traceevent.h @@ -26,13 +26,14 @@ #pragma once #include "tracing_global.h" +#include "safecastable.h" #include #include namespace Timeline { -class TraceEvent +class TraceEvent : public SafeCastable { public: qint64 timestamp() const { return m_timestamp; } @@ -43,9 +44,11 @@ public: bool isValid() const { return m_typeIndex != -1; } + qint32 classId() const { return m_classId; } + protected: - TraceEvent(qint64 timestamp = -1, qint32 typeIndex = -1) - : m_timestamp(timestamp), m_typeIndex(typeIndex) + TraceEvent(qint32 classId, qint64 timestamp = -1, qint32 typeIndex = -1) + : m_timestamp(timestamp), m_typeIndex(typeIndex), m_classId(classId) {} TraceEvent(const TraceEvent &) = default; @@ -56,6 +59,7 @@ protected: private: qint64 m_timestamp; qint32 m_typeIndex; + qint32 m_classId; }; } // namespace Timeline diff --git a/src/libs/tracing/traceeventtype.h b/src/libs/tracing/traceeventtype.h index 58a3e180cde..9a667d6fd7a 100644 --- a/src/libs/tracing/traceeventtype.h +++ b/src/libs/tracing/traceeventtype.h @@ -26,6 +26,7 @@ #pragma once #include "tracing_global.h" +#include "safecastable.h" #include #include @@ -33,7 +34,7 @@ namespace Timeline { -class TraceEventType +class TraceEventType : public SafeCastable { public: const QString &displayName() const { return m_displayName; } @@ -42,9 +43,11 @@ public: quint8 feature() const { return m_feature; } void setFeature(quint8 feature) { m_feature = feature; } + qint32 classId() const { return m_classId; } + protected: - TraceEventType(quint8 feature = 255, const QString &displayName = QString()) - : m_displayName(displayName), m_feature(feature) + TraceEventType(qint32 classId, quint8 feature = 255, const QString &displayName = QString()) + : m_displayName(displayName), m_classId(classId), m_feature(feature) {} TraceEventType(const TraceEventType &) = default; @@ -54,6 +57,7 @@ protected: private: QString m_displayName; + qint32 m_classId; quint8 m_feature; }; diff --git a/src/libs/tracing/tracing.pro b/src/libs/tracing/tracing.pro index 1ef079a20bd..a12f03a8604 100644 --- a/src/libs/tracing/tracing.pro +++ b/src/libs/tracing/tracing.pro @@ -25,6 +25,7 @@ SOURCES += \ HEADERS += \ $$PWD/flamegraph.h \ $$PWD/flamegraphattached.h \ + $$PWD/safecastable.h \ $$PWD/tracing_global.h \ $$PWD/timelinemodel.h \ $$PWD/timelinemodel_p.h \ diff --git a/src/libs/tracing/tracing.qbs b/src/libs/tracing/tracing.qbs index d91c765db00..4705d9adc79 100644 --- a/src/libs/tracing/tracing.qbs +++ b/src/libs/tracing/tracing.qbs @@ -17,6 +17,7 @@ Project { "README", "flamegraph.cpp", "flamegraph.h", "flamegraphattached.h", + "safecastable.h", "timelineabstractrenderer.cpp", "timelineabstractrenderer.h", "timelineabstractrenderer_p.h", "timelineformattime.cpp", "timelineformattime.h", diff --git a/src/plugins/qmlprofiler/qmlevent.h b/src/plugins/qmlprofiler/qmlevent.h index 23a62cb643f..3f999d419e9 100644 --- a/src/plugins/qmlprofiler/qmlevent.h +++ b/src/plugins/qmlprofiler/qmlevent.h @@ -39,24 +39,26 @@ namespace QmlProfiler { struct QmlEvent : public Timeline::TraceEvent { - QmlEvent() : m_dataType(Inline8Bit), m_dataLength(0) {} + static const qint32 staticClassId = 0x716d6c65; // 'qmle'; + + QmlEvent() : TraceEvent(staticClassId), m_dataType(Inline8Bit), m_dataLength(0) {} template QmlEvent(qint64 timestamp, int typeIndex, std::initializer_list list) - : TraceEvent(timestamp, typeIndex) + : TraceEvent(staticClassId, timestamp, typeIndex) { assignNumbers, Number>(list); } QmlEvent(qint64 timestamp, int typeIndex, const QString &data) - : TraceEvent(timestamp, typeIndex) + : TraceEvent(staticClassId, timestamp, typeIndex) { assignNumbers(data.toUtf8()); } template QmlEvent(qint64 timestamp, int typeIndex, const QVector &data) - : TraceEvent(timestamp, typeIndex) + : TraceEvent(staticClassId, timestamp, typeIndex) { assignNumbers, Number>(data); } diff --git a/src/plugins/qmlprofiler/qmleventtype.cpp b/src/plugins/qmlprofiler/qmleventtype.cpp index 9cb99c0081e..88a3d6dd47c 100644 --- a/src/plugins/qmlprofiler/qmleventtype.cpp +++ b/src/plugins/qmlprofiler/qmleventtype.cpp @@ -79,7 +79,7 @@ QDataStream &operator<<(QDataStream &stream, const QmlEventType &type) QmlEventType::QmlEventType(Message message, RangeType rangeType, int detailType, const QmlEventLocation &location, const QString &data, const QString displayName) : - TraceEventType(qmlFeatureFromType(message, rangeType, detailType)), + TraceEventType(staticClassId, qmlFeatureFromType(message, rangeType, detailType)), m_data(data), m_location(location), m_message(message), m_rangeType(rangeType), m_detailType(detailType) { diff --git a/src/plugins/qmlprofiler/qmleventtype.h b/src/plugins/qmlprofiler/qmleventtype.h index 6c3fc53e06d..1e038e634eb 100644 --- a/src/plugins/qmlprofiler/qmleventtype.h +++ b/src/plugins/qmlprofiler/qmleventtype.h @@ -37,6 +37,8 @@ namespace QmlProfiler { class QmlEventType : public Timeline::TraceEventType { public: + static const qint32 staticClassId = 0x716d6c74; // 'qmlt'; + QmlEventType(Message message = MaximumMessage, RangeType rangeType = MaximumRangeType, int detailType = -1, const QmlEventLocation &location = QmlEventLocation(), const QString &data = QString(), const QString displayName = QString()); diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp index c54c7f0981c..2d02c10afd7 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp @@ -148,8 +148,9 @@ void QmlProfilerModelManager::registerFeatures(quint64 features, QmlEventLoader { const TraceEventLoader traceEventLoader = eventLoader ? [eventLoader]( const Timeline::TraceEvent &event, const Timeline::TraceEventType &type) { - return eventLoader(static_cast(event), - static_cast(type)); + QTC_ASSERT(event.is(), return); + QTC_ASSERT(type.is(), return); + eventLoader(event.asConstRef(), type.asConstRef()); } : TraceEventLoader(); Timeline::TimelineTraceManager::registerFeatures(features, traceEventLoader, initializer, @@ -158,7 +159,10 @@ void QmlProfilerModelManager::registerFeatures(quint64 features, QmlEventLoader const QmlEventType &QmlProfilerModelManager::eventType(int typeId) const { - return static_cast(TimelineTraceManager::eventType(typeId)); + static const QmlEventType invalid; + const Timeline::TraceEventType &type = TimelineTraceManager::eventType(typeId); + QTC_ASSERT(type.is(), return invalid); + return type.asConstRef(); } void QmlProfilerModelManager::replayEvents(TraceEventLoader loader, Initializer initializer, @@ -190,7 +194,8 @@ void QmlProfilerModelManager::replayQmlEvents(QmlEventLoader loader, if (future.isCanceled()) return false; - loader(static_cast(event), eventType(event.typeIndex())); + QTC_ASSERT(event.is(), return false); + loader(event.asRvalueRef(), eventType(event.typeIndex())); return true; }); @@ -462,13 +467,19 @@ void QmlProfilerEventTypeStorage::set(int typeId, Timeline::TraceEventType &&typ const size_t index = static_cast(typeId); if (m_types.size() <= index) m_types.resize(index + 1); - m_types[index] = std::move(static_cast(type)); + QTC_ASSERT(type.is(), return); + m_types[index] = std::move(type.asRvalueRef()); } int QmlProfilerEventTypeStorage::append(Timeline::TraceEventType &&type) { const size_t index = m_types.size(); - m_types.push_back(std::move(static_cast(type))); + if (type.is()) { + m_types.push_back(std::move(type.asRvalueRef())); + } else { + QTC_CHECK(false); + m_types.push_back(QmlEventType()); + } QTC_ASSERT(index <= std::numeric_limits::max(), return std::numeric_limits::max()); return static_cast(index); } @@ -495,7 +506,8 @@ QmlProfilerEventStorage::QmlProfilerEventStorage( int QmlProfilerEventStorage::append(Timeline::TraceEvent &&event) { - m_file.append(std::move(static_cast(event))); + QTC_ASSERT(event.is(), return m_size); + m_file.append(std::move(event.asRvalueRef())); return m_size++; }