File indexing completed on 2022-11-22 13:51:27

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 }