Skip to content

Commit

Permalink
Implement code navigation for QObjects.
Browse files Browse the repository at this point in the history
Allows for QObjects to navigate to the code location, where they were
created. Not (only) the header file or the class's constructor, but
where the constructor was called from.

This is done by generating a backtrace from
Probe::objectAdded, which is called from the QObject constructor. From
there we can step up to the frame above the object's constructor and
get the source location of that frame.

The stacktrace generation is based on backward-cpp.
  • Loading branch information
akreuzkamp committed Feb 20, 2017
1 parent 0302277 commit 6e54f6d
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ include(FeatureSummary)
include(ECMGeneratePriFile)
include(ECMEnableSanitizers)
include(GenerateExportHeader)
include("3rdparty/backward-cpp/BackwardMacros.cmake")

# Exit for blacklisted compilers (those that don't support C++11 very well)
# MSVC++ < 2010 aka 10.0 aka 1600
Expand Down
2 changes: 2 additions & 0 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ else()
)
endif()

add_backward(gammaray_core)

if(NOT GAMMARAY_PROBE_ONLY_BUILD)
install(TARGETS gammaray_core EXPORT GammaRayTargets ${INSTALL_TARGETS_DEFAULT_ARGS})

Expand Down
2 changes: 2 additions & 0 deletions core/objectdataprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
*/

#include "objectdataprovider.h"
#include "probe.h"

#include <common/sourcelocation.h>

Expand Down Expand Up @@ -91,6 +92,7 @@ SourceLocation ObjectDataProvider::creationLocation(QObject *obj)
return loc;
}

loc = Probe::instance()->objectCreationSourceLocation(obj);
return loc;
}

Expand Down
45 changes: 45 additions & 0 deletions core/probe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
#include <common/streamoperators.h>
#include <common/paths.h>

#include <3rdparty/backward-cpp/backward.hpp>

#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
#include <QApplication>
#else
Expand Down Expand Up @@ -194,6 +196,7 @@ struct Listener

bool trackDestroyed;
QVector<QObject *> addedBeforeProbeInstance;
QHash<QObject *, backward::StackTrace> constructionBacktracesForObjects;
};

Q_GLOBAL_STATIC(Listener, s_listener)
Expand All @@ -209,6 +212,7 @@ Probe::Probe(QObject *parent)
, m_window(nullptr)
, m_queueTimer(new QTimer(this))
, m_server(nullptr)
, m_traceResolver(new backward::TraceResolver())
{
Q_ASSERT(thread() == qApp->thread());
IF_DEBUG(cout << "attaching GammaRay probe" << endl;)
Expand Down Expand Up @@ -538,6 +542,9 @@ void Probe::objectAdded(QObject *obj, bool fromCtor)

#endif

if (fromCtor) {
s_listener()->constructionBacktracesForObjects[obj].load_here(32);
}
if (!isInitialized()) {
IF_DEBUG(cout
<< "objectAdded Before: "
Expand Down Expand Up @@ -993,3 +1000,41 @@ void Probe::executeSignalCallback(const Func &func)
instance()->m_signalSpyCallbacks.constEnd(),
func);
}

SourceLocation Probe::objectCreationSourceLocation(QObject* object)
{
if (!s_listener()->constructionBacktracesForObjects.contains(object)) {
IF_DEBUG(std::cout << "No backtrace for object available for object" << object << "." << std::endl;)
return SourceLocation();
}

backward::StackTrace &st = s_listener()->constructionBacktracesForObjects[object];
int distanceToQObject = 0;
m_traceResolver->load_stacktrace(st);

const QMetaObject *metaObject = object->metaObject();
while (metaObject && metaObject != &QObject::staticMetaObject) {
distanceToQObject++;
metaObject = metaObject->superClass();
}

IF_DEBUG(std::cout << " - Distance: " << distanceToQObject << std::endl;
for (size_t i = 4; i < (uint)6 + distanceToQObject; ++i) {
backward::ResolvedTrace trace = m_traceResolver->resolve(st[i]);
std::cout << "#" << i
<< " " << trace.object_function
<< " " << trace.source.filename
<< ":" << trace.source.line
<< ":" << trace.source.col
<< std::endl;
})

backward::ResolvedTrace trace = m_traceResolver->resolve(st[4 + distanceToQObject + 1]);

SourceLocation loc;
loc.setUrl(QUrl::fromLocalFile(QString::fromStdString(trace.source.filename)));
loc.setLine(trace.source.line);
loc.setColumn(trace.source.col);

return loc;
}
10 changes: 10 additions & 0 deletions core/probe.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@
#include "probeinterface.h"
#include "signalspycallbackset.h"

#include <common/sourcelocation.h>

#include <QObject>
#include <QList>
#include <QSet>
#include <QVector>
#include <memory>

QT_BEGIN_NAMESPACE
class QItemSelectionModel;
Expand All @@ -47,6 +50,10 @@ class QTimer;
class QMutex;
QT_END_NAMESPACE

namespace backward {
class TraceResolver;
}

namespace GammaRay {
class ProbeCreator;
class ObjectListModel;
Expand Down Expand Up @@ -87,6 +94,8 @@ class GAMMARAY_CORE_EXPORT Probe : public QObject, public ProbeInterface
void selectObject(void *object, const QString &typeName) override;
void registerSignalSpyCallbackSet(const SignalSpyCallbackSet &callbacks) override;

SourceLocation objectCreationSourceLocation(QObject *object);

QObject *window() const;
void setWindow(QObject *window);

Expand Down Expand Up @@ -216,6 +225,7 @@ private slots:
QVector<SignalSpyCallbackSet> m_signalSpyCallbacks;
SignalSpyCallbackSet m_previousSignalSpyCallbackSet;
Server *m_server;
std::unique_ptr<backward::TraceResolver> m_traceResolver;
};
}

Expand Down

0 comments on commit 6e54f6d

Please sign in to comment.