File indexing completed on 2024-04-14 04:31:18
0001 /* This file is part of KDevelop 0002 Copyright 2006-2008 Hamish Rodda <rodda@kde.org> 0003 Copyright 2011 Mathieu Lornac <mathieu.lornac@gmail.com> 0004 Copyright 2011 Damien Coppel <damien.coppel@gmail.com> 0005 Copyright 2011 Lionel Duc <lionel.data@gmail.com> 0006 Copyright 2015 Laszlo Kis-Adam <laszlo.kis-adam@kdemail.net> 0007 Copyright 2016-2017 Anton Anikin <anton@anikin.xyz> 0008 0009 This program is free software; you can redistribute it and/or 0010 modify it under the terms of the GNU General Public 0011 License as published by the Free Software Foundation; either 0012 version 2 of the License, or (at your option) any later version. 0013 0014 This program is distributed in the hope that it will be useful, 0015 but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0017 General Public License for more details. 0018 0019 You should have received a copy of the GNU General Public License 0020 along with this program; see the file COPYING. If not, write to 0021 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0022 Boston, MA 02110-1301, USA. 0023 */ 0024 0025 #include "xmlparser.h" 0026 0027 #include "debug.h" 0028 #include "xmlerror.h" 0029 #include "utils.h" 0030 0031 #include <KLocalizedString> 0032 #include <KMessageBox> 0033 0034 #include <QStack> 0035 #include <QXmlStreamReader> 0036 0037 namespace Valgrind 0038 { 0039 0040 namespace XmlParser 0041 { 0042 0043 class Parser : public QXmlStreamReader 0044 { 0045 public: 0046 explicit Parser(const QString& toolName); 0047 virtual ~Parser(); 0048 0049 QVector<KDevelop::IProblem::Ptr> parse(bool showInstructionPointer); 0050 0051 private: 0052 void startElement(); 0053 void endElement(QVector<KDevelop::IProblem::Ptr>& problems, bool showInstructionPointer); 0054 0055 void clear(); 0056 0057 enum State { 0058 Unknown, 0059 Session, 0060 Status, 0061 Preamble, 0062 Error, 0063 Stack, 0064 Frame, 0065 0066 // DRD tool 0067 OtherSegmentStart, 0068 OtherSegmentEnd 0069 }; 0070 0071 QString m_toolName; 0072 0073 QStack<State> m_stateStack; 0074 0075 QString m_name; 0076 QString m_value; 0077 0078 XmlParser::Frame* m_frame; 0079 XmlParser::Stack* m_stack; 0080 XmlParser::OtherSegment* m_otherSegment; 0081 XmlParser::Error* m_error; 0082 }; 0083 0084 inline QString errorXmlName() { return QStringLiteral("error"); } 0085 inline QString stackXmlName() { return QStringLiteral("stack"); } 0086 inline QString frameXmlName() { return QStringLiteral("frame"); } 0087 0088 inline QString otherSegmentStartXmlName() { return QStringLiteral("other_segment_start"); } 0089 inline QString otherSegmentEndXmlName() { return QStringLiteral("other_segment_end"); } 0090 0091 Parser::Parser(const QString& toolName) 0092 : m_toolName(toolName) 0093 , m_frame(nullptr) 0094 , m_stack(nullptr) 0095 , m_otherSegment(nullptr) 0096 , m_error(new XmlParser::Error) 0097 { 0098 } 0099 0100 Parser::~Parser() 0101 { 0102 delete m_error; 0103 } 0104 0105 void Parser::clear() 0106 { 0107 m_stateStack.clear(); 0108 m_name.clear(); 0109 m_value.clear(); 0110 } 0111 0112 void Parser::startElement() 0113 { 0114 State newState = Unknown; 0115 0116 if (m_name == QStringLiteral("valgrindoutput")) { 0117 newState = Session; 0118 } 0119 0120 else if (m_name == QStringLiteral("status")) { 0121 newState = Status; 0122 } 0123 0124 else if (m_name == QStringLiteral("preamble")) { 0125 newState = Preamble; 0126 } 0127 0128 else if (m_name == errorXmlName()) { 0129 newState = Error; 0130 m_error->clear(); 0131 } 0132 0133 else if (m_name == stackXmlName()) { 0134 newState = Stack; 0135 0136 // Useful stacks are inside error or other_segment_begin/end 0137 if (m_stateStack.top() == Error) { 0138 m_stack = m_error->addStack(); 0139 } else if (m_stateStack.top() == OtherSegmentStart || 0140 m_stateStack.top() == OtherSegmentEnd) { 0141 0142 Q_ASSERT(m_otherSegment); 0143 m_stack = m_otherSegment->addStack(); 0144 } 0145 } 0146 0147 else if (m_name == frameXmlName()) { 0148 newState = Frame; 0149 if (m_stack) { 0150 m_frame = m_stack->addFrame(); 0151 } 0152 } 0153 0154 else if (m_name == otherSegmentStartXmlName()) { 0155 newState = OtherSegmentStart; 0156 m_otherSegment = m_error->addOtherSegment(true); 0157 } 0158 0159 else if (m_name == otherSegmentEndXmlName()) { 0160 newState = OtherSegmentEnd; 0161 m_otherSegment = m_error->addOtherSegment(false); 0162 } 0163 0164 else { 0165 m_stateStack.push(m_stateStack.top()); 0166 return; 0167 } 0168 0169 m_stateStack.push(newState); 0170 return; 0171 } 0172 0173 void Parser::endElement(QVector<KDevelop::IProblem::Ptr>& problems, bool showInstructionPointer) 0174 { 0175 State state = m_stateStack.pop(); 0176 0177 switch (state) { 0178 0179 case Error: 0180 if (m_name == errorXmlName()) { 0181 problems.append(m_error->toIProblem(m_toolName, showInstructionPointer)); 0182 } else { 0183 m_error->setValue(m_name, m_value); 0184 } 0185 break; 0186 0187 case Stack: 0188 if (m_stack && m_name == stackXmlName()) { 0189 m_stack = nullptr; 0190 } 0191 break; 0192 0193 case Frame: 0194 if (m_frame) { 0195 if (m_name == frameXmlName()) { 0196 m_frame = nullptr; 0197 } else { 0198 m_frame->setValue(m_name, m_value); 0199 } 0200 } 0201 break; 0202 0203 case OtherSegmentStart: 0204 if (m_name == otherSegmentStartXmlName()) { 0205 m_otherSegment = nullptr; 0206 } 0207 break; 0208 0209 case OtherSegmentEnd: 0210 if (m_name == otherSegmentEndXmlName()) { 0211 m_otherSegment = nullptr; 0212 } 0213 break; 0214 0215 default: 0216 break; 0217 } 0218 } 0219 0220 QVector<KDevelop::IProblem::Ptr> Parser::parse(bool showInstructionPointer) 0221 { 0222 QVector<KDevelop::IProblem::Ptr> problems; 0223 0224 while (!atEnd()) { 0225 switch (readNext()) { 0226 0227 case StartDocument: 0228 clear(); 0229 break; 0230 0231 case StartElement: 0232 m_name = name().toString(); 0233 m_value.clear(); 0234 startElement(); 0235 break; 0236 0237 case EndElement: 0238 m_name = name().toString(); 0239 endElement(problems, showInstructionPointer); 0240 break; 0241 0242 case Characters: 0243 m_value += text(); 0244 break; 0245 0246 default: 0247 break; 0248 } 0249 } 0250 0251 if (hasError()) { 0252 switch (error()) { 0253 0254 case CustomError: 0255 case UnexpectedElementError: 0256 case NotWellFormedError: 0257 KMessageBox::error(activeMainWindow(), 0258 i18n("Valgrind XML Parsing: error at line %1, column %2: %3", 0259 lineNumber(), 0260 columnNumber(), 0261 errorString()), 0262 i18n("Valgrind Error")); 0263 break; 0264 0265 case NoError: 0266 case PrematureEndOfDocumentError: 0267 break; 0268 } 0269 } 0270 0271 return problems; 0272 } 0273 0274 } 0275 0276 QVector<KDevelop::IProblem::Ptr> parseXml(const QString& toolName, const QString& xmlData, bool showInstructionPointer) 0277 { 0278 XmlParser::Parser parser(toolName); 0279 parser.addData(xmlData); 0280 0281 return parser.parse(showInstructionPointer); 0282 } 0283 0284 }