50 #include <QRegularExpression> 
   52 #include <QTextStream> 
   55 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) 
   65     for (
const std::string &arg: args)
 
   66         args2 << QString::fromStdString(arg);
 
   69     process.start(QString::fromStdString(exe), args2);
 
   70     process.waitForFinished();
 
   72     if (redirect == 
"2>&1") {
 
   73         QString s1 = process.readAllStandardOutput();
 
   74         QString s2 = process.readAllStandardError();
 
   75         output = (s1 + 
"\n" + s2).toStdString();
 
   77         output = process.readAllStandardOutput().toStdString();
 
   80         std::ofstream fout(redirect.substr(3));
 
   81         fout << process.readAllStandardError().toStdString();
 
   83     return process.exitCode();
 
   89     mCppcheck(result, true, executeCommand)
 
  113         qDebug() << 
"Whole program analysis";
 
  114         std::list<FileWithDetails> files2;
 
  115         std::transform(
mFiles.cbegin(), 
mFiles.cend(), std::back_inserter(files2), [&](
const QString& file) {
 
  116             return FileWithDetails{file.toStdString(), 0};
 
  124     QString file = mResult.getNextFile();
 
  125     while (!file.isEmpty() && mState == Running) {
 
  126         qDebug() << 
"Checking file" << file;
 
  127         mCppcheck.check(file.toStdString());
 
  128         runAddonsAndTools(
nullptr, file);
 
  129         emit fileChecked(file);
 
  131         if (mState == Running)
 
  132             file = mResult.getNextFile();
 
  135     FileSettings fileSettings = mResult.getNextFileSettings();
 
  136     while (!fileSettings.
filename().empty() && mState == Running) {
 
  137         file = QString::fromStdString(fileSettings.
filename());
 
  138         qDebug() << 
"Checking file" << file;
 
  139         mCppcheck.check(fileSettings);
 
  140         runAddonsAndTools(&fileSettings, QString::fromStdString(fileSettings.
filename()));
 
  141         emit fileChecked(file);
 
  143         if (mState == Running)
 
  144             fileSettings = mResult.getNextFileSettings();
 
  147     if (mState == Running)
 
  166             for (std::list<std::string>::const_iterator incIt = fileSettings->
includePaths.cbegin(); incIt != fileSettings->
includePaths.cend(); ++incIt)
 
  167                 args << (
"-I" + QString::fromStdString(*incIt));
 
  169                 args << 
"-isystem" << QString::fromStdString(*i);
 
  170             for (
const QString& def : QString::fromStdString(fileSettings->
defines).split(
";")) {
 
  171                 args << (
"-D" + def);
 
  173             for (
const std::string& U : fileSettings->
undefs) {
 
  174                 args << QString::fromStdString(
"-U" + U);
 
  178             if (!clangPath.isEmpty()) {
 
  179                 QDir dir(clangPath + 
"/../lib/clang");
 
  180                 for (
const QString& ver : dir.entryList()) {
 
  181                     QString includePath = dir.absolutePath() + 
'/' + ver + 
"/include";
 
  182                     if (ver[0] != 
'.' && QDir(includePath).exists()) {
 
  183                         args << 
"-isystem" << includePath;
 
  194                 if (!includePath.isEmpty()) {
 
  195                     includePath.replace(
"\\", 
"/");
 
  196                     args << 
"-isystem" << includePath.trimmed();
 
  200             args << 
"-U__STDC__" << 
"-fno-ms-compatibility";
 
  203             if (!fileSettings->
standard.empty())
 
  204                 args << (
"-std=" + QString::fromStdString(fileSettings->
standard));
 
  209                     args << (
"-std=" + QString::fromStdString(std));
 
  213             QString analyzerInfoFile;
 
  216             if (!buildDir.empty()) {
 
  219                 QStringList args2(args);
 
  220                 args2.insert(0,
"-E");
 
  224                 process.waitForFinished();
 
  225                 const QByteArray &ba = process.readAllStandardOutput();
 
  226 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 
  227                 const quint16 chksum = qChecksum(QByteArrayView(ba));
 
  229                 const quint16 chksum = qChecksum(ba.data(), ba.length());
 
  232                 QFile f1(analyzerInfoFile + 
'.' + addon + 
"-E");
 
  233                 if (f1.open(QIODevice::ReadOnly | QIODevice::Text)) {
 
  234                     QTextStream in1(&f1);
 
  235                     const quint16 oldchksum = in1.readAll().toInt();
 
  236                     if (oldchksum == chksum) {
 
  237                         QFile f2(analyzerInfoFile + 
'.' + addon + 
"-results");
 
  238                         if (f2.open(QIODevice::ReadOnly | QIODevice::Text)) {
 
  239                             QTextStream in2(&f2);
 
  246                 f1.open(QIODevice::WriteOnly | QIODevice::Text);
 
  247                 QTextStream out1(&f1);
 
  250                 QFile::remove(analyzerInfoFile + 
'.' + addon + 
"-results");
 
  262                 args.insert(0,
"-checks=-*,clang-analyzer-*");
 
  263                 args.insert(1, fileName);
 
  264                 args.insert(2, 
"--");
 
  266                 args.insert(0,
"-checks=*,-clang-analyzer-*,-llvm*");
 
  267                 args.insert(1, fileName);
 
  268                 args.insert(2, 
"--");
 
  273                 QString 
debug(cmd.contains(
" ") ? (
'\"' + cmd + 
'\"') : cmd);
 
  274                 for (
const QString& arg : args) {
 
  275                     if (arg.contains(
" "))
 
  276                         debug += 
" \"" + arg + 
'\"';
 
  282                 if (!analyzerInfoFile.isEmpty()) {
 
  283                     QFile f(analyzerInfoFile + 
'.' + addon + 
"-cmd");
 
  284                     if (f.open(QIODevice::WriteOnly | QIODevice::Text)) {
 
  293             process.waitForFinished(600*1000);
 
  294             const QString errout(process.readAllStandardOutput() + 
"\n\n\n" + process.readAllStandardError());
 
  295             if (!analyzerInfoFile.isEmpty()) {
 
  296                 QFile f(analyzerInfoFile + 
'.' + addon + 
"-results");
 
  297                 if (f.open(QIODevice::WriteOnly | QIODevice::Text)) {
 
  316     QList<ErrorItem> errorItems;
 
  318     static const QRegularExpression r1(
"^(.+):([0-9]+):([0-9]+): (note|warning|error|fatal error): (.*)$");
 
  319     static const QRegularExpression r2(
"^(.*)\\[([a-zA-Z0-9\\-_\\.]+)\\]$");
 
  320     QTextStream in(&err, QIODevice::ReadOnly);
 
  321     while (!in.atEnd()) {
 
  322         QString line = in.readLine();
 
  324         if (line.startsWith(
"Assertion failed:")) {
 
  330             e.
errorId = tool + 
"-internal-error";
 
  334             errorItems.append(e);
 
  338         const QRegularExpressionMatch r1MatchRes = r1.match(line);
 
  339         if (!r1MatchRes.hasMatch())
 
  341         if (r1MatchRes.captured(4) != 
"note") {
 
  342             errorItems.append(errorItem);
 
  344             errorItem.
file0 = r1MatchRes.captured(1);
 
  348         errorItem.
errorPath.last().file = r1MatchRes.captured(1);
 
  349         errorItem.
errorPath.last().line = r1MatchRes.captured(2).toInt();
 
  350         errorItem.
errorPath.last().column = r1MatchRes.captured(3).toInt();
 
  351         if (r1MatchRes.captured(4) == 
"warning")
 
  353         else if (r1MatchRes.captured(4) == 
"error" || r1MatchRes.captured(4) == 
"fatal error")
 
  357         const QRegularExpressionMatch r2MatchRes = r2.match(r1MatchRes.captured(5));
 
  358         if (r2MatchRes.hasMatch()) {
 
  359             message = r2MatchRes.captured(1);
 
  360             const QString id1(r2MatchRes.captured(2));
 
  361             if (id1.startsWith(
"clang"))
 
  364                 id = tool + 
'-' + r2MatchRes.captured(2);
 
  366                 if (id1.startsWith(
"performance"))
 
  368                 else if (id1.startsWith(
"portability"))
 
  370                 else if (id1.startsWith(
"misc") && !id1.contains(
"unused"))
 
  376             message = r1MatchRes.captured(5);
 
  385         errorItem.
errorPath.last().info = message;
 
  387     errorItems.append(errorItem);
 
  390         if (e.errorPath.isEmpty())
 
  393         errorMessage.
setFileName(e.errorPath.back().file.toStdString());
 
  394         errorMessage.
lineNumber = e.errorPath.back().line;
 
  395         errorMessage.
errorId = e.errorId.toStdString();
 
  396         errorMessage.
symbolNames = e.symbolNames.toStdString();
 
  401         std::list<ErrorMessage::FileLocation> callstack;
 
  402         std::transform(e.errorPath.cbegin(), e.errorPath.cend(), std::back_inserter(callstack), [](
const QErrorPathItem& path) {
 
  403             return ErrorMessage::FileLocation(path.file.toStdString(), path.info.toStdString(), path.line, path.column);
 
  405         const std::string f0 = file0.toStdString();
 
  406         const std::string msg = e.message.toStdString();
 
  407         const std::string 
id = e.errorId.toStdString();
 
  416         return s.isSuppressed(errorMessage);
 
  431     process.start(path, QStringList() << 
"--version");
 
  432     process.waitForFinished();
 
  433     if (process.exitCode() == 0)
 
  438     if (QFileInfo(
"C:/Program Files/LLVM/bin/clang.exe").exists())
 
  439         return "C:/Program Files/LLVM/bin/clang.exe";
 
  450     path += 
"clang-tidy";
 
  456     process.start(path, QStringList() << 
"--version");
 
  457     process.waitForFinished();
 
  458     if (process.exitCode() == 0)
 
  463     if (QFileInfo(
"C:/Program Files/LLVM/bin/clang-tidy.exe").exists())
 
  464         return "C:/Program Files/LLVM/bin/clang-tidy.exe";
 
bool mAnalyseWholeProgram
 
static QString clangTidyCmd()
Determine command to run clang-tidy.
 
void parseClangErrors(const QString &tool, const QString &file0, QString err)
 
@ Running
The thread is checking.
 
@ Stopping
The thread will stop after current work.
 
void run() override
method that is run in a thread
 
void analyseWholeProgram(const QStringList &files)
Run whole program analysis.
 
CheckThread(ThreadResult &result)
 
QStringList mAddonsAndTools
 
CppCheck mCppcheck
Cppcheck itself.
 
void check(const Settings &settings)
Set settings for cppcheck.
 
void done()
cpp checking is done
 
static int executeCommand(std::string exe, std::vector< std::string > args, std::string redirect, std::string &output)
 
void runAddonsAndTools(const FileSettings *fileSettings, const QString &fileName)
 
QStringList mClangIncludePaths
 
QList< SuppressionList::Suppression > mSuppressions
 
bool isSuppressed(const SuppressionList::ErrorMessage &errorMessage) const
 
std::atomic< State > mState
Thread's current execution state.
 
static QString clangCmd()
Determine command to run clang.
 
bool analyseWholeProgram()
Analyse whole program, run this after all TUs has been scanned.
 
Settings & settings()
Get reference to current settings.
 
A class containing error data for one error.
 
QList< QErrorPathItem > errorPath
 
Wrapper for error messages, provided by reportErr()
 
A class containing data for one error path item.
 
This is just a container for general settings so that we don't need to pass individual values to func...
 
static void terminate(bool t=true)
Request termination of checking.
 
std::string buildDir
–cppcheck-build-dir.
 
Standards standards
Struct contains standards settings.
 
Threads use this class to obtain new files to process and to publish results.
 
void reportErr(const ErrorMessage &msg) override
Information about found errors and warnings is directed here.
 
@ portability
Portability warning.
 
@ information
Checking information.
 
@ performance
Performance warning.
 
@ error
Programming error.
 
#define SETTINGS_CLANG_PATH
 
const std::string & filename() const
 
std::set< std::string > undefs
 
std::list< std::string > includePaths
 
std::list< std::string > systemIncludePaths
 
std::string getCPP() const
 
void setFileName(std::string s)
 
bool startsWith(const std::string &str, const char start[], std::size_t startlen)