From f1ff2a01cc7214ea971b4d33165a4e28aefab8f2 Mon Sep 17 00:00:00 2001
From: Lasse Holmstedt <lasse.holmstedt@nokia.com>
Date: Wed, 8 Sep 2010 13:31:12 +0200
Subject: [PATCH] QML Debugger: Mangle shadow build filenames

Without doing some magic for the filenames, we go to shadow build files
instead of the real ones, resulting in confusion. The user should never
see the shadow build files while debugging.

Reviewed-by: hjk
---
 src/plugins/debugger/debuggerengine.h   |  9 ++-
 src/plugins/debugger/debuggerrunner.cpp |  4 ++
 src/plugins/debugger/qml/qmlengine.cpp  | 91 ++++++++++++++++++++++++-
 src/plugins/debugger/qml/qmlengine.h    |  8 +++
 4 files changed, 108 insertions(+), 4 deletions(-)

diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h
index e18e763e169..b400435e8a9 100644
--- a/src/plugins/debugger/debuggerengine.h
+++ b/src/plugins/debugger/debuggerengine.h
@@ -80,7 +80,10 @@ public:
     // for qml debugging
     QString qmlServerAddress;
     quint16 qmlServerPort;
-    DebuggerEngineType cppEngineType; // for cpp+qml debugging
+    QString projectBuildDir;
+    QString projectDir;
+    // for cpp+qml debugging
+    DebuggerEngineType cppEngineType;
 
     // for remote debugging
     QString remoteChannel;
@@ -274,8 +277,8 @@ public:
 
     void resetLocation();
     void openFile(const QString &fileName, int lineNumber = -1);
-    void gotoLocation(const QString &fileName, int lineNumber, bool setMarker);
-    void gotoLocation(const StackFrame &frame, bool setMarker);
+    virtual void gotoLocation(const QString &fileName, int lineNumber, bool setMarker);
+    virtual void gotoLocation(const StackFrame &frame, bool setMarker);
     virtual void quitDebugger(); // called by DebuggerRunControl
 
 signals:
diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp
index e8d3dfc909d..310e8ce36fc 100644
--- a/src/plugins/debugger/debuggerrunner.cpp
+++ b/src/plugins/debugger/debuggerrunner.cpp
@@ -156,6 +156,10 @@ static DebuggerStartParameters localStartParameters(RunConfiguration *runConfigu
         sp.qmlServerAddress = QLatin1String("127.0.0.1");
         sp.qmlServerPort = runConfiguration->qmlDebugServerPort();
 
+        sp.projectDir = runConfiguration->target()->project()->projectDirectory();
+        if (runConfiguration->target()->activeBuildConfiguration())
+            sp.projectBuildDir = runConfiguration->target()->activeBuildConfiguration()->buildDirectory();
+
         sp.environment << QString(Constants::E_QML_DEBUG_SERVER_PORT)
                         + QLatin1Char('=') + QString::number(sp.qmlServerPort);
     }
diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp
index 2cd0f9b6395..d8c2ac69c46 100644
--- a/src/plugins/debugger/qml/qmlengine.cpp
+++ b/src/plugins/debugger/qml/qmlengine.cpp
@@ -126,6 +126,25 @@ void QmlEngine::pauseConnection()
     m_adapter->pauseConnection();
 }
 
