Cppcheck
xmlreportv1.cpp
Go to the documentation of this file.
00001 /*
00002  * Cppcheck - A tool for static C/C++ code analysis
00003  * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team.
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation, either version 3 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include <QObject>
00020 #include <QString>
00021 #include <QList>
00022 #include <QDir>
00023 #include <QXmlStreamWriter>
00024 #include <QDebug>
00025 #include "report.h"
00026 #include "erroritem.h"
00027 #include "xmlreport.h"
00028 #include "xmlreportv1.h"
00029 
00030 static const char ResultElementName[] = "results";
00031 static const char ErrorElementName[] = "error";
00032 static const char FilenameAttribute[] = "file";
00033 static const char LineAttribute[] = "line";
00034 static const char IdAttribute[] = "id";
00035 static const char SeverityAttribute[] = "severity";
00036 static const char MsgAttribute[] = "msg";
00037 
00038 XmlReportV1::XmlReportV1(const QString &filename) :
00039     XmlReport(filename),
00040     mXmlReader(NULL),
00041     mXmlWriter(NULL)
00042 {
00043 }
00044 
00045 XmlReportV1::~XmlReportV1()
00046 {
00047     delete mXmlReader;
00048     delete mXmlWriter;
00049 }
00050 
00051 bool XmlReportV1::Create()
00052 {
00053     if (Report::Create()) {
00054         mXmlWriter = new QXmlStreamWriter(Report::GetFile());
00055         return true;
00056     }
00057     return false;
00058 }
00059 
00060 bool XmlReportV1::Open()
00061 {
00062     if (Report::Open()) {
00063         mXmlReader = new QXmlStreamReader(Report::GetFile());
00064         return true;
00065     }
00066     return false;
00067 }
00068 
00069 void XmlReportV1::WriteHeader()
00070 {
00071     mXmlWriter->setAutoFormatting(true);
00072     mXmlWriter->writeStartDocument();
00073     mXmlWriter->writeStartElement(ResultElementName);
00074 }
00075 
00076 void XmlReportV1::WriteFooter()
00077 {
00078     mXmlWriter->writeEndElement();
00079     mXmlWriter->writeEndDocument();
00080 }
00081 
00082 void XmlReportV1::WriteError(const ErrorItem &error)
00083 {
00084     /*
00085     Error example from the core program in xml
00086     <error file="gui/test.cpp" line="14" id="mismatchAllocDealloc" severity="error" msg="Mismatching allocation and deallocation: k"/>
00087     The callstack seems to be ignored here as well, instead last item of the stack is used
00088     */
00089 
00090     // Don't write inconclusive errors to XML V1
00091     if (error.inconclusive)
00092         return;
00093 
00094     mXmlWriter->writeStartElement(ErrorElementName);
00095     QString file = QDir::toNativeSeparators(error.files[error.files.size() - 1]);
00096     file = XmlReport::quoteMessage(file);
00097     mXmlWriter->writeAttribute(FilenameAttribute, file);
00098     const QString line = QString::number(error.lines[error.lines.size() - 1]);
00099     mXmlWriter->writeAttribute(LineAttribute, line);
00100     mXmlWriter->writeAttribute(IdAttribute, error.errorId);
00101 
00102     // Don't localize severity so we can read these files
00103     mXmlWriter->writeAttribute(SeverityAttribute, GuiSeverity::toString(error.severity));
00104     const QString message = XmlReport::quoteMessage(error.message);
00105     mXmlWriter->writeAttribute(MsgAttribute, message);
00106     mXmlWriter->writeEndElement();
00107 }
00108 
00109 QList<ErrorItem> XmlReportV1::Read()
00110 {
00111     QList<ErrorItem> errors;
00112     bool insideResults = false;
00113     if (!mXmlReader) {
00114         qDebug() << "You must Open() the file before reading it!";
00115         return errors;
00116     }
00117     while (!mXmlReader->atEnd()) {
00118         switch (mXmlReader->readNext()) {
00119         case QXmlStreamReader::StartElement:
00120             if (mXmlReader->name() == ResultElementName)
00121                 insideResults = true;
00122 
00123             // Read error element from inside result element
00124             if (insideResults && mXmlReader->name() == ErrorElementName) {
00125                 ErrorItem item = ReadError(mXmlReader);
00126                 errors.append(item);
00127             }
00128             break;
00129 
00130         case QXmlStreamReader::EndElement:
00131             if (mXmlReader->name() == ResultElementName)
00132                 insideResults = false;
00133             break;
00134 
00135             // Not handled
00136         case QXmlStreamReader::NoToken:
00137         case QXmlStreamReader::Invalid:
00138         case QXmlStreamReader::StartDocument:
00139         case QXmlStreamReader::EndDocument:
00140         case QXmlStreamReader::Characters:
00141         case QXmlStreamReader::Comment:
00142         case QXmlStreamReader::DTD:
00143         case QXmlStreamReader::EntityReference:
00144         case QXmlStreamReader::ProcessingInstruction:
00145             break;
00146         }
00147     }
00148     return errors;
00149 }
00150 
00151 ErrorItem XmlReportV1::ReadError(QXmlStreamReader *reader)
00152 {
00153     ErrorItem item;
00154     if (reader->name().toString() == ErrorElementName) {
00155         QXmlStreamAttributes attribs = reader->attributes();
00156         QString file = attribs.value("", FilenameAttribute).toString();
00157         file = XmlReport::unquoteMessage(file);
00158         item.file = file;
00159         item.files.push_back(file);
00160         const int line = attribs.value("", LineAttribute).toString().toUInt();
00161         item.lines.push_back(line);
00162         item.errorId = attribs.value("", IdAttribute).toString();
00163         item.severity = GuiSeverity::fromString(attribs.value("", SeverityAttribute).toString());
00164 
00165         // NOTE: This duplicates the message to Summary-field. But since
00166         // old XML format doesn't have separate summary and verbose messages
00167         // we must add same message to both data so it shows up in GUI.
00168         // Check if there is full stop and cut the summary to it.
00169         QString summary = attribs.value("", MsgAttribute).toString();
00170         const int ind = summary.indexOf('.');
00171         if (ind != -1)
00172             summary = summary.left(ind + 1);
00173         item.summary = XmlReport::unquoteMessage(summary);
00174         QString message = attribs.value("", MsgAttribute).toString();
00175         item.message = XmlReport::unquoteMessage(message);
00176     }
00177     return item;
00178 }