cppcheck/verify/mainwindow.cpp

149 lines
4.3 KiB
C++

/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2010 Daniel Marjamäki and Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "preprocessor.h"
#include "tokenize.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <set>
#include <QFileDialog>
static void arrayIndex(const Tokenizer &tokenizer, std::set<unsigned int> &errorlines);
static unsigned char readChar(std::istream &istr)
{
unsigned char ch = (unsigned char)istr.get();
// Handling of newlines..
if (ch == '\r')
{
ch = '\n';
if ((char)istr.peek() == '\n')
(void)istr.get();
}
return ch;
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->actionOpen, SIGNAL(triggered()), this, SLOT(open()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::open()
{
const std::string fileName = QFileDialog::getOpenFileName(this,
tr("Open File"),
"",
"cpp files (*.cpp)").toStdString();
if (fileName.empty())
return;
setWindowTitle(fileName.c_str());
Tokenizer tokenizer;
{
// Preprocess the file..
Preprocessor preprocessor;
std::ifstream fin(fileName.c_str());
std::string filedata;
std::list<std::string> configurations;
std::list<std::string> includePaths;
preprocessor.preprocess(fin,
filedata,
configurations,
fileName,
includePaths);
filedata = Preprocessor::getcode(filedata, "", fileName, NULL, NULL);
// Tokenize the preprocessed code..
std::istringstream istr(filedata);
tokenizer.tokenize(istr, fileName.c_str(), "");
}
// Check the tokens..
std::set<unsigned int> errorlines;
arrayIndex(tokenizer, errorlines);
// show report..
{
std::ostringstream report;
std::ifstream fin(fileName.c_str());
for (unsigned char c = readChar(fin); fin.good(); c = readChar(fin))
{
if (c & 0x80)
continue;
report << c;
}
ui->codeEditor->setPlainText(QString::fromStdString(report.str()));
QList<int> errorLines;
for (std::set<unsigned int>::const_iterator it = errorlines.begin(); it != errorlines.end(); ++it)
errorLines.push_back(*it);
ui->codeEditor->highlightErrors(errorLines);
}
}
/**
* Check that array indexes are within bounds
* 1. Locate array access through: [ .. ]
* 2. Try to determine if index is within bounds.
* 3. If it fails to determine that the index is within bounds then write warning
* \param tokenizer The tokenizer
* \param errout output stream to write warnings to
*/
static void arrayIndex(const Tokenizer &tokenizer, std::set<unsigned int> &errorlines)
{
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next())
{
// 1. Locate array access through: [ .. ]
if (tok->fileIndex() == 0 && tok->str() == "[")
{
// 2. try to determine if the array index is within bounds
// array declaration
if (Token::simpleMatch(tok, "[ ]"))
continue;
if (Token::Match(tok->tokAt(-2), "%type% %var% [ %num% ] ;|="))
continue;
// 3. If it fails to determine that the index is within bounds then write warning
errorlines.insert(tok->linenr());
}
}
}