File indexing completed on 2024-04-21 04:36:04
0001 /* 0002 * XDebug-specific Variable 0003 * 0004 * Copyright 2009 Vladimir Prus <ghost@cs.msu.su> 0005 * Copyright 2009 Niko Sams <niko.sams@gmail.com> 0006 * 0007 * This program is free software; you can redistribute it and/or modify 0008 * it under the terms of the GNU General Public License as 0009 * published by the Free Software Foundation; either version 2 of the 0010 * License, or (at your option) any later version. 0011 * 0012 * This program is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0015 * GNU General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU General Public 0018 * License along with this program; if not, write to the 0019 * Free Software Foundation, Inc., 0020 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 0021 */ 0022 0023 #include "variable.h" 0024 #include "debugsession.h" 0025 0026 #include <QDebug> 0027 0028 #include <QDomElement> 0029 #include <QXmlStreamReader> 0030 0031 #include <interfaces/icore.h> 0032 #include <debugger/interfaces/ivariablecontroller.h> 0033 #include <debugger/interfaces/iframestackmodel.h> 0034 0035 #include "connection.h" 0036 #include "debuggerdebug.h" 0037 0038 namespace XDebug { 0039 static bool hasStartedSession() 0040 { 0041 KDevelop::IDebugSession* session = KDevelop::ICore::self()->debugController()->currentSession(); 0042 if (!session) { 0043 return false; 0044 } 0045 0046 KDevelop::IDebugSession::DebuggerState s = session->state(); 0047 return s != KDevelop::IDebugSession::NotStartedState 0048 && s != KDevelop::IDebugSession::EndedState; 0049 } 0050 0051 Variable::Variable(KDevelop::TreeModel* model, KDevelop::TreeItem* parent, 0052 const QString& expression, const QString& display) 0053 : KDevelop::Variable(model, parent, expression, display) 0054 { 0055 } 0056 0057 Variable::~Variable() 0058 { 0059 } 0060 0061 class PropertyGetCallback 0062 : public CallbackBase 0063 { 0064 public: 0065 PropertyGetCallback(Variable* variable, QObject* callback, const char* callbackMethod) 0066 : m_variable(variable) 0067 , m_callback(callback) 0068 , m_callbackMethod(callbackMethod) 0069 {} 0070 0071 void execute(const QDomDocument& xml) override 0072 { 0073 qCDebug(KDEV_PHP_DEBUGGER) << xml.toString(); 0074 Q_ASSERT(xml.documentElement().attribute("command") == "property_get"); 0075 0076 if (!m_variable) {return;} 0077 0078 bool hasValue = false; 0079 QDomElement el = xml.documentElement().firstChildElement(); 0080 if (el.nodeName() == "error") { 0081 qCDebug(KDEV_PHP_DEBUGGER) << el.firstChildElement().text(); 0082 //hasValue=false 0083 } else { 0084 el = xml.documentElement().firstChildElement("property"); 0085 hasValue = !el.isNull(); 0086 if (hasValue) { 0087 m_variable->handleProperty(el); 0088 } 0089 } 0090 0091 if (m_callback && m_callbackMethod) { 0092 QMetaObject::invokeMethod(m_callback, m_callbackMethod, Q_ARG(bool, hasValue)); 0093 } 0094 } 0095 0096 bool allowError() const override { return true; } 0097 0098 private: 0099 QPointer<Variable> m_variable; 0100 QObject* m_callback; 0101 const char* m_callbackMethod; 0102 }; 0103 0104 void Variable::attachMaybe(QObject* callback, const char* callbackMethod) 0105 { 0106 if (hasStartedSession()) { 0107 // FIXME: Eventually, should be a property of variable. 0108 KDevelop::IDebugSession* is = KDevelop::ICore::self()->debugController()->currentSession(); 0109 DebugSession* s = static_cast<DebugSession*>(is); 0110 QStringList args; 0111 args << "-n " + expression(); 0112 args << QString("-d %0").arg(s->frameStackModel()->currentFrame()); 0113 s->connection()->sendCommand("property_get", args, QByteArray(), 0114 new PropertyGetCallback(this, callback, callbackMethod)); 0115 } 0116 } 0117 0118 void Variable::fetchMoreChildren() 0119 { 0120 // FIXME: should not even try this if app is not started. 0121 // Probably need to disable open, or something 0122 if (hasStartedSession()) { 0123 // FIXME: Eventually, should be a property of variable. 0124 KDevelop::IDebugSession* is = KDevelop::ICore::self()->debugController()->currentSession(); 0125 DebugSession* s = static_cast<DebugSession*>(is); 0126 qCDebug(KDEV_PHP_DEBUGGER) << expression() << m_fullName; 0127 QStringList args; 0128 args << "-n " + m_fullName; 0129 args << QString("-d %0").arg(s->frameStackModel()->currentFrame()); 0130 s->connection()->sendCommand("property_get", args, QByteArray(), 0131 new PropertyGetCallback(this, nullptr, nullptr)); 0132 } 0133 } 0134 0135 void Variable::handleProperty(const QDomElement& xml) 0136 { 0137 Q_ASSERT(!xml.isNull()); 0138 Q_ASSERT(xml.nodeName() == "property"); 0139 0140 setInScope(true); 0141 0142 m_fullName = xml.attribute("fullname"); 0143 //qCDebug(KDEV_PHP_DEBUGGER) << m_fullName; 0144 if (xml.firstChild().isText()) { 0145 QString v = xml.firstChild().toText().data(); 0146 if (xml.attribute("encoding") == "base64") { 0147 //TODO: use Connection::m_codec->toUnicode 0148 v = QString::fromUtf8(QByteArray::fromBase64(xml.text().toUtf8())); 0149 } 0150 //qCDebug(KDEV_PHP_DEBUGGER) << "value" << v; 0151 setValue(v); 0152 } 0153 0154 QMap<QString, Variable*> existing; 0155 for (int i = 0; i < childCount() - (hasMore() ? 1 : 0); i++) { 0156 Q_ASSERT(dynamic_cast<Variable*>(child(i))); 0157 Variable* v = static_cast<Variable*>(child(i)); 0158 existing[v->expression()] = v; 0159 } 0160 0161 QSet<QString> current; 0162 QDomElement el = xml.firstChildElement("property"); 0163 while (!el.isNull()) { 0164 QString name = el.attribute("name"); 0165 //qCDebug(KDEV_PHP_DEBUGGER) << name; 0166 current << name; 0167 Variable* v = nullptr; 0168 if (!existing.contains(name)) { 0169 v = new Variable(model(), this, name); 0170 appendChild(v, false); 0171 } else { 0172 v = existing[name]; 0173 } 0174 0175 v->handleProperty(el); 0176 0177 el = el.nextSiblingElement("property"); 0178 } 0179 0180 for (int i = 0; i < childCount() - (hasMore() ? 1 : 0); ++i) { 0181 Q_ASSERT(dynamic_cast<KDevelop::Variable*>(child(i))); 0182 KDevelop::Variable* v = static_cast<KDevelop::Variable*>(child(i)); 0183 if (!current.contains(v->expression())) { 0184 removeChild(i); 0185 --i; 0186 delete v; 0187 } 0188 } 0189 0190 if (!childCount() && xml.attribute("children") == "1") { 0191 qCDebug(KDEV_PHP_DEBUGGER) << "has more" << this; 0192 setHasMore(true); 0193 if (isExpanded()) { 0194 fetchMoreChildren(); 0195 } 0196 } 0197 } 0198 0199 QString Variable::fullName() const 0200 { 0201 return m_fullName; 0202 } 0203 }