Verification; Updated report

This commit is contained in:
Daniel Marjamäki 2019-12-27 19:05:10 +01:00
parent 147cf9319f
commit 4b4f7ea60b
17 changed files with 89 additions and 26 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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?
*/

View File

@ -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

View File

@ -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.

View File

@ -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;
};

View File

@ -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:

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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());
}

View File

@ -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);
}

View File

@ -46,6 +46,7 @@ Settings::Settings()
force(false),
inconclusive(false),
verification(false),
verificationReport(false),
debugVerification(false),
inlineSuppressions(false),
jobs(1),

View File

@ -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 */

View File

@ -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);

View File

@ -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();
}

View File

@ -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);