File indexing completed on 2024-03-24 04:38:30
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 2011 Sarie Lucas <lucas.sarie@gmail.com> 0007 * Copyright 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 "xmlerror.h" 0026 0027 #include "debug.h" 0028 0029 #include <shell/problem.h> 0030 #include <language/editor/documentrange.h> 0031 0032 #include <QRegularExpression> 0033 0034 namespace Valgrind 0035 { 0036 0037 namespace XmlParser 0038 { 0039 0040 void Frame::setValue(const QString& name, const QString& value) 0041 { 0042 if (name == "ip") { 0043 instructionPointer = value; 0044 } 0045 0046 else if (name == "obj") { 0047 objectFile = value; 0048 } 0049 0050 else if (name == "fn") { 0051 function = value; 0052 } 0053 0054 else if (name == "dir") { 0055 directory = value; 0056 } 0057 0058 else if (name == "file") { 0059 file = value; 0060 } 0061 0062 else if (name == "line") { 0063 line = value.toInt(); 0064 } 0065 } 0066 0067 KDevelop::IProblem::Ptr Frame::toIProblem(const QString& toolName, bool showInstructionPointer) const 0068 { 0069 KDevelop::IProblem::Ptr frameProblem(new KDevelop::DetectedProblem(toolName)); 0070 0071 KDevelop::DocumentRange range; 0072 range.setBothLines(line - 1); 0073 0074 if (directory.isEmpty() && file.isEmpty()) { 0075 range.document = KDevelop::IndexedString(objectFile); 0076 } else { 0077 range.document = KDevelop::IndexedString(directory + QLatin1Char('/') + file); 0078 } 0079 0080 frameProblem->setFinalLocation(range); 0081 frameProblem->setFinalLocationMode(KDevelop::IProblem::TrimmedLine); 0082 0083 QString description; 0084 if (showInstructionPointer) { 0085 description = QStringLiteral("%1: ").arg(instructionPointer); 0086 } 0087 description += function; 0088 frameProblem->setDescription(description); 0089 0090 return frameProblem; 0091 } 0092 0093 Frame* Stack::addFrame() 0094 { 0095 frames.append(Frame{}); 0096 return &frames.last(); 0097 } 0098 0099 KDevelop::IProblem::Ptr Stack::toIProblem(const QString& toolName, bool showInstructionPointer) const 0100 { 0101 KDevelop::IProblem::Ptr stackProblem(new KDevelop::DetectedProblem(toolName)); 0102 0103 KDevelop::DocumentRange range(KDevelop::DocumentRange::invalid()); 0104 for (const Frame& frame : frames) { 0105 auto frameProblem = frame.toIProblem(toolName, showInstructionPointer); 0106 stackProblem->addDiagnostic(frameProblem); 0107 0108 if (!range.isValid() && !frame.file.isEmpty()) { 0109 range = frameProblem->finalLocation(); 0110 } 0111 } 0112 0113 stackProblem->setFinalLocation(range); 0114 stackProblem->setFinalLocationMode(KDevelop::IProblem::TrimmedLine); 0115 0116 return stackProblem; 0117 } 0118 0119 Stack* OtherSegment::addStack() 0120 { 0121 stacks.append(Stack{}); 0122 return &stacks.last(); 0123 } 0124 0125 KDevelop::IProblem::Ptr OtherSegment::toIProblem(const QString& toolName, bool showInstructionPointer) const 0126 { 0127 QString description = isStart ? QStringLiteral("Other segment start") : QStringLiteral("Other segment end"); 0128 0129 // Simplify view for segments with single stack 0130 if (stacks.size() == 1) { 0131 auto segmentProblem = stacks.first().toIProblem(toolName, showInstructionPointer); 0132 segmentProblem->setDescription(description); 0133 return segmentProblem; 0134 } 0135 0136 KDevelop::IProblem::Ptr segmentProblem(new KDevelop::DetectedProblem(toolName)); 0137 segmentProblem->setDescription(description); 0138 0139 for (int i = 0; i < stacks.size(); ++i) { 0140 auto stackProblem = stacks.at(i).toIProblem(toolName, showInstructionPointer); 0141 stackProblem->setDescription(QStringLiteral("Stack_%1").arg(i)); 0142 segmentProblem->addDiagnostic(stackProblem); 0143 } 0144 0145 return segmentProblem; 0146 } 0147 0148 void Error::clear() 0149 { 0150 stacks.clear(); 0151 messages.clear(); 0152 otherSegments.clear(); 0153 } 0154 0155 Stack* Error::addStack() 0156 { 0157 stacks.append(Stack{}); 0158 return &stacks.last(); 0159 } 0160 0161 OtherSegment* Error::addOtherSegment(bool isStart) 0162 { 0163 otherSegments.append({ isStart, {} }); 0164 return &otherSegments.last(); 0165 } 0166 0167 void Error::setValue(const QString& name, const QString& value) 0168 { 0169 // Fix for memcheck messages 0170 static const QRegularExpression memcheckSuffix(" in loss record \\d+ of \\d+$"); 0171 0172 if (!value.isEmpty() && (name == QStringLiteral("text") || 0173 name == QStringLiteral("auxwhat") || 0174 name == QStringLiteral("what"))) { 0175 messages += value.trimmed().remove(memcheckSuffix); 0176 } 0177 } 0178 0179 KDevelop::IProblem::Ptr Error::toIProblem(const QString& toolName, bool showInstructionPointer) const 0180 { 0181 Q_ASSERT(!messages.isEmpty()); 0182 Q_ASSERT(!stacks.isEmpty()); 0183 0184 // Simplify view for errors with single stack / message 0185 if (stacks.size() == 1 && messages.size() == 1) { 0186 auto problem = stacks.first().toIProblem(toolName, showInstructionPointer); 0187 problem->setDescription(messages.first()); 0188 return problem; 0189 } 0190 0191 KDevelop::IProblem::Ptr problem(new KDevelop::DetectedProblem(toolName)); 0192 problem->setDescription(messages.first()); 0193 0194 // Add all stacks 0195 for (const Stack& stack : stacks) { 0196 problem->addDiagnostic(stack.toIProblem(toolName, showInstructionPointer)); 0197 } 0198 0199 // First stack is the one that shows the actual error 0200 // Hence why the problem gets it's file/line pair from here 0201 problem->setFinalLocation(problem->diagnostics().first()->finalLocation()); 0202 problem->setFinalLocationMode(KDevelop::IProblem::TrimmedLine); 0203 0204 // Set descriptions for all stacks. If we have some "extra" messages, then 0205 // we add them as "empty" (text-only) problems. 0206 for (int i = 0; i < messages.size(); ++i) { 0207 if (i < stacks.size()) { 0208 problem->diagnostics().at(i)->setDescription(messages.at(i)); 0209 } 0210 0211 else { 0212 KDevelop::IProblem::Ptr messageOnlyProblem(new KDevelop::DetectedProblem(toolName)); 0213 messageOnlyProblem->setDescription(messages.at(i)); 0214 messageOnlyProblem->setFinalLocation(problem->finalLocation()); 0215 problem->addDiagnostic(messageOnlyProblem); 0216 } 0217 } 0218 0219 // Add other segments ad diagnostics (DRD tool) 0220 for (const auto& segment : otherSegments) { 0221 if (!segment.stacks.isEmpty()) { 0222 problem->addDiagnostic(segment.toIProblem(toolName, showInstructionPointer)); 0223 } 0224 } 0225 0226 return problem; 0227 } 0228 0229 } 0230 0231 }