+void QmlEngine::gotoLocation(const QString &fileName, int lineNumber, bool setMarker)
+{
+    QString processedFilename = fileName;
+
+    if (isShadowBuildProject())
+        processedFilename = fromShadowBuildFilename(fileName);
+
+    DebuggerEngine::gotoLocation(processedFilename, lineNumber, setMarker);
+}
+
+void QmlEngine::gotoLocation(const StackFrame &frame, bool setMarker)
+{
+    StackFrame adjustedFrame = frame;
+    if (isShadowBuildProject())
+        adjustedFrame.file = fromShadowBuildFilename(frame.file);
+
+    DebuggerEngine::gotoLocation(adjustedFrame, setMarker);
+}
+
 void QmlEngine::setupInferior()
 {
     QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
@@ -380,7 +399,10 @@ void QmlEngine::attemptBreakpointSynchronization()
     QSet< QPair<QString, qint32> > breakList;
     for (int index = 0; index != handler->size(); ++index) {
         BreakpointData *data = handler->at(index);
-        breakList << qMakePair(data->fileName, data->lineNumber.toInt());
+        QString processedFilename = data->fileName;
+        if (isShadowBuildProject())
+            processedFilename = toShadowBuildFilename(data->fileName);
+        breakList << qMakePair(processedFilename, data->lineNumber.toInt());
     }
 
     {
@@ -677,6 +699,73 @@ void QmlEngine::executeDebuggerCommand(const QString& command)
     sendMessage(reply);
 }
 
+bool QmlEngine::isShadowBuildProject() const
+{
+    if (!startParameters().projectBuildDir.isEmpty()
+        && (startParameters().projectDir != startParameters().projectBuildDir))
+    {
+        return true;
+    }
+    return false;
+}
+
+QString QmlEngine::qmlImportPath() const
+{
+    QString result;
+    const QString qmlImportPathPrefix("QML_IMPORT_PATH=");
+    QStringList env = startParameters().environment;
+    foreach(const QString &envStr, env) {
+        if (envStr.startsWith(qmlImportPathPrefix)) {
+            result = envStr.mid(qmlImportPathPrefix.length());
+            break;
+        }
+    }
+    return result;
+}
+
+QString QmlEngine::toShadowBuildFilename(const QString &filename) const
+{
+    QString newFilename = filename;
+    QString importPath = qmlImportPath();
+
+    newFilename = mangleFilenamePaths(filename, startParameters().projectDir, startParameters().projectBuildDir);
+    if (newFilename == filename && !importPath.isEmpty()) {
+        newFilename = mangleFilenamePaths(filename, startParameters().projectDir, importPath);
+    }
+
+    return newFilename;
+}
+
+QString QmlEngine::mangleFilenamePaths(const QString &filename, const QString &oldBasePath, const QString &newBasePath) const
+{
+    QDir oldBaseDir(oldBasePath);
+    QDir newBaseDir(newBasePath);
+    QFileInfo fileInfo(filename);
+
+    if (oldBaseDir.exists() && newBaseDir.exists() && fileInfo.exists()) {
+        if (fileInfo.absoluteFilePath().startsWith(oldBaseDir.canonicalPath())) {
+            QString fileRelativePath = fileInfo.canonicalFilePath().mid(oldBasePath.length());
+            QFileInfo projectFile(newBaseDir.canonicalPath() + QLatin1Char('/') + fileRelativePath);
+
+            if (projectFile.exists())
+                return projectFile.canonicalFilePath();
+        }
+    }
+    return filename;
+}
+
+QString QmlEngine::fromShadowBuildFilename(const QString &filename) const
+{
+    QString newFilename = filename;
+    QString importPath = qmlImportPath();
+
+    newFilename = mangleFilenamePaths(filename, startParameters().projectBuildDir, startParameters().projectDir);
+    if (newFilename == filename && !importPath.isEmpty()) {
+        newFilename = mangleFilenamePaths(filename, startParameters().projectBuildDir, importPath);
+    }
+
+    return newFilename;
+}
 
 } // namespace Internal
 } // namespace Debugger
diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h
index 9c02c2c4cb7..5c0854acf28 100644
--- a/src/plugins/debugger/qml/qmlengine.h
+++ b/src/plugins/debugger/qml/qmlengine.h
@@ -67,6 +67,8 @@ public:
     void shutdownInferiorAsSlave();
     void shutdownEngineAsSlave();
     void pauseConnection();
+    void gotoLocation(const QString &fileName, int lineNumber, bool setMarker);
+    void gotoLocation(const StackFrame &frame, bool setMarker);
 
 public slots:
     void messageReceived(const QByteArray &message);
@@ -130,6 +132,12 @@ private:
     void expandObject(const QByteArray &iname, quint64 objectId);
     void sendPing();
 
+    bool isShadowBuildProject() const;
+    QString fromShadowBuildFilename(const QString &filename) const;
+    QString mangleFilenamePaths(const QString &filename, const QString &oldBasePath, const QString &newBasePath) const;
+    QString toShadowBuildFilename(const QString &filename) const;
+    QString qmlImportPath() const;
+
 private:
     friend class QmlCppEngine;
 
-- 
GitLab