File indexing completed on 2021-12-21 13:15:51

0001 /*
0002  * XDebug Debugger Support
0003  *
0004  * Copyright 2007 Hamish Rodda <rodda@kde.org>
0005  * Copyright 2008 Vladimir Prus <ghost@cs.msu.su>
0006  * Copyright 2009 Niko Sams <niko.sams@gmail.com>
0007  *
0008  * This program is free software; you can redistribute it and/or modify
0009  * it under the terms of the GNU General Public License as
0010  * published by the Free Software Foundation; either version 2 of the
0011  * License, or (at your option) any later version.
0012  *
0013  * This program is distributed in the hope that it will be useful,
0014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0016  * GNU General Public License for more details.
0017  *
0018  * You should have received a copy of the GNU General Public
0019  * License along with this program; if not, write to the
0020  * Free Software Foundation, Inc.,
0021  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0022  */
0023 
0024 #include "variablecontroller.h"
0025 
0026 #include <KTextEditor/Document>
0027 
0028 #include <QDomElement>
0029 #include <QXmlStreamReader>
0030 
0031 #include <debugger/variable/variablecollection.h>
0032 #include <debugger/breakpoint/breakpointmodel.h>
0033 #include <interfaces/icore.h>
0034 #include <interfaces/idebugcontroller.h>
0035 #include <debugger/interfaces/iframestackmodel.h>
0036 
0037 #include "connection.h"
0038 #include "debugsession.h"
0039 #include "variable.h"
0040 #include "stringhelpers.h"
0041 
0042 namespace XDebug {
0043 VariableController::VariableController(DebugSession* parent)
0044     : KDevelop::IVariableController(parent)
0045 {
0046     Q_ASSERT(parent);
0047 }
0048 
0049 DebugSession* VariableController::debugSession() const
0050 {
0051     return static_cast<DebugSession*>(const_cast<QObject*>(QObject::parent()));
0052 }
0053 
0054 void VariableController::update()
0055 {
0056     //if (autoUpdate() & UpdateWatches) {
0057     variableCollection()->watches()->reinstall();
0058     //}
0059 //    if (autoUpdate() & UpdateLocals) {
0060     updateLocals();
0061 //    }
0062 }
0063 
0064 void VariableController::handleLocals(KDevelop::Locals* locals, const QDomDocument& xml)
0065 {
0066     Q_ASSERT(xml.documentElement().attribute("command") == "context_get");
0067 
0068     QStringList names;
0069     {
0070         QDomElement el = xml.documentElement().firstChildElement("property");
0071         while (!el.isNull()) {
0072             names << el.attribute("fullname");
0073             el = el.nextSiblingElement("property");
0074         }
0075     }
0076 
0077     {
0078         QList<KDevelop::Variable*> vars = locals->updateLocals(names);
0079 
0080         QDomElement el = xml.documentElement().firstChildElement("property");
0081         while (!el.isNull()) {
0082             QString name = el.attribute("fullname");
0083             foreach (KDevelop::Variable* v, vars) {
0084                 Q_ASSERT(dynamic_cast<Variable*>(v));
0085                 if (v->expression() == name) {
0086                     static_cast<Variable*>(v)->handleProperty(el);
0087                     break;
0088                 }
0089             }
0090 
0091             el = el.nextSiblingElement("property");
0092         }
0093     }
0094 }
0095 void VariableController::handleContextNames(const QDomDocument& xml)
0096 {
0097     Q_ASSERT(xml.documentElement().attribute("command") == "context_names");
0098 
0099     QDomElement el = xml.documentElement().firstChildElement("context");
0100     while (!el.isNull()) {
0101         QString name = el.attribute("name");
0102         QString id = el.attribute("id");
0103         QStringList args;
0104         args << QString("-c %0").arg(id);
0105         Q_ASSERT(debugSession()->frameStackModel()->currentFrame() != -1);
0106         args << QString("-d %0").arg(debugSession()->frameStackModel()->currentFrame());
0107         KDevelop::Locals* locals = KDevelop::ICore::self()->debugController()->variableCollection()->locals(name);
0108         CallbackWithCookie<VariableController, KDevelop::Locals>* cb =
0109             new CallbackWithCookie<VariableController, KDevelop::Locals>
0110                 (this, &VariableController::handleLocals, locals);
0111         debugSession()->connection()->sendCommand("context_get", args, QByteArray(), cb);
0112         el = el.nextSiblingElement("context");
0113     }
0114 }
0115 
0116 void VariableController::updateLocals()
0117 {
0118     if (debugSession()->frameStackModel()->currentFrame() == -1) {
0119         return;
0120     }
0121 
0122     Callback<VariableController>* cb = new Callback<VariableController>(this, &VariableController::handleContextNames);
0123     QStringList args;
0124     args << QString("-d %0").arg(debugSession()->frameStackModel()->currentFrame());
0125     debugSession()->connection()->sendCommand("context_names", args, QByteArray(), cb);
0126 }
0127 
0128 KTextEditor::Range VariableController::expressionRangeUnderCursor(KTextEditor::Document* doc, const KTextEditor::Cursor& cursor)
0129 {
0130     QString line = doc->line(cursor.line());
0131     int index = cursor.column();
0132     QChar c = line[index];
0133     if (!c.isLetterOrNumber() && c != '_' && c != '$') {
0134         return {};
0135     }
0136 
0137     int start = Utils::expressionAt(line, index);
0138     int end = index;
0139     for (; end < line.size(); ++end) {
0140         QChar c = line[end];
0141         if (!(c.isLetterOrNumber() || c == '_' || c == '$')) {
0142             break;
0143         }
0144     }
0145 
0146     if (!(start < end)) {
0147         return {};
0148     }
0149 
0150     // TODO: Check whether this was ported correctly
0151     return {
0152                KTextEditor::Cursor {
0153                    cursor.line(), start
0154                }, KTextEditor::Cursor {
0155                    cursor.line(), end
0156                }
0157     };
0158 }
0159 
0160 void VariableController::addWatch(KDevelop::Variable* variable)
0161 {
0162     if (Variable* v = dynamic_cast<Variable*>(variable)) {
0163         variableCollection()->watches()->add(v->fullName());
0164     }
0165 }
0166 
0167 void VariableController::addWatchpoint(KDevelop::Variable* variable)
0168 {
0169     if (Variable* v = dynamic_cast<Variable*>(variable)) {
0170         KDevelop::ICore::self()->debugController()->breakpointModel()->addWatchpoint(v->fullName());
0171     }
0172 }
0173 
0174 KDevelop::Variable* VariableController::
0175 createVariable(KDevelop::TreeModel* model, KDevelop::TreeItem* parent,
0176                const QString& expression, const QString& display)
0177 {
0178     return new Variable(model, parent, expression, display);
0179 }
0180 
0181 void VariableController::handleEvent(KDevelop::IDebugSession::event_t event)
0182 {
0183     IVariableController::handleEvent(event);
0184 }
0185 }