Cppcheck
cppchecklibrarydata.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 "cppchecklibrarydata.h"
20 
21 #include "utils.h"
22 
23 #include <stdexcept>
24 #include <string>
25 
26 #include <QObject>
27 #include <QVariant>
28 #include <QXmlStreamAttributes>
29 #include <QXmlStreamReader>
30 #include <QXmlStreamWriter>
31 #include <QtGlobal>
32 
33 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
34 #include <QStringRef>
35 #endif
36 
37 const unsigned int CppcheckLibraryData::Function::Arg::ANY = ~0U;
38 const unsigned int CppcheckLibraryData::Function::Arg::VARIADIC = ~1U;
39 
40 static std::string unhandledElement(const QXmlStreamReader &xmlReader)
41 {
42  throw std::runtime_error(QObject::tr("line %1: Unhandled element %2").arg(xmlReader.lineNumber()).arg(xmlReader.name().toString()).toStdString());
43 }
44 
45 static std::string mandatoryAttibuteMissing(const QXmlStreamReader &xmlReader, const QString& attributeName)
46 {
47  throw std::runtime_error(QObject::tr("line %1: Mandatory attribute '%2' missing in '%3'")
48  .arg(xmlReader.lineNumber())
49  .arg(attributeName)
50  .arg(xmlReader.name().toString()).toStdString());
51 }
52 
53 static CppcheckLibraryData::Container loadContainer(QXmlStreamReader &xmlReader)
54 {
56  container.id = xmlReader.attributes().value("id").toString();
57  container.inherits = xmlReader.attributes().value("inherits").toString();
58  container.startPattern = xmlReader.attributes().value("startPattern").toString();
59  container.endPattern = xmlReader.attributes().value("endPattern").toString();
60  container.opLessAllowed = xmlReader.attributes().value("opLessAllowed").toString();
61  container.itEndPattern = xmlReader.attributes().value("itEndPattern").toString();
62 
63  QXmlStreamReader::TokenType type;
64  while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
65  xmlReader.name().toString() != "container") {
66  if (type != QXmlStreamReader::StartElement)
67  continue;
68  const QString elementName = xmlReader.name().toString();
69  if (elementName == "type") {
70  container.type.templateParameter = xmlReader.attributes().value("templateParameter").toString();
71  container.type.string = xmlReader.attributes().value("string").toString();
72  } else if (elementName == "size" || elementName == "access" || elementName == "other" || elementName == "rangeItemRecordType") {
73  const QString indexOperator = xmlReader.attributes().value("indexOperator").toString();
74  if (elementName == "access" && indexOperator == "array-like")
75  container.access_arrayLike = true;
76  const QString templateParameter = xmlReader.attributes().value("templateParameter").toString();
77  if (elementName == "size" && !templateParameter.isEmpty())
78  container.size_templateParameter = templateParameter.toInt();
79  for (;;) {
80  type = xmlReader.readNext();
81  if (xmlReader.name().toString() == elementName)
82  break;
83  if (type != QXmlStreamReader::StartElement)
84  continue;
86  function.name = xmlReader.attributes().value("name").toString();
87  function.action = xmlReader.attributes().value("action").toString();
88  function.yields = xmlReader.attributes().value("yields").toString();
89  if (elementName == "size")
90  container.sizeFunctions.append(function);
91  else if (elementName == "access")
92  container.accessFunctions.append(function);
93  else if (elementName == "rangeItemRecordType") {
95  rangeItemRecordType.name = xmlReader.attributes().value("name").toString();
96  rangeItemRecordType.templateParameter = xmlReader.attributes().value("templateParameter").toString();
97  container.rangeItemRecordTypeList.append(rangeItemRecordType);
98  } else
99  container.otherFunctions.append(function);
100  }
101  } else {
102  unhandledElement(xmlReader);
103  }
104  }
105  return container;
106 }
107 
108 static CppcheckLibraryData::Define loadDefine(const QXmlStreamReader &xmlReader)
109 {
111  define.name = xmlReader.attributes().value("name").toString();
112  define.value = xmlReader.attributes().value("value").toString();
113  return define;
114 }
115 
116 static QString loadUndefine(const QXmlStreamReader &xmlReader)
117 {
118  return xmlReader.attributes().value("name").toString();
119 }
120 
121 static CppcheckLibraryData::SmartPointer loadSmartPointer(QXmlStreamReader &xmlReader)
122 {
124  smartPointer.name = xmlReader.attributes().value("class-name").toString();
125  QXmlStreamReader::TokenType type;
126  while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
127  xmlReader.name().toString() != "smart-pointer") {
128  if (type != QXmlStreamReader::StartElement)
129  continue;
130  const QString elementName = xmlReader.name().toString();
131  if (elementName == "unique") {
132  smartPointer.unique = true;
133  } else {
134  unhandledElement(xmlReader);
135  }
136  }
137  return smartPointer;
138 }
139 
140 static CppcheckLibraryData::TypeChecks loadTypeChecks(QXmlStreamReader &xmlReader)
141 {
143  QXmlStreamReader::TokenType type;
144  while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
145  xmlReader.name().toString() != "type-checks") {
146  if (type != QXmlStreamReader::StartElement)
147  continue;
148  const QString elementName = xmlReader.name().toString();
149  if (elementName == "suppress" || elementName == "check") {
150  QPair<QString, QString> entry(elementName, xmlReader.readElementText());
151  typeChecks.append(entry);
152  }
153  }
154  return typeChecks;
155 }
156 
157 static CppcheckLibraryData::Function::Arg loadFunctionArg(QXmlStreamReader &xmlReader)
158 {
160  QString argnr = xmlReader.attributes().value("nr").toString();
161  if (argnr == "any")
163  else if (argnr == "variadic")
165  else
166  arg.nr = argnr.toUInt();
167  arg.defaultValue = xmlReader.attributes().value("default").toString();
168 
169  QXmlStreamReader::TokenType type;
170  while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
171  xmlReader.name().toString() != "arg") {
172  if (type != QXmlStreamReader::StartElement)
173  continue;
174  const QString elementName = xmlReader.name().toString();
175  if (elementName == "not-bool")
176  arg.notbool = true;
177  else if (elementName == "not-null")
178  arg.notnull = true;
179  else if (elementName == "not-uninit")
180  arg.notuninit = true;
181  else if (elementName == "strz")
182  arg.strz = true;
183  else if (elementName == "formatstr")
184  arg.formatstr = true;
185  else if (elementName == "valid")
186  arg.valid = xmlReader.readElementText();
187  else if (elementName == "minsize") {
189  minsize.type = xmlReader.attributes().value("type").toString();
190  minsize.arg = xmlReader.attributes().value("arg").toString();
191  minsize.arg2 = xmlReader.attributes().value("arg2").toString();
192  arg.minsizes.append(minsize);
193  } else if (elementName == "iterator") {
194  arg.iterator.container = xmlReader.attributes().value("container").toInt();
195  arg.iterator.type = xmlReader.attributes().value("type").toString();
196  } else {
197  unhandledElement(xmlReader);
198  }
199  }
200  return arg;
201 }
202 
203 static CppcheckLibraryData::Function loadFunction(QXmlStreamReader &xmlReader, const QString &comments)
204 {
206  function.comments = comments;
207  function.name = xmlReader.attributes().value("name").toString();
208  QXmlStreamReader::TokenType type;
209  while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
210  xmlReader.name().toString() != "function") {
211  if (type != QXmlStreamReader::StartElement)
212  continue;
213  const QString elementName = xmlReader.name().toString();
214  if (elementName == "noreturn")
215  function.noreturn = (xmlReader.readElementText() == "true") ? CppcheckLibraryData::Function::True : CppcheckLibraryData::Function::False;
216  else if (elementName == "pure")
217  function.gccPure = true;
218  else if (elementName == "const")
219  function.gccConst = true;
220  else if (elementName == "leak-ignore")
221  function.leakignore = true;
222  else if (elementName == "use-retval")
223  function.useretval = true;
224  else if (elementName == "returnValue") {
225  const QString container = xmlReader.attributes().value("container").toString();
226  function.returnValue.container = container.isNull() ? -1 : container.toInt();
227  function.returnValue.type = xmlReader.attributes().value("type").toString();
228  function.returnValue.value = xmlReader.readElementText();
229  } else if (elementName == "formatstr") {
230  function.formatstr.scan = xmlReader.attributes().value("scan").toString();
231  function.formatstr.secure = xmlReader.attributes().value("secure").toString();
232  } else if (elementName == "arg")
233  function.args.append(loadFunctionArg(xmlReader));
234  else if (elementName == "warn") {
235  function.warn.severity = xmlReader.attributes().value("severity").toString();
236  function.warn.cstd = xmlReader.attributes().value("cstd").toString();
237  function.warn.reason = xmlReader.attributes().value("reason").toString();
238  function.warn.alternatives = xmlReader.attributes().value("alternatives").toString();
239  function.warn.msg = xmlReader.readElementText();
240  } else if (elementName == "not-overlapping-data") {
241  const QStringList attributeList {"ptr1-arg", "ptr2-arg", "size-arg", "strlen-arg"};
242  for (const QString &attr : attributeList) {
243  if (xmlReader.attributes().hasAttribute(attr)) {
244  function.notOverlappingDataArgs[attr] = xmlReader.attributes().value(attr).toString();
245  }
246  }
247  } else if (elementName == "container") {
248  const QStringList attributeList {"action", "yields"};
249  for (const QString &attr : attributeList) {
250  if (xmlReader.attributes().hasAttribute(attr)) {
251  function.containerAttributes[attr] = xmlReader.attributes().value(attr).toString();
252  }
253  }
254  } else {
255  unhandledElement(xmlReader);
256  }
257  }
258  return function;
259 }
260 
261 static CppcheckLibraryData::MemoryResource loadMemoryResource(QXmlStreamReader &xmlReader)
262 {
264  memoryresource.type = xmlReader.name().toString();
265  QXmlStreamReader::TokenType type;
266  while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
267  xmlReader.name().toString() != memoryresource.type) {
268  if (type != QXmlStreamReader::StartElement)
269  continue;
270  const QString elementName = xmlReader.name().toString();
271  if (elementName == "alloc" || elementName == "realloc") {
273  alloc.isRealloc = (elementName == "realloc");
274  alloc.init = (xmlReader.attributes().value("init").toString() == "true");
275  if (xmlReader.attributes().hasAttribute("arg")) {
276  alloc.arg = xmlReader.attributes().value("arg").toInt();
277  }
278  if (alloc.isRealloc && xmlReader.attributes().hasAttribute("realloc-arg")) {
279  alloc.reallocArg = xmlReader.attributes().value("realloc-arg").toInt();
280  }
281  if (memoryresource.type == "memory") {
282  alloc.bufferSize = xmlReader.attributes().value("buffer-size").toString();
283  }
284  alloc.name = xmlReader.readElementText();
285  memoryresource.alloc.append(alloc);
286  } else if (elementName == "dealloc") {
288  if (xmlReader.attributes().hasAttribute("arg")) {
289  dealloc.arg = xmlReader.attributes().value("arg").toInt();
290  }
291  dealloc.name = xmlReader.readElementText();
292  memoryresource.dealloc.append(dealloc);
293  } else if (elementName == "use")
294  memoryresource.use.append(xmlReader.readElementText());
295  else
296  unhandledElement(xmlReader);
297  }
298  return memoryresource;
299 }
300 
301 static CppcheckLibraryData::PodType loadPodType(const QXmlStreamReader &xmlReader)
302 {
304  podtype.name = xmlReader.attributes().value("name").toString();
305  if (podtype.name.isEmpty()) {
306  mandatoryAttibuteMissing(xmlReader, "name");
307  }
308  podtype.stdtype = xmlReader.attributes().value("stdtype").toString();
309  podtype.size = xmlReader.attributes().value("size").toString();
310  podtype.sign = xmlReader.attributes().value("sign").toString();
311  return podtype;
312 }
313 
314 static CppcheckLibraryData::PlatformType loadPlatformType(QXmlStreamReader &xmlReader)
315 {
317  platformType.name = xmlReader.attributes().value("name").toString();
318  platformType.value = xmlReader.attributes().value("value").toString();
319 
320  QXmlStreamReader::TokenType type;
321  while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
322  xmlReader.name().toString() != "platformtype") {
323  if (type != QXmlStreamReader::StartElement)
324  continue;
325  const QString elementName = xmlReader.name().toString();
326  if (QStringList({"unsigned", "long", "pointer", "const_ptr", "ptr_ptr"}).contains(elementName)) {
327  platformType.types.append(elementName);
328  } else if (elementName == "platform") {
329  platformType.platforms.append(xmlReader.attributes().value("type").toString());
330  } else {
331  unhandledElement(xmlReader);
332  }
333  }
334  return platformType;
335 }
336 
337 static CppcheckLibraryData::Reflection loadReflection(QXmlStreamReader &xmlReader)
338 {
340 
341  QXmlStreamReader::TokenType type;
342  while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
343  xmlReader.name().toString() != "reflection") {
344  if (type != QXmlStreamReader::StartElement)
345  continue;
346  const QString elementName = xmlReader.name().toString();
347  if (elementName == "call") {
349  if (xmlReader.attributes().hasAttribute("arg")) {
350  call.arg = xmlReader.attributes().value("arg").toInt();
351  } else {
352  mandatoryAttibuteMissing(xmlReader, "arg");
353  }
354  call.name = xmlReader.readElementText();
355  reflection.calls.append(call);
356  } else {
357  unhandledElement(xmlReader);
358  }
359  }
360 
361  return reflection;
362 }
363 
364 static CppcheckLibraryData::Markup loadMarkup(QXmlStreamReader &xmlReader)
365 {
367 
368  QXmlStreamReader::TokenType type;
369  if (xmlReader.attributes().hasAttribute("ext")) {
370  markup.ext = xmlReader.attributes().value("ext").toString();
371  } else {
372  mandatoryAttibuteMissing(xmlReader, "ext");
373  }
374  if (xmlReader.attributes().hasAttribute("aftercode")) {
375  markup.afterCode = (xmlReader.attributes().value("aftercode") == QString("true"));
376  } else {
377  mandatoryAttibuteMissing(xmlReader, "aftercode");
378  }
379  if (xmlReader.attributes().hasAttribute("reporterrors")) {
380  markup.reportErrors = (xmlReader.attributes().value("reporterrors") == QString("true"));
381  } else {
382  mandatoryAttibuteMissing(xmlReader, "reporterrors");
383  }
384 
385  while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
386  xmlReader.name().toString() != "markup") {
387  if (type != QXmlStreamReader::StartElement)
388  continue;
389  const QString elementName = xmlReader.name().toString();
390  if (elementName == "keywords") {
391  while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
392  xmlReader.name().toString() != "keywords") {
393  if (type != QXmlStreamReader::StartElement)
394  continue;
395  if (xmlReader.name().toString() == "keyword") {
396  markup.keywords.append(xmlReader.attributes().value("name").toString());
397  } else {
398  unhandledElement(xmlReader);
399  }
400  }
401  } else if (elementName == "codeblocks") {
403 
404  while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
405  xmlReader.name().toString() != "codeblocks") {
406  if (type != QXmlStreamReader::StartElement)
407  continue;
408  if (xmlReader.name().toString() == "block") {
409  codeBlock.blocks.append(xmlReader.attributes().value("name").toString());
410  } else if (xmlReader.name().toString() == "structure") {
411  codeBlock.offset = xmlReader.attributes().value("offset").toInt();
412  codeBlock.start = xmlReader.attributes().value("start").toString();
413  codeBlock.end = xmlReader.attributes().value("end").toString();
414  } else {
415  unhandledElement(xmlReader);
416  }
417  }
418  markup.codeBlocks.append(codeBlock);
419  } else if (elementName == "exported") {
421 
422  while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
423  xmlReader.name().toString() != "exported") {
424  if (type != QXmlStreamReader::StartElement)
425  continue;
426  if (xmlReader.name().toString() == "exporter") {
427  exporter.prefix = xmlReader.attributes().value("prefix").toString();
428  } else if (xmlReader.name().toString() == "prefix") {
429  exporter.prefixList.append(xmlReader.readElementText());
430  } else if (xmlReader.name().toString() == "suffix") {
431  exporter.suffixList.append(xmlReader.readElementText());
432  } else {
433  unhandledElement(xmlReader);
434  }
435  }
436  markup.exporter.append(exporter);
437  } else if (elementName == "imported") {
438  while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
439  xmlReader.name().toString() != "imported") {
440  if (type != QXmlStreamReader::StartElement)
441  continue;
442  if (xmlReader.name().toString() == "importer") {
443  markup.importer.append(xmlReader.readElementText());
444  } else {
445  unhandledElement(xmlReader);
446  }
447  }
448  } else {
449  unhandledElement(xmlReader);
450  }
451  }
452 
453  return markup;
454 }
455 
456 static CppcheckLibraryData::Entrypoint loadEntrypoint(const QXmlStreamReader &xmlReader)
457 {
459  entrypoint.name = xmlReader.attributes().value("name").toString();
460  return entrypoint;
461 }
462 
463 QString CppcheckLibraryData::open(QIODevice &file)
464 {
465  clear();
466  QString comments;
467  QXmlStreamReader xmlReader(&file);
468  while (!xmlReader.atEnd()) {
469  const QXmlStreamReader::TokenType t = xmlReader.readNext();
470  switch (t) {
471  case QXmlStreamReader::Comment:
472  if (!comments.isEmpty())
473  comments += "\n";
474  comments += xmlReader.text().toString();
475  break;
476  case QXmlStreamReader::StartElement:
477  try {
478  const QString elementName(xmlReader.name().toString());
479  if (elementName == "def")
480  ;
481  else if (elementName == "container")
482  containers.append(loadContainer(xmlReader));
483  else if (elementName == "define")
484  defines.append(loadDefine(xmlReader));
485  else if (elementName == "undefine")
486  undefines.append(loadUndefine(xmlReader));
487  else if (elementName == "function")
488  functions.append(loadFunction(xmlReader, comments));
489  else if (elementName == "memory" || elementName == "resource")
490  memoryresource.append(loadMemoryResource(xmlReader));
491  else if (elementName == "podtype")
492  podtypes.append(loadPodType(xmlReader));
493  else if (elementName == "smart-pointer")
494  smartPointers.append(loadSmartPointer(xmlReader));
495  else if (elementName == "type-checks")
496  typeChecks.append(loadTypeChecks(xmlReader));
497  else if (elementName == "platformtype")
498  platformTypes.append(loadPlatformType(xmlReader));
499  else if (elementName == "reflection")
500  reflections.append(loadReflection(xmlReader));
501  else if (elementName == "markup")
502  markups.append(loadMarkup(xmlReader));
503  else if (elementName == "entrypoint")
504  entrypoints.append(loadEntrypoint(xmlReader));
505  else
506  unhandledElement(xmlReader);
507  } catch (std::runtime_error &e) {
508  return e.what();
509  }
510  comments.clear();
511  break;
512  default:
513  break;
514  }
515  }
516  if (xmlReader.hasError())
517  return xmlReader.errorString();
518  return QString();
519 }
520 
521 static void writeContainerFunctions(QXmlStreamWriter &xmlWriter, const QString &name, int extra, const QList<CppcheckLibraryData::Container::Function> &functions)
522 {
523  if (functions.isEmpty() && extra < 0)
524  return;
525  xmlWriter.writeStartElement(name);
526  if (extra >= 0) {
527  if (name == "access")
528  xmlWriter.writeAttribute("indexOperator", "array-like");
529  else if (name == "size")
530  xmlWriter.writeAttribute("templateParameter", QString::number(extra));
531  }
532  for (const CppcheckLibraryData::Container::Function &function : functions) {
533  xmlWriter.writeStartElement("function");
534  xmlWriter.writeAttribute("name", function.name);
535  if (!function.action.isEmpty())
536  xmlWriter.writeAttribute("action", function.action);
537  if (!function.yields.isEmpty())
538  xmlWriter.writeAttribute("yields", function.yields);
539  xmlWriter.writeEndElement();
540  }
541  xmlWriter.writeEndElement();
542 }
543 
544 static void writeContainerRangeItemRecords(QXmlStreamWriter &xmlWriter, const QList<CppcheckLibraryData::Container::RangeItemRecordType> &rangeItemRecords)
545 {
546  if (rangeItemRecords.isEmpty())
547  return;
548  xmlWriter.writeStartElement("rangeItemRecordType");
549  for (const CppcheckLibraryData::Container::RangeItemRecordType &item : rangeItemRecords) {
550  xmlWriter.writeStartElement("member");
551  xmlWriter.writeAttribute("name", item.name);
552  xmlWriter.writeAttribute("templateParameter", item.templateParameter);
553  xmlWriter.writeEndElement();
554  }
555  xmlWriter.writeEndElement();
556 }
557 
558 static void writeContainer(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Container &container)
559 {
560  xmlWriter.writeStartElement("container");
561  xmlWriter.writeAttribute("id", container.id);
562  if (!container.startPattern.isEmpty())
563  xmlWriter.writeAttribute("startPattern", container.startPattern);
564  if (!container.endPattern.isNull())
565  xmlWriter.writeAttribute("endPattern", container.endPattern);
566  if (!container.inherits.isEmpty())
567  xmlWriter.writeAttribute("inherits", container.inherits);
568  if (!container.opLessAllowed.isEmpty())
569  xmlWriter.writeAttribute("opLessAllowed", container.opLessAllowed);
570  if (!container.itEndPattern.isEmpty())
571  xmlWriter.writeAttribute("itEndPattern", container.itEndPattern);
572 
573  if (!container.type.templateParameter.isEmpty() || !container.type.string.isEmpty()) {
574  xmlWriter.writeStartElement("type");
575  if (!container.type.templateParameter.isEmpty())
576  xmlWriter.writeAttribute("templateParameter", container.type.templateParameter);
577  if (!container.type.string.isEmpty())
578  xmlWriter.writeAttribute("string", container.type.string);
579  xmlWriter.writeEndElement();
580  }
581  writeContainerFunctions(xmlWriter, "size", container.size_templateParameter, container.sizeFunctions);
582  writeContainerFunctions(xmlWriter, "access", container.access_arrayLike?1:-1, container.accessFunctions);
583  writeContainerFunctions(xmlWriter, "other", -1, container.otherFunctions);
585  xmlWriter.writeEndElement();
586 }
587 
588 static void writeFunction(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Function &function)
589 {
590  QString comments = function.comments;
591  while (comments.startsWith("\n"))
592  comments = comments.mid(1);
593  while (comments.endsWith("\n"))
594  comments.chop(1);
595  for (const QString &comment : comments.split('\n')) {
596  if (comment.length() >= 1)
597  xmlWriter.writeComment(comment);
598  }
599 
600  xmlWriter.writeStartElement("function");
601  xmlWriter.writeAttribute("name", function.name);
602 
603  if (function.useretval)
604  xmlWriter.writeEmptyElement("use-retval");
605  if (function.gccConst)
606  xmlWriter.writeEmptyElement("const");
607  if (function.gccPure)
608  xmlWriter.writeEmptyElement("pure");
609  if (!function.returnValue.empty()) {
610  xmlWriter.writeStartElement("returnValue");
611  if (!function.returnValue.type.isNull())
612  xmlWriter.writeAttribute("type", function.returnValue.type);
613  if (function.returnValue.container >= 0)
614  xmlWriter.writeAttribute("container", QString::number(function.returnValue.container));
615  if (!function.returnValue.value.isNull())
616  xmlWriter.writeCharacters(function.returnValue.value);
617  xmlWriter.writeEndElement();
618  }
619  if (function.noreturn != CppcheckLibraryData::Function::Unknown)
620  xmlWriter.writeTextElement("noreturn", bool_to_string(function.noreturn == CppcheckLibraryData::Function::True));
621  if (function.leakignore)
622  xmlWriter.writeEmptyElement("leak-ignore");
623  // Argument info..
624  for (const CppcheckLibraryData::Function::Arg &arg : function.args) {
625  if (arg.formatstr) {
626  xmlWriter.writeStartElement("formatstr");
627  if (!function.formatstr.scan.isNull())
628  xmlWriter.writeAttribute("scan", function.formatstr.scan);
629  if (!function.formatstr.secure.isNull())
630  xmlWriter.writeAttribute("secure", function.formatstr.secure);
631  xmlWriter.writeEndElement();
632  }
633 
634  xmlWriter.writeStartElement("arg");
636  xmlWriter.writeAttribute("nr", "any");
638  xmlWriter.writeAttribute("nr", "variadic");
639  else
640  xmlWriter.writeAttribute("nr", QString::number(arg.nr));
641  if (!arg.defaultValue.isNull())
642  xmlWriter.writeAttribute("default", arg.defaultValue);
643  if (arg.formatstr)
644  xmlWriter.writeEmptyElement("formatstr");
645  if (arg.notnull)
646  xmlWriter.writeEmptyElement("not-null");
647  if (arg.notuninit)
648  xmlWriter.writeEmptyElement("not-uninit");
649  if (arg.notbool)
650  xmlWriter.writeEmptyElement("not-bool");
651  if (arg.strz)
652  xmlWriter.writeEmptyElement("strz");
653 
654  if (!arg.valid.isEmpty())
655  xmlWriter.writeTextElement("valid",arg.valid);
656 
657  for (const CppcheckLibraryData::Function::Arg::MinSize &minsize : arg.minsizes) {
658  xmlWriter.writeStartElement("minsize");
659  xmlWriter.writeAttribute("type", minsize.type);
660  xmlWriter.writeAttribute("arg", minsize.arg);
661  if (!minsize.arg2.isEmpty())
662  xmlWriter.writeAttribute("arg2", minsize.arg2);
663  xmlWriter.writeEndElement();
664  }
665 
666  if (arg.iterator.container >= 0 || !arg.iterator.type.isNull()) {
667  xmlWriter.writeStartElement("iterator");
668  if (arg.iterator.container >= 0)
669  xmlWriter.writeAttribute("container", QString::number(arg.iterator.container));
670  if (!arg.iterator.type.isNull())
671  xmlWriter.writeAttribute("type", arg.iterator.type);
672  xmlWriter.writeEndElement();
673  }
674 
675  xmlWriter.writeEndElement();
676  }
677 
678  if (!function.warn.isEmpty()) {
679  xmlWriter.writeStartElement("warn");
680 
681  if (!function.warn.severity.isEmpty())
682  xmlWriter.writeAttribute("severity", function.warn.severity);
683 
684  if (!function.warn.cstd.isEmpty())
685  xmlWriter.writeAttribute("cstd", function.warn.cstd);
686 
687  if (!function.warn.alternatives.isEmpty())
688  xmlWriter.writeAttribute("alternatives", function.warn.alternatives);
689 
690  if (!function.warn.reason.isEmpty())
691  xmlWriter.writeAttribute("reason", function.warn.reason);
692 
693  if (!function.warn.msg.isEmpty())
694  xmlWriter.writeCharacters(function.warn.msg);
695 
696  xmlWriter.writeEndElement();
697  }
698  if (!function.notOverlappingDataArgs.isEmpty()) {
699  xmlWriter.writeStartElement("not-overlapping-data");
700  foreach (const QString& value, function.notOverlappingDataArgs) {
701  xmlWriter.writeAttribute(function.notOverlappingDataArgs.key(value), value);
702  }
703  xmlWriter.writeEndElement();
704  }
705  if (!function.containerAttributes.isEmpty()) {
706  xmlWriter.writeStartElement("container");
707  foreach (const QString& value, function.containerAttributes) {
708  xmlWriter.writeAttribute(function.containerAttributes.key(value), value);
709  }
710  xmlWriter.writeEndElement();
711  }
712  xmlWriter.writeEndElement();
713 }
714 
715 static void writeMemoryResource(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::MemoryResource &mr)
716 {
717  xmlWriter.writeStartElement(mr.type);
718  for (const CppcheckLibraryData::MemoryResource::Alloc &alloc : mr.alloc) {
719  if (alloc.isRealloc) {
720  xmlWriter.writeStartElement("realloc");
721  } else {
722  xmlWriter.writeStartElement("alloc");
723  }
724  xmlWriter.writeAttribute("init", bool_to_string(alloc.init));
725  if (alloc.arg != -1) {
726  xmlWriter.writeAttribute("arg", QString("%1").arg(alloc.arg));
727  }
728  if (alloc.isRealloc && alloc.reallocArg != -1) {
729  xmlWriter.writeAttribute("realloc-arg", QString("%1").arg(alloc.reallocArg));
730  }
731  if (mr.type == "memory" && !alloc.bufferSize.isEmpty()) {
732  xmlWriter.writeAttribute("buffer-size", alloc.bufferSize);
733  }
734  xmlWriter.writeCharacters(alloc.name);
735  xmlWriter.writeEndElement();
736  }
737 
738  for (const CppcheckLibraryData::MemoryResource::Dealloc &dealloc : mr.dealloc) {
739  xmlWriter.writeStartElement("dealloc");
740  if (dealloc.arg != -1) {
741  xmlWriter.writeAttribute("arg", QString("%1").arg(dealloc.arg));
742  }
743  xmlWriter.writeCharacters(dealloc.name);
744  xmlWriter.writeEndElement();
745  }
746 
747  for (const QString &use : mr.use) {
748  xmlWriter.writeTextElement("use", use);
749  }
750  xmlWriter.writeEndElement();
751 }
752 
753 static void writeTypeChecks(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::TypeChecks &typeChecks)
754 {
755  xmlWriter.writeStartElement("type-checks");
756  if (!typeChecks.isEmpty()) {
757  xmlWriter.writeStartElement("unusedvar");
758  }
759  for (const QPair<QString, QString> &check : typeChecks) {
760  xmlWriter.writeStartElement(check.first);
761  xmlWriter.writeCharacters(check.second);
762  xmlWriter.writeEndElement();
763  }
764  if (!typeChecks.isEmpty()) {
765  xmlWriter.writeEndElement();
766  }
767  xmlWriter.writeEndElement();
768 }
769 
770 static void writePlatformType(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::PlatformType &pt)
771 {
772  xmlWriter.writeStartElement("platformtype");
773  xmlWriter.writeAttribute("name", pt.name);
774  xmlWriter.writeAttribute("value", pt.value);
775  for (const QString &type : pt.types) {
776  xmlWriter.writeStartElement(type);
777  xmlWriter.writeEndElement();
778  }
779  for (const QString &platform : pt.platforms) {
780  xmlWriter.writeStartElement("platform");
781  if (!platform.isEmpty()) {
782  xmlWriter.writeAttribute("type", platform);
783  }
784  xmlWriter.writeEndElement();
785  }
786  xmlWriter.writeEndElement();
787 }
788 
789 static void writeReflection(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Reflection &refl)
790 {
791  xmlWriter.writeStartElement("reflection");
792  for (const CppcheckLibraryData::Reflection::Call &call : refl.calls) {
793  xmlWriter.writeStartElement("call");
794  xmlWriter.writeAttribute("arg", QString("%1").arg(call.arg));
795  xmlWriter.writeCharacters(call.name);
796  xmlWriter.writeEndElement();
797  }
798  xmlWriter.writeEndElement();
799 }
800 
801 static void writeMarkup(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Markup &mup)
802 {
803  xmlWriter.writeStartElement("markup");
804  xmlWriter.writeAttribute("ext", mup.ext);
805  xmlWriter.writeAttribute("aftercode", QVariant(mup.afterCode).toString());
806  xmlWriter.writeAttribute("reporterrors", QVariant(mup.reportErrors).toString());
807  if (!mup.keywords.isEmpty()) {
808  xmlWriter.writeStartElement("keywords");
809  for (const QString &keyword : mup.keywords) {
810  xmlWriter.writeStartElement("keyword");
811  xmlWriter.writeAttribute("name", keyword);
812  xmlWriter.writeEndElement();
813  }
814  xmlWriter.writeEndElement();
815  }
816  if (!mup.importer.isEmpty()) {
817  xmlWriter.writeStartElement("imported");
818  for (const QString &import : mup.importer) {
819  xmlWriter.writeStartElement("importer");
820  xmlWriter.writeCharacters(import);
821  xmlWriter.writeEndElement();
822  }
823  xmlWriter.writeEndElement();
824  }
825  if (!mup.exporter.isEmpty()) {
826  xmlWriter.writeStartElement("exported");
827  for (const CppcheckLibraryData::Markup::Exporter &exporter : mup.exporter) {
828  xmlWriter.writeStartElement("exporter");
829  xmlWriter.writeAttribute("prefix", exporter.prefix);
830  for (const QString &prefix : exporter.prefixList) {
831  xmlWriter.writeStartElement("prefix");
832  xmlWriter.writeCharacters(prefix);
833  xmlWriter.writeEndElement();
834  }
835  for (const QString &suffix : exporter.suffixList) {
836  xmlWriter.writeStartElement("suffix");
837  xmlWriter.writeCharacters(suffix);
838  xmlWriter.writeEndElement();
839  }
840  xmlWriter.writeEndElement();
841  }
842  xmlWriter.writeEndElement();
843  }
844  if (!mup.codeBlocks.isEmpty()) {
845  for (const CppcheckLibraryData::Markup::CodeBlocks &codeblock : mup.codeBlocks) {
846  xmlWriter.writeStartElement("codeblocks");
847  for (const QString &block : codeblock.blocks) {
848  xmlWriter.writeStartElement("block");
849  xmlWriter.writeAttribute("name", block);
850  xmlWriter.writeEndElement();
851  }
852  xmlWriter.writeStartElement("structure");
853  xmlWriter.writeAttribute("offset", QString("%1").arg(codeblock.offset));
854  xmlWriter.writeAttribute("start", codeblock.start);
855  xmlWriter.writeAttribute("end", codeblock.end);
856  xmlWriter.writeEndElement();
857  xmlWriter.writeEndElement();
858  }
859  }
860  xmlWriter.writeEndElement();
861 }
862 
864 {
865  QString outputString;
866  QXmlStreamWriter xmlWriter(&outputString);
867  xmlWriter.setAutoFormatting(true);
868  xmlWriter.setAutoFormattingIndent(2);
869  xmlWriter.writeStartDocument("1.0");
870  xmlWriter.writeStartElement("def");
871  xmlWriter.writeAttribute("format","2");
872 
873  for (const Define &define : defines) {
874  xmlWriter.writeStartElement("define");
875  xmlWriter.writeAttribute("name", define.name);
876  xmlWriter.writeAttribute("value", define.value);
877  xmlWriter.writeEndElement();
878  }
879 
880  for (const QString &undef : undefines) {
881  xmlWriter.writeStartElement("undefine");
882  xmlWriter.writeAttribute("name", undef);
883  xmlWriter.writeEndElement();
884  }
885 
886  for (const Function &function : functions) {
887  writeFunction(xmlWriter, function);
888  }
889 
890  for (const MemoryResource &mr : memoryresource) {
891  writeMemoryResource(xmlWriter, mr);
892  }
893 
894  for (const Container &container : containers) {
895  writeContainer(xmlWriter, container);
896  }
897 
898  for (const PodType &podtype : podtypes) {
899  xmlWriter.writeStartElement("podtype");
900  xmlWriter.writeAttribute("name", podtype.name);
901  if (!podtype.stdtype.isEmpty())
902  xmlWriter.writeAttribute("stdtype", podtype.stdtype);
903  if (!podtype.sign.isEmpty())
904  xmlWriter.writeAttribute("sign", podtype.sign);
905  if (!podtype.size.isEmpty())
906  xmlWriter.writeAttribute("size", podtype.size);
907  xmlWriter.writeEndElement();
908  }
909 
910  for (const TypeChecks &check : typeChecks) {
911  writeTypeChecks(xmlWriter, check);
912  }
913 
914  for (const SmartPointer &smartPtr : smartPointers) {
915  xmlWriter.writeStartElement("smart-pointer");
916  xmlWriter.writeAttribute("class-name", smartPtr.name);
917  if (smartPtr.unique) {
918  xmlWriter.writeEmptyElement("unique");
919  }
920  xmlWriter.writeEndElement();
921  }
922 
923  for (const PlatformType &pt : platformTypes) {
924  writePlatformType(xmlWriter, pt);
925  }
926 
927  for (const Reflection &refl : reflections) {
928  writeReflection(xmlWriter, refl);
929  }
930 
931  for (const Markup &mup : markups) {
932  writeMarkup(xmlWriter, mup);
933  }
934 
935  for (const Entrypoint &ent : entrypoints) {
936  xmlWriter.writeStartElement("entrypoint");
937  xmlWriter.writeAttribute("name", ent.name);
938  xmlWriter.writeEndElement();
939  }
940 
941  xmlWriter.writeEndElement();
942 
943  return outputString;
944 }
QList< QPair< QString, QString > > TypeChecks
QList< PlatformType > platformTypes
QList< PodType > podtypes
QList< SmartPointer > smartPointers
QList< Container > containers
QString open(QIODevice &file)
QList< Function > functions
QList< TypeChecks > typeChecks
QList< Entrypoint > entrypoints
QList< MemoryResource > memoryresource
QList< Reflection > reflections
static CppcheckLibraryData::MemoryResource loadMemoryResource(QXmlStreamReader &xmlReader)
static void writeContainer(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Container &container)
static CppcheckLibraryData::Define loadDefine(const QXmlStreamReader &xmlReader)
static CppcheckLibraryData::Container loadContainer(QXmlStreamReader &xmlReader)
static CppcheckLibraryData::PodType loadPodType(const QXmlStreamReader &xmlReader)
static CppcheckLibraryData::Function::Arg loadFunctionArg(QXmlStreamReader &xmlReader)
static std::string mandatoryAttibuteMissing(const QXmlStreamReader &xmlReader, const QString &attributeName)
static std::string unhandledElement(const QXmlStreamReader &xmlReader)
static CppcheckLibraryData::TypeChecks loadTypeChecks(QXmlStreamReader &xmlReader)
static void writeContainerFunctions(QXmlStreamWriter &xmlWriter, const QString &name, int extra, const QList< CppcheckLibraryData::Container::Function > &functions)
static CppcheckLibraryData::Markup loadMarkup(QXmlStreamReader &xmlReader)
static void writeMarkup(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Markup &mup)
static CppcheckLibraryData::SmartPointer loadSmartPointer(QXmlStreamReader &xmlReader)
static CppcheckLibraryData::PlatformType loadPlatformType(QXmlStreamReader &xmlReader)
static void writePlatformType(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::PlatformType &pt)
static void writeMemoryResource(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::MemoryResource &mr)
static void writeContainerRangeItemRecords(QXmlStreamWriter &xmlWriter, const QList< CppcheckLibraryData::Container::RangeItemRecordType > &rangeItemRecords)
static void writeReflection(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Reflection &refl)
static void writeTypeChecks(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::TypeChecks &typeChecks)
static QString loadUndefine(const QXmlStreamReader &xmlReader)
static CppcheckLibraryData::Function loadFunction(QXmlStreamReader &xmlReader, const QString &comments)
static CppcheckLibraryData::Entrypoint loadEntrypoint(const QXmlStreamReader &xmlReader)
static void writeFunction(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Function &function)
static CppcheckLibraryData::Reflection loadReflection(QXmlStreamReader &xmlReader)
struct CppcheckLibraryData::Container::@0 type
QList< RangeItemRecordType > rangeItemRecordTypeList
static const unsigned int VARIADIC
struct CppcheckLibraryData::Function::Arg::Iterator iterator
static const char * bool_to_string(bool b)
Definition: utils.h:345
bool contains(const Range &r, const T &x)
Definition: utils.h:62