Cppcheck
xmlreportv2.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 "xmlreportv2.h"
00029 #include "cppcheck.h"
00030 
00031 static const char ResultElementName[] = "results";
00032 static const char CppcheckElementName[] = "cppcheck";
00033 static const char ErrorElementName[] = "error";
00034 static const char ErrorsElementName[] = "errors";
00035 static const char LocationElementName[] = "location";
00036 static const char FilenameAttribute[] = "file";
00037 static const char LineAttribute[] = "line";
00038 static const char IdAttribute[] = "id";
00039 static const char SeverityAttribute[] = "severity";
00040 static const char MsgAttribute[] = "msg";
00041 static const char VersionAttribute[] = "version";
00042 static const char VerboseAttribute[] = "verbose";
00043 
00044 XmlReportV2::XmlReportV2(const QString &filename) :
00045     XmlReport(filename),
00046     mXmlReader(NULL),
00047     mXmlWriter(NULL)
00048 {
00049 }
00050 
00051 XmlReportV2::~XmlReportV2()
00052 {
00053     delete mXmlReader;
00054     delete mXmlWriter;
00055 }
00056 
00057 bool XmlReportV2::Create()
00058 {
00059     if (Report::Create()) {
00060         mXmlWriter = new QXmlStreamWriter(Report::GetFile());
00061         return true;
00062     }
00063     return false;
00064 }
00065 
00066 bool XmlReportV2::Open()
00067 {
00068     if (Report::Open()) {
00069         mXmlReader = new QXmlStreamReader(Report::GetFile());
00070         return true;
00071     }
00072     return false;
00073 }
00074 
00075 void XmlReportV2::WriteHeader()
00076 {
00077     mXmlWriter->setAutoFormatting(true);
00078     mXmlWriter->writeStartDocument();
00079     mXmlWriter->writeStartElement(ResultElementName);
00080     mXmlWriter->writeAttribute(VersionAttribute, QString::number(2));
00081     mXmlWriter->writeStartElement(CppcheckElementName);
00082     mXmlWriter->writeAttribute(VersionAttribute, QString(CppCheck::version()));
00083     mXmlWriter->writeEndElement();
00084     mXmlWriter->writeStartElement(ErrorsElementName);
00085 }
00086 
00087 void XmlReportV2::WriteFooter()
00088 {
00089     mXmlWriter->writeEndElement(); // errors
00090     mXmlWriter->writeEndElement(); // results
00091     mXmlWriter->writeEndDocument();
00092 }
00093 
00094 void XmlReportV2::WriteError(const ErrorItem &error)
00095 {
00096     /*
00097     Error example from the core program in xml
00098     <error id="mismatchAllocDealloc" severity="error" msg="Mismatching allocation and deallocation: k"
00099               verbose="Mismatching allocation and deallocation: k">
00100       <location file="..\..\test\test.cxx" line="16"/>
00101       <location file="..\..\test\test.cxx" line="32"/>
00102     </error>
00103     */
00104 
00105     // Don't write inconclusive errors to XML V2 until we decide the format
00106     if (error.inconclusive)
00107         return;
00108 
00109     mXmlWriter->writeStartElement(ErrorElementName);
00110     mXmlWriter->writeAttribute(IdAttribute, error.errorId);
00111 
00112     // Don't localize severity so we can read these files
00113     mXmlWriter->writeAttribute(SeverityAttribute, GuiSeverity::toString(error.severity));
00114     const QString summary = XmlReport::quoteMessage(error.summary);
00115     mXmlWriter->writeAttribute(MsgAttribute, summary);
00116     const QString message = XmlReport::quoteMessage(error.message);
00117     mXmlWriter->writeAttribute(VerboseAttribute, message);
00118 
00119     for (int i = 0; i < error.files.count(); i++) {
00120         mXmlWriter->writeStartElement(LocationElementName);
00121 
00122         QString file = QDir::toNativeSeparators(error.files[i]);
00123         file = XmlReport::quoteMessage(file);
00124         mXmlWriter->writeAttribute(FilenameAttribute, file);
00125         const QString line = QString::number(error.lines[i]);
00126         mXmlWriter->writeAttribute(LineAttribute, line);
00127 
00128         mXmlWriter->writeEndElement();
00129     }
00130 
00131     mXmlWriter->writeEndElement();
00132 }
00133 
00134 QList<ErrorItem> XmlReportV2::Read()
00135 {
00136     QList<ErrorItem> errors;
00137     bool insideResults = false;
00138     if (!mXmlReader) {
00139         qDebug() << "You must Open() the file before reading it!";
00140         return errors;
00141     }
00142     while (!mXmlReader->atEnd()) {
00143         switch (mXmlReader->readNext()) {
00144         case QXmlStreamReader::StartElement:
00145             if (mXmlReader->name() == ResultElementName)
00146                 insideResults = true;
00147 
00148             // Read error element from inside result element
00149             if (insideResults && mXmlReader->name() == ErrorElementName) {
00150                 ErrorItem item = ReadError(mXmlReader);
00151                 errors.append(item);
00152             }
00153             break;
00154 
00155         case QXmlStreamReader::EndElement:
00156             if (mXmlReader->name() == ResultElementName)
00157                 insideResults = false;
00158             break;
00159 
00160             // Not handled
00161         case QXmlStreamReader::NoToken:
00162         case QXmlStreamReader::Invalid:
00163         case QXmlStreamReader::StartDocument:
00164         case QXmlStreamReader::EndDocument:
00165         case QXmlStreamReader::Characters:
00166         case QXmlStreamReader::Comment:
00167         case QXmlStreamReader::DTD:
00168         case QXmlStreamReader::EntityReference:
00169         case QXmlStreamReader::ProcessingInstruction:
00170             break;
00171         }
00172     }
00173     return errors;
00174 }
00175 
00176 ErrorItem XmlReportV2::ReadError(QXmlStreamReader *reader)
00177 {
00178     /*
00179     Error example from the core program in xml
00180     <error id="mismatchAllocDealloc" severity="error" msg="Mismatching allocation and deallocation: k"
00181               verbose="Mismatching allocation and deallocation: k">
00182       <location file="..\..\test\test.cxx" line="16"/>
00183       <location file="..\..\test\test.cxx" line="32"/>
00184     </error>
00185     */
00186 
00187     ErrorItem item;
00188 
00189     // Read error element from inside errors element
00190     if (mXmlReader->name() == ErrorElementName) {
00191         QXmlStreamAttributes attribs = reader->attributes();
00192         item.errorId = attribs.value("", IdAttribute).toString();
00193         item.severity = GuiSeverity::fromString(attribs.value("", SeverityAttribute).toString());
00194         const QString summary = attribs.value("", MsgAttribute).toString();
00195         item.summary = XmlReport::unquoteMessage(summary);
00196         const QString message = attribs.value("", VerboseAttribute).toString();
00197         item.message = XmlReport::unquoteMessage(message);
00198     }
00199 
00200     bool errorRead = false;
00201     while (!errorRead && !mXmlReader->atEnd()) {
00202         switch (mXmlReader->readNext()) {
00203         case QXmlStreamReader::StartElement:
00204 
00205             // Read location element from inside error element
00206             if (mXmlReader->name() == LocationElementName) {
00207                 QXmlStreamAttributes attribs = mXmlReader->attributes();
00208                 QString file = attribs.value("", FilenameAttribute).toString();
00209                 file = XmlReport::unquoteMessage(file);
00210                 if (item.file.isEmpty())
00211                     item.file = file;
00212                 item.files.push_back(file);
00213                 const int line = attribs.value("", LineAttribute).toString().toUInt();
00214                 item.lines.push_back(line);
00215             }
00216             break;
00217 
00218         case QXmlStreamReader::EndElement:
00219             if (mXmlReader->name() == ErrorElementName)
00220                 errorRead = true;
00221             break;
00222 
00223             // Not handled
00224         case QXmlStreamReader::NoToken:
00225         case QXmlStreamReader::Invalid:
00226         case QXmlStreamReader::StartDocument:
00227         case QXmlStreamReader::EndDocument:
00228         case QXmlStreamReader::Characters:
00229         case QXmlStreamReader::Comment:
00230         case QXmlStreamReader::DTD:
00231         case QXmlStreamReader::EntityReference:
00232         case QXmlStreamReader::ProcessingInstruction:
00233             break;
00234         }
00235     }
00236     return item;
00237 }