Cppcheck
xmlreportv2.cpp
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2024 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "xmlreportv2.h"
20 
21 #include "cppcheck.h"
22 #include "erroritem.h"
23 #include "report.h"
24 #include "settings.h"
25 #include "xmlreport.h"
26 
27 #include <utility>
28 
29 #include <QDebug>
30 #include <QDir>
31 #include <QFile>
32 #include <QXmlStreamAttributes>
33 #include <QXmlStreamReader>
34 #include <QXmlStreamWriter>
35 
36 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
37 #include <QStringRef>
38 #endif
39 
40 static const QString ResultElementName = "results";
41 static const QString CppcheckElementName = "cppcheck";
42 static const QString ErrorElementName = "error";
43 static const QString ErrorsElementName = "errors";
44 static const QString LocationElementName = "location";
45 static const QString CWEAttribute = "cwe";
46 static const QString HashAttribute = "hash";
47 static const QString SinceDateAttribute = "sinceDate";
48 static const QString TagsAttribute = "tag";
49 static const QString FilenameAttribute = "file";
50 static const QString IncludedFromFilenameAttribute = "file0";
51 static const QString InconclusiveAttribute = "inconclusive";
52 static const QString InfoAttribute = "info";
53 static const QString LineAttribute = "line";
54 static const QString ColumnAttribute = "column";
55 static const QString IdAttribute = "id";
56 static const QString SeverityAttribute = "severity";
57 static const QString MsgAttribute = "msg";
58 static const QString VersionAttribute = "version";
59 static const QString ProductNameAttribute = "product-name";
60 static const QString VerboseAttribute = "verbose";
61 
62 XmlReportV2::XmlReportV2(const QString &filename, QString productName) :
63  XmlReport(filename),
64  mProductName(std::move(productName)),
65  mXmlReader(nullptr),
66  mXmlWriter(nullptr)
67 {}
68 
70 {
71  delete mXmlReader;
72  delete mXmlWriter;
73 }
74 
76 {
77  if (Report::create()) {
78  mXmlWriter = new QXmlStreamWriter(Report::getFile());
79  return true;
80  }
81  return false;
82 }
83 
85 {
86  if (Report::open()) {
87  mXmlReader = new QXmlStreamReader(Report::getFile());
88  return true;
89  }
90  return false;
91 }
92 
94 {
95  const auto nameAndVersion = Settings::getNameAndVersion(mProductName.toStdString());
96  const QString name = QString::fromStdString(nameAndVersion.first);
97  const QString version = nameAndVersion.first.empty() ? CppCheck::version() : QString::fromStdString(nameAndVersion.second);
98 
99  mXmlWriter->setAutoFormatting(true);
100  mXmlWriter->writeStartDocument();
101  mXmlWriter->writeStartElement(ResultElementName);
102  mXmlWriter->writeAttribute(VersionAttribute, QString::number(2));
103  mXmlWriter->writeStartElement(CppcheckElementName);
104  if (!name.isEmpty())
105  mXmlWriter->writeAttribute(ProductNameAttribute, name);
106  mXmlWriter->writeAttribute(VersionAttribute, version);
107  mXmlWriter->writeEndElement();
108  mXmlWriter->writeStartElement(ErrorsElementName);
109 }
110 
112 {
113  mXmlWriter->writeEndElement(); // errors
114  mXmlWriter->writeEndElement(); // results
115  mXmlWriter->writeEndDocument();
116 }
117 
119 {
120  /*
121  Error example from the core program in xml
122  <error id="mismatchAllocDealloc" severity="error" msg="Mismatching allocation and deallocation: k"
123  verbose="Mismatching allocation and deallocation: k">
124  <location file="..\..\test\test.cxx" line="16"/>
125  <location file="..\..\test\test.cxx" line="32"/>
126  </error>
127  */
128 
129  mXmlWriter->writeStartElement(ErrorElementName);
130  mXmlWriter->writeAttribute(IdAttribute, error.errorId);
131 
132  // Don't localize severity so we can read these files
133  mXmlWriter->writeAttribute(SeverityAttribute, GuiSeverity::toString(error.severity));
134  const QString summary = XmlReport::quoteMessage(error.summary);
135  mXmlWriter->writeAttribute(MsgAttribute, summary);
136  const QString message = XmlReport::quoteMessage(error.message);
137  mXmlWriter->writeAttribute(VerboseAttribute, message);
138  if (error.inconclusive)
139  mXmlWriter->writeAttribute(InconclusiveAttribute, "true");
140  if (error.cwe > 0)
141  mXmlWriter->writeAttribute(CWEAttribute, QString::number(error.cwe));
142  if (error.hash > 0)
143  mXmlWriter->writeAttribute(HashAttribute, QString::number(error.hash));
144  if (!error.file0.isEmpty())
146  if (!error.sinceDate.isEmpty())
147  mXmlWriter->writeAttribute(SinceDateAttribute, error.sinceDate);
148  if (!error.tags.isEmpty())
149  mXmlWriter->writeAttribute(TagsAttribute, error.tags);
150 
151  for (int i = error.errorPath.count() - 1; i >= 0; i--) {
152  mXmlWriter->writeStartElement(LocationElementName);
153 
154  QString file = QDir::toNativeSeparators(error.errorPath[i].file);
155  mXmlWriter->writeAttribute(FilenameAttribute, XmlReport::quoteMessage(file));
156  mXmlWriter->writeAttribute(LineAttribute, QString::number(error.errorPath[i].line));
157  if (error.errorPath[i].column > 0)
158  mXmlWriter->writeAttribute(ColumnAttribute, QString::number(error.errorPath[i].column));
159  if (error.errorPath.count() > 1)
160  mXmlWriter->writeAttribute(InfoAttribute, XmlReport::quoteMessage(error.errorPath[i].info));
161 
162  mXmlWriter->writeEndElement();
163  }
164 
165  mXmlWriter->writeEndElement();
166 }
167 
168 QList<ErrorItem> XmlReportV2::read()
169 {
170  QList<ErrorItem> errors;
171  bool insideResults = false;
172  if (!mXmlReader) {
173  qDebug() << "You must Open() the file before reading it!";
174  return errors;
175  }
176  while (!mXmlReader->atEnd()) {
177  switch (mXmlReader->readNext()) {
178  case QXmlStreamReader::StartElement:
179  if (mXmlReader->name() == ResultElementName)
180  insideResults = true;
181 
182  // Read error element from inside result element
183  if (insideResults && mXmlReader->name() == ErrorElementName) {
185  errors.append(item);
186  }
187  break;
188 
189  case QXmlStreamReader::EndElement:
190  if (mXmlReader->name() == ResultElementName)
191  insideResults = false;
192  break;
193 
194  // Not handled
195  case QXmlStreamReader::NoToken:
196  case QXmlStreamReader::Invalid:
197  case QXmlStreamReader::StartDocument:
198  case QXmlStreamReader::EndDocument:
199  case QXmlStreamReader::Characters:
200  case QXmlStreamReader::Comment:
201  case QXmlStreamReader::DTD:
202  case QXmlStreamReader::EntityReference:
203  case QXmlStreamReader::ProcessingInstruction:
204  break;
205  }
206  }
207  return errors;
208 }
209 
210 ErrorItem XmlReportV2::readError(const QXmlStreamReader *reader)
211 {
212  /*
213  Error example from the core program in xml
214  <error id="mismatchAllocDealloc" severity="error" msg="Mismatching allocation and deallocation: k"
215  verbose="Mismatching allocation and deallocation: k">
216  <location file="..\..\test\test.cxx" line="16"/>
217  <location file="..\..\test\test.cxx" line="32"/>
218  </error>
219  */
220 
221  ErrorItem item;
222 
223  // Read error element from inside errors element
224  if (mXmlReader->name() == ErrorElementName) {
225  QXmlStreamAttributes attribs = reader->attributes();
226  item.errorId = attribs.value(QString(), IdAttribute).toString();
227  item.severity = GuiSeverity::fromString(attribs.value(QString(), SeverityAttribute).toString());
228  const QString summary = attribs.value(QString(), MsgAttribute).toString();
229  item.summary = XmlReport::unquoteMessage(summary);
230  const QString message = attribs.value(QString(), VerboseAttribute).toString();
231  item.message = XmlReport::unquoteMessage(message);
232  if (attribs.hasAttribute(QString(), InconclusiveAttribute))
233  item.inconclusive = true;
234  if (attribs.hasAttribute(QString(), CWEAttribute))
235  item.cwe = attribs.value(QString(), CWEAttribute).toInt();
236  if (attribs.hasAttribute(QString(), HashAttribute))
237  item.hash = attribs.value(QString(), HashAttribute).toULongLong();
238  if (attribs.hasAttribute(QString(), IncludedFromFilenameAttribute))
239  item.file0 = attribs.value(QString(), IncludedFromFilenameAttribute).toString();
240  if (attribs.hasAttribute(QString(), SinceDateAttribute))
241  item.sinceDate = attribs.value(QString(), SinceDateAttribute).toString();
242  if (attribs.hasAttribute(QString(), TagsAttribute))
243  item.tags = attribs.value(QString(), TagsAttribute).toString();
244  }
245 
246  bool errorRead = false;
247  while (!errorRead && !mXmlReader->atEnd()) {
248  switch (mXmlReader->readNext()) {
249  case QXmlStreamReader::StartElement:
250 
251  // Read location element from inside error element
252  if (mXmlReader->name() == LocationElementName) {
253  QXmlStreamAttributes attribs = mXmlReader->attributes();
254  QString file0 = attribs.value(QString(), IncludedFromFilenameAttribute).toString();
255  if (!file0.isEmpty())
256  item.file0 = XmlReport::unquoteMessage(file0);
257  QErrorPathItem loc;
258  loc.file = XmlReport::unquoteMessage(attribs.value(QString(), FilenameAttribute).toString());
259  loc.line = attribs.value(QString(), LineAttribute).toString().toUInt();
260  if (attribs.hasAttribute(QString(), ColumnAttribute))
261  loc.column = attribs.value(QString(), ColumnAttribute).toString().toInt();
262  if (attribs.hasAttribute(QString(), InfoAttribute))
263  loc.info = XmlReport::unquoteMessage(attribs.value(QString(), InfoAttribute).toString());
264  item.errorPath.push_front(loc);
265  }
266  break;
267 
268  case QXmlStreamReader::EndElement:
269  if (mXmlReader->name() == ErrorElementName)
270  errorRead = true;
271  break;
272 
273  // Not handled
274  case QXmlStreamReader::NoToken:
275  case QXmlStreamReader::Invalid:
276  case QXmlStreamReader::StartDocument:
277  case QXmlStreamReader::EndDocument:
278  case QXmlStreamReader::Characters:
279  case QXmlStreamReader::Comment:
280  case QXmlStreamReader::DTD:
281  case QXmlStreamReader::EntityReference:
282  case QXmlStreamReader::ProcessingInstruction:
283  break;
284  }
285  }
286 
287  if (item.errorPath.size() == 1 && item.errorPath[0].info.isEmpty())
288  item.errorPath[0].info = item.message;
289 
290  return item;
291 }
static const char * version()
Returns current version number as a string.
Definition: cppcheck.cpp:354
A class containing error data for one error.
Definition: erroritem.h:72
bool inconclusive
Definition: erroritem.h:87
QString file0
Definition: erroritem.h:84
int cwe
Definition: erroritem.h:90
QString summary
Definition: erroritem.h:88
Severity severity
Definition: erroritem.h:86
unsigned long long hash
Definition: erroritem.h:91
QString message
Definition: erroritem.h:89
QList< QErrorPathItem > errorPath
Definition: erroritem.h:92
QString sinceDate
Definition: erroritem.h:96
QString tags
Definition: erroritem.h:97
QString errorId
Definition: erroritem.h:85
static QString toString(Severity severity)
Definition: erroritem.h:40
static Severity fromString(const QString &severity)
Definition: erroritem.h:44
A class containing data for one error path item.
Definition: erroritem.h:52
QString file
Definition: erroritem.h:56
QString info
Definition: erroritem.h:59
QFile * getFile()
Get the file object where the report is written to.
Definition: report.cpp:60
virtual bool open()
Open the existing report (file).
Definition: report.cpp:44
virtual bool create()
Create the report (file).
Definition: report.cpp:34
static std::pair< std::string, std::string > getNameAndVersion(const std::string &productName)
Definition: settings.cpp:159
const QString mProductName
Product name read from cppcheck.cfg.
Definition: xmlreportv2.h:86
ErrorItem readError(const QXmlStreamReader *reader)
Read and parse error item from XML stream.
void writeFooter() override
Write report footer.
QXmlStreamReader * mXmlReader
XML stream reader for reading the report in XML format.
Definition: xmlreportv2.h:91
void writeError(const ErrorItem &error) override
Write error to report.
XmlReportV2(const QString &filename, QString productName)
Definition: xmlreportv2.cpp:62
QXmlStreamWriter * mXmlWriter
XML stream writer for writing the report in XML format.
Definition: xmlreportv2.h:96
QList< ErrorItem > read() override
Read contents of the report file.
bool create() override
Create the report (file).
Definition: xmlreportv2.cpp:75
bool open() override
Open existing report file.
Definition: xmlreportv2.cpp:84
void writeHeader() override
Write report header.
Definition: xmlreportv2.cpp:93
~XmlReportV2() override
Definition: xmlreportv2.cpp:69
Base class for XML report classes.
Definition: xmlreport.h:36
static QString quoteMessage(const QString &message)
Quote the message.
Definition: xmlreport.cpp:39
static QString unquoteMessage(const QString &message)
Unquote the message.
Definition: xmlreport.cpp:50
std::string toString(Color c)
Definition: color.cpp:54
@ error
Programming error.
static const QString SeverityAttribute
Definition: xmlreportv2.cpp:56
static const QString FilenameAttribute
Definition: xmlreportv2.cpp:49
static const QString InfoAttribute
Definition: xmlreportv2.cpp:52
static const QString LocationElementName
Definition: xmlreportv2.cpp:44
static const QString ResultElementName
Definition: xmlreportv2.cpp:40
static const QString MsgAttribute
Definition: xmlreportv2.cpp:57
static const QString ProductNameAttribute
Definition: xmlreportv2.cpp:59
static const QString CWEAttribute
Definition: xmlreportv2.cpp:45
static const QString ErrorsElementName
Definition: xmlreportv2.cpp:43
static const QString SinceDateAttribute
Definition: xmlreportv2.cpp:47
static const QString VerboseAttribute
Definition: xmlreportv2.cpp:60
static const QString VersionAttribute
Definition: xmlreportv2.cpp:58
static const QString LineAttribute
Definition: xmlreportv2.cpp:53
static const QString IdAttribute
Definition: xmlreportv2.cpp:55
static const QString TagsAttribute
Definition: xmlreportv2.cpp:48
static const QString HashAttribute
Definition: xmlreportv2.cpp:46
static const QString ColumnAttribute
Definition: xmlreportv2.cpp:54
static const QString IncludedFromFilenameAttribute
Definition: xmlreportv2.cpp:50
static const QString CppcheckElementName
Definition: xmlreportv2.cpp:41
static const QString InconclusiveAttribute
Definition: xmlreportv2.cpp:51
static const QString ErrorElementName
Definition: xmlreportv2.cpp:42