Verification; Updated report
This commit is contained in:
parent
147cf9319f
commit
4b4f7ea60b
|
@ -192,6 +192,8 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
|
|||
// Experimental: Verify
|
||||
else if (std::strcmp(argv[i], "--verify") == 0)
|
||||
mSettings->verification = true;
|
||||
else if (std::strcmp(argv[i], "--verify-report") == 0)
|
||||
mSettings->verification = mSettings->verificationReport = true;
|
||||
else if (std::strcmp(argv[i], "--debug-verify") == 0)
|
||||
mSettings->debugVerification = true;
|
||||
|
||||
|
|
|
@ -79,13 +79,14 @@
|
|||
/*static*/ FILE* CppCheckExecutor::mExceptionOutput = stdout;
|
||||
|
||||
CppCheckExecutor::CppCheckExecutor()
|
||||
: mSettings(nullptr), mLatestProgressOutputTime(0), mErrorOutput(nullptr), mShowAllErrors(false)
|
||||
: mSettings(nullptr), mLatestProgressOutputTime(0), mErrorOutput(nullptr), mVerificationOutput(nullptr), mShowAllErrors(false)
|
||||
{
|
||||
}
|
||||
|
||||
CppCheckExecutor::~CppCheckExecutor()
|
||||
{
|
||||
delete mErrorOutput;
|
||||
delete mVerificationOutput;
|
||||
}
|
||||
|
||||
bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* const argv[])
|
||||
|
@ -1063,6 +1064,13 @@ void CppCheckExecutor::reportErr(const ErrorLogger::ErrorMessage &msg)
|
|||
}
|
||||
}
|
||||
|
||||
void CppCheckExecutor::reportVerification(const std::string &str)
|
||||
{
|
||||
if (!mVerificationOutput)
|
||||
mVerificationOutput = new std::ofstream("verification-report.txt");
|
||||
(*mVerificationOutput) << str << std::endl;
|
||||
}
|
||||
|
||||
void CppCheckExecutor::setExceptionOutput(FILE* exceptionOutput)
|
||||
{
|
||||
mExceptionOutput = exceptionOutput;
|
||||
|
|
|
@ -81,6 +81,8 @@ public:
|
|||
*/
|
||||
void reportInfo(const ErrorLogger::ErrorMessage &msg) OVERRIDE;
|
||||
|
||||
void reportVerification(const std::string &str) OVERRIDE;
|
||||
|
||||
/**
|
||||
* Information about how many files have been checked
|
||||
*
|
||||
|
@ -187,6 +189,11 @@ private:
|
|||
*/
|
||||
std::ofstream *mErrorOutput;
|
||||
|
||||
/**
|
||||
* Verification report
|
||||
*/
|
||||
std::ostream *mVerificationOutput;
|
||||
|
||||
/**
|
||||
* Has --errorlist been given?
|
||||
*/
|
||||
|
|
|
@ -348,6 +348,11 @@ void ThreadExecutor::reportInfo(const ErrorLogger::ErrorMessage &msg)
|
|||
writeToPipe(REPORT_INFO, msg.serialize());
|
||||
}
|
||||
|
||||
void ThreadExecutor::reportVerification(const std::string &str)
|
||||
{
|
||||
writeToPipe(REPORT_VERIFICATION, str.c_str());
|
||||
}
|
||||
|
||||
#elif defined(THREADING_MODEL_WIN)
|
||||
|
||||
void ThreadExecutor::addFileContent(const std::string &path, const std::string &content)
|
||||
|
@ -490,7 +495,12 @@ void ThreadExecutor::reportErr(const ErrorLogger::ErrorMessage &msg)
|
|||
|
||||
void ThreadExecutor::reportInfo(const ErrorLogger::ErrorMessage &msg)
|
||||
{
|
||||
report(msg, MessageType::REPORT_INFO);
|
||||
|
||||
}
|
||||
|
||||
void ThreadExecutor::reportVerification(const std::string &/*str*/)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void ThreadExecutor::report(const ErrorLogger::ErrorMessage &msg, MessageType msgType)
|
||||
|
@ -551,4 +561,8 @@ void ThreadExecutor::reportInfo(const ErrorLogger::ErrorMessage &/*msg*/)
|
|||
|
||||
}
|
||||
|
||||
void ThreadExecutor::reportVerification(const std::string &/*str*/)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -54,6 +54,7 @@ public:
|
|||
void reportOut(const std::string &outmsg) OVERRIDE;
|
||||
void reportErr(const ErrorLogger::ErrorMessage &msg) OVERRIDE;
|
||||
void reportInfo(const ErrorLogger::ErrorMessage &msg) OVERRIDE;
|
||||
void reportVerification(const std::string &str) OVERRIDE;
|
||||
|
||||
/**
|
||||
* @brief Add content to a file, to be used in unit testing.
|
||||
|
@ -75,7 +76,7 @@ private:
|
|||
/** @brief Key is file name, and value is the content of the file */
|
||||
std::map<std::string, std::string> mFileContents;
|
||||
private:
|
||||
enum PipeSignal {REPORT_OUT='1',REPORT_ERROR='2', REPORT_INFO='3', CHILD_END='4'};
|
||||
enum PipeSignal {REPORT_OUT='1',REPORT_ERROR='2', REPORT_INFO='3', REPORT_VERIFICATION='4', CHILD_END='5'};
|
||||
|
||||
/**
|
||||
* Read from the pipe, parse and handle what ever is in there.
|
||||
|
|
|
@ -12,10 +12,11 @@ NewSuppressionDialog::NewSuppressionDialog(QWidget *parent) :
|
|||
|
||||
class QErrorLogger : public ErrorLogger {
|
||||
public:
|
||||
virtual void reportOut(const std::string &/*outmsg*/) {}
|
||||
virtual void reportErr(const ErrorLogger::ErrorMessage &msg) {
|
||||
void reportOut(const std::string &/*outmsg*/) override {}
|
||||
void reportErr(const ErrorLogger::ErrorMessage &msg) override {
|
||||
errorIds << QString::fromStdString(msg.id);
|
||||
}
|
||||
void reportVerification(const std::string &/*str*/) override {}
|
||||
QStringList errorIds;
|
||||
};
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ public:
|
|||
*/
|
||||
void reportOut(const std::string &outmsg) override;
|
||||
void reportErr(const ErrorLogger::ErrorMessage &msg) override;
|
||||
void reportVerification(const std::string &/*str*/) override {}
|
||||
|
||||
public slots:
|
||||
|
||||
|
|
|
@ -766,9 +766,8 @@ void CppCheck::checkNormalTokens(const Tokenizer &tokenizer)
|
|||
}
|
||||
|
||||
// Verification using ExprEngine..
|
||||
if (mSettings.verification) {
|
||||
if (mSettings.verification)
|
||||
ExprEngine::runChecks(this, &tokenizer, &mSettings);
|
||||
}
|
||||
|
||||
// Analyse the tokens..
|
||||
|
||||
|
@ -1202,6 +1201,11 @@ void CppCheck::reportStatus(unsigned int /*fileindex*/, unsigned int /*filecount
|
|||
|
||||
}
|
||||
|
||||
void CppCheck::reportVerification(const std::string &str)
|
||||
{
|
||||
mErrorLogger.reportVerification(str);
|
||||
}
|
||||
|
||||
void CppCheck::getErrorMessages()
|
||||
{
|
||||
Settings s(mSettings);
|
||||
|
|
|
@ -195,6 +195,8 @@ private:
|
|||
*/
|
||||
void reportOut(const std::string &outmsg) OVERRIDE;
|
||||
|
||||
void reportVerification(const std::string &str) OVERRIDE;
|
||||
|
||||
std::list<std::string> mErrorList;
|
||||
Settings mSettings;
|
||||
|
||||
|
|
|
@ -401,6 +401,8 @@ public:
|
|||
reportErr(msg);
|
||||
}
|
||||
|
||||
virtual void reportVerification(const std::string &str) = 0;
|
||||
|
||||
/**
|
||||
* Report unmatched suppressions
|
||||
* @param unmatched list of unmatched suppressions (from Settings::Suppressions::getUnmatched(Local|Global)Suppressions)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "exprengine.h"
|
||||
#include "astutils.h"
|
||||
#include "path.h"
|
||||
#include "settings.h"
|
||||
#include "symboldatabase.h"
|
||||
#include "tokenize.h"
|
||||
|
@ -1455,12 +1456,12 @@ static void execute(const Token *start, const Token *end, Data &data)
|
|||
}
|
||||
}
|
||||
|
||||
void ExprEngine::executeAllFunctions(const Tokenizer *tokenizer, const Settings *settings, const std::vector<ExprEngine::Callback> &callbacks, std::ostream &trace)
|
||||
void ExprEngine::executeAllFunctions(const Tokenizer *tokenizer, const Settings *settings, const std::vector<ExprEngine::Callback> &callbacks, std::ostream &report)
|
||||
{
|
||||
const SymbolDatabase *symbolDatabase = tokenizer->getSymbolDatabase();
|
||||
for (const Scope *functionScope : symbolDatabase->functionScopes) {
|
||||
try {
|
||||
executeFunction(functionScope, tokenizer, settings, callbacks, trace);
|
||||
executeFunction(functionScope, tokenizer, settings, callbacks, report);
|
||||
} catch (const VerifyException &e) {
|
||||
// FIXME.. there should not be exceptions
|
||||
std::string functionName = functionScope->function->name();
|
||||
|
@ -1549,7 +1550,7 @@ static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data)
|
|||
return ExprEngine::ValuePtr();
|
||||
}
|
||||
|
||||
void ExprEngine::executeFunction(const Scope *functionScope, const Tokenizer *tokenizer, const Settings *settings, const std::vector<ExprEngine::Callback> &callbacks, std::ostream &trace)
|
||||
void ExprEngine::executeFunction(const Scope *functionScope, const Tokenizer *tokenizer, const Settings *settings, const std::vector<ExprEngine::Callback> &callbacks, std::ostream &report)
|
||||
{
|
||||
if (!functionScope->bodyStart)
|
||||
return;
|
||||
|
@ -1576,14 +1577,24 @@ void ExprEngine::executeFunction(const Scope *functionScope, const Tokenizer *to
|
|||
call(callbacks, tok, bailoutValue, &data);
|
||||
}
|
||||
|
||||
if (settings->debugVerification) {
|
||||
// TODO generate better output!!
|
||||
trackExecution.print(trace);
|
||||
if (settings->debugVerification && !trackExecution.isAllOk()) {
|
||||
if (settings->verificationReport)
|
||||
report << "[debug]" << std::endl;
|
||||
trackExecution.print(report);
|
||||
if (settings->verificationReport)
|
||||
report << "[details]" << std::endl;
|
||||
trackExecution.report(report, functionScope);
|
||||
}
|
||||
|
||||
// Write a verification report
|
||||
//if (!trackExecution.isAllOk())
|
||||
// trackExecution.report(trace, functionScope);
|
||||
if (settings->verificationReport) {
|
||||
report << "[function-report] "
|
||||
<< Path::stripDirectoryPart(tokenizer->list.getFiles().at(functionScope->bodyStart->fileIndex())) << ":"
|
||||
<< functionScope->bodyStart->linenr() << ":"
|
||||
<< function->name()
|
||||
<< (trackExecution.isAllOk() ? " is safe" : " is not safe")
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings)
|
||||
|
@ -1752,5 +1763,9 @@ void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer,
|
|||
#ifdef VERIFY_INTEGEROVERFLOW
|
||||
callbacks.push_back(integerOverflow);
|
||||
#endif
|
||||
ExprEngine::executeAllFunctions(tokenizer, settings, callbacks, std::cout);
|
||||
|
||||
std::ostringstream report;
|
||||
ExprEngine::executeAllFunctions(tokenizer, settings, callbacks, report);
|
||||
if (errorLogger && settings->verificationReport && !report.str().empty())
|
||||
errorLogger->reportVerification(report.str());
|
||||
}
|
||||
|
|
|
@ -297,8 +297,8 @@ namespace ExprEngine {
|
|||
typedef std::function<void(const Token *, const ExprEngine::Value &, ExprEngine::DataBase *)> Callback;
|
||||
|
||||
/** Execute all functions */
|
||||
void CPPCHECKLIB executeAllFunctions(const Tokenizer *tokenizer, const Settings *settings, const std::vector<Callback> &callbacks, std::ostream &trace);
|
||||
void executeFunction(const Scope *functionScope, const Tokenizer *tokenizer, const Settings *settings, const std::vector<Callback> &callbacks, std::ostream &trace);
|
||||
void CPPCHECKLIB executeAllFunctions(const Tokenizer *tokenizer, const Settings *settings, const std::vector<Callback> &callbacks, std::ostream &report);
|
||||
void executeFunction(const Scope *functionScope, const Tokenizer *tokenizer, const Settings *settings, const std::vector<Callback> &callbacks, std::ostream &report);
|
||||
|
||||
void runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings);
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ Settings::Settings()
|
|||
force(false),
|
||||
inconclusive(false),
|
||||
verification(false),
|
||||
verificationReport(false),
|
||||
debugVerification(false),
|
||||
inlineSuppressions(false),
|
||||
jobs(1),
|
||||
|
|
|
@ -191,6 +191,10 @@ public:
|
|||
/** @brief Enable verification analysis */
|
||||
bool verification;
|
||||
|
||||
/** @brief Generate verification report */
|
||||
bool verificationReport;
|
||||
|
||||
/** @brief Generate verification debug output */
|
||||
bool debugVerification;
|
||||
|
||||
/** @brief check unknown function return values */
|
||||
|
|
|
@ -37,8 +37,8 @@ private:
|
|||
public:
|
||||
std::list<std::string> id;
|
||||
|
||||
void reportOut(const std::string & /*outmsg*/) OVERRIDE {
|
||||
}
|
||||
void reportOut(const std::string & /*outmsg*/) OVERRIDE {}
|
||||
void reportVerification(const std::string & /*str*/) OVERRIDE {}
|
||||
|
||||
void reportErr(const ErrorLogger::ErrorMessage &msg) OVERRIDE {
|
||||
id.push_back(msg.id);
|
||||
|
|
|
@ -103,8 +103,8 @@ private:
|
|||
};
|
||||
std::vector<ExprEngine::Callback> callbacks;
|
||||
callbacks.push_back(f);
|
||||
std::ostringstream dummy;
|
||||
ExprEngine::executeAllFunctions(&tokenizer, &settings, callbacks, dummy);
|
||||
std::ostringstream trace;
|
||||
ExprEngine::executeAllFunctions(&tokenizer, &settings, callbacks, trace);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -126,8 +126,8 @@ private:
|
|||
};
|
||||
std::vector<ExprEngine::Callback> callbacks;
|
||||
callbacks.push_back(f);
|
||||
std::ostringstream dummy;
|
||||
ExprEngine::executeAllFunctions(&tokenizer, &settings, callbacks, dummy);
|
||||
std::ostringstream trace;
|
||||
ExprEngine::executeAllFunctions(&tokenizer, &settings, callbacks, trace);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -139,9 +139,9 @@ private:
|
|||
Tokenizer tokenizer(&settings, this);
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize(istr, "test.cpp");
|
||||
std::vector<ExprEngine::Callback> dummy;
|
||||
std::vector<ExprEngine::Callback> callbacks;
|
||||
std::ostringstream ret;
|
||||
ExprEngine::executeAllFunctions(&tokenizer, &settings, dummy, ret);
|
||||
ExprEngine::executeAllFunctions(&tokenizer, &settings, callbacks, ret);
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ protected:
|
|||
|
||||
void processOptions(const options& args);
|
||||
public:
|
||||
void reportVerification(const std::string &/*str*/) OVERRIDE {}
|
||||
void reportOut(const std::string &outmsg) OVERRIDE;
|
||||
void reportErr(const ErrorLogger::ErrorMessage &msg) OVERRIDE;
|
||||
void run(const std::string &str);
|
||||
|
|
Loading…
Reference in New Issue