Cppcheck
threadhandler.cpp
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2023 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "threadhandler.h"
20 
21 #include "checkthread.h"
22 #include "common.h"
23 #include "resultsview.h"
24 #include "settings.h"
25 
26 #include <string>
27 #include <unordered_set>
28 #include <utility>
29 
30 #include <QDebug>
31 #include <QFile>
32 #include <QFileInfo>
33 #include <QIODevice>
34 #include <QSettings>
35 #include <QTextStream>
36 #include <QVariant>
37 
38 ThreadHandler::ThreadHandler(QObject *parent) :
39  QObject(parent)
40 {
41  setThreadCount(1);
42 }
43 
45 {
46  removeThreads();
47 }
48 
50 {
51  mLastFiles.clear();
53  mAnalyseWholeProgram = false;
54  mAddonsAndTools.clear();
55  mSuppressions.clear();
56 }
57 
58 void ThreadHandler::setFiles(const QStringList &files)
59 {
60  mResults.setFiles(files);
61  mLastFiles = files;
62 }
63 
65 {
66  mResults.setProject(prj);
67  mLastFiles.clear();
68 }
69 
71 {
72  if (mRunningThreadCount == 0) {
74  }
75 }
76 
77 void ThreadHandler::setCheckFiles(const QStringList& files)
78 {
79  if (mRunningThreadCount == 0) {
80  mResults.setFiles(files);
81  }
82 }
83 
84 void ThreadHandler::check(const Settings &settings)
85 {
86  if (mResults.getFileCount() == 0 || mRunningThreadCount > 0 || settings.jobs == 0) {
87  qDebug() << "Can't start checking if there's no files to check or if check is in progress.";
88  emit done();
89  return;
90  }
91 
92  setThreadCount(settings.jobs);
93 
95 
98  }
99 
100  QStringList addonsAndTools = mAddonsAndTools;
101  for (const std::string& addon: settings.addons) {
102  QString s = QString::fromStdString(addon);
103  if (!addonsAndTools.contains(s))
104  addonsAndTools << s;
105  }
106 
107  for (int i = 0; i < mRunningThreadCount; i++) {
108  mThreads[i]->setAddonsAndTools(addonsAndTools);
109  mThreads[i]->setSuppressions(mSuppressions);
110  mThreads[i]->setClangIncludePaths(mClangIncludePaths);
111  mThreads[i]->check(settings);
112  }
113 
114  // Date and time when checking starts..
115  mCheckStartTime = QDateTime::currentDateTime();
116 
117  mAnalyseWholeProgram = true;
118 
119  mTimer.start();
120 }
121 
123 {
124  return mRunningThreadCount > 0;
125 }
126 
127 void ThreadHandler::setThreadCount(const int count)
128 {
129  if (mRunningThreadCount > 0 ||
130  count == mThreads.size() ||
131  count <= 0) {
132  return;
133  }
134 
135  //Remove unused old threads
136  removeThreads();
137  //Create new threads
138  for (int i = mThreads.size(); i < count; i++) {
139  mThreads << new CheckThread(mResults);
140  connect(mThreads.last(), &CheckThread::done,
142  connect(mThreads.last(), &CheckThread::fileChecked,
144  }
145 }
146 
147 
149 {
150  for (CheckThread* thread : mThreads) {
151  if (thread->isRunning()) {
152  thread->terminate();
153  thread->wait();
154  }
155  disconnect(thread, &CheckThread::done,
157  disconnect(thread, &CheckThread::fileChecked,
159  delete thread;
160  }
161 
162  mThreads.clear();
163  mAnalyseWholeProgram = false;
164 }
165 
167 {
169  mThreads[0]->analyseWholeProgram(mLastFiles);
170  mAnalyseWholeProgram = false;
171  return;
172  }
173 
175  if (mRunningThreadCount == 0) {
176  emit done();
177 
178  mScanDuration = mTimer.elapsed();
179 
180  // Set date/time used by the recheck
181  if (!mCheckStartTime.isNull()) {
183  mCheckStartTime = QDateTime();
184  }
185  }
186 }
187 
189 {
190  mCheckStartTime = QDateTime();
191  mAnalyseWholeProgram = false;
192  for (CheckThread* thread : mThreads) {
193  thread->stop();
194  }
195 }
196 
198 {
199  connect(&mResults, &ThreadResult::progress,
200  view, &ResultsView::progress);
201 
202  connect(&mResults, &ThreadResult::error,
203  view, &ResultsView::error);
204 
205  connect(&mResults, &ThreadResult::log,
206  this, &ThreadHandler::log);
207 
210 }
211 
212 void ThreadHandler::loadSettings(const QSettings &settings)
213 {
214  setThreadCount(settings.value(SETTINGS_CHECK_THREADS, 1).toInt());
215 }
216 
217 void ThreadHandler::saveSettings(QSettings &settings) const
218 {
219  settings.setValue(SETTINGS_CHECK_THREADS, mThreads.size());
220 }
221 
223 {
224  return !mLastFiles.isEmpty();
225 }
226 
228 {
229  return mLastFiles.size();
230 }
231 
233 {
234  return mScanDuration;
235 }
236 
237 QStringList ThreadHandler::getReCheckFiles(bool all) const
238 {
239  if (mLastCheckTime.isNull() || all)
240  return mLastFiles;
241 
242  std::set<QString> modified;
243  std::set<QString> unmodified;
244 
245  QStringList files;
246  for (int i = 0; i < mLastFiles.size(); ++i) {
247  if (needsReCheck(mLastFiles[i], modified, unmodified))
248  files.push_back(mLastFiles[i]);
249  }
250  return files;
251 }
252 
253 bool ThreadHandler::needsReCheck(const QString &filename, std::set<QString> &modified, std::set<QString> &unmodified) const
254 {
255  if (modified.find(filename) != modified.end())
256  return true;
257 
258  if (unmodified.find(filename) != unmodified.end())
259  return false;
260 
261  if (QFileInfo(filename).lastModified() > mLastCheckTime) {
262  return true;
263  }
264 
265  // Parse included files recursively
266  QFile f(filename);
267  if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
268  return false;
269 
270  // prevent recursion..
271  unmodified.insert(filename);
272 
273  QTextStream in(&f);
274  while (!in.atEnd()) {
275  QString line = in.readLine();
276  if (line.startsWith("#include \"")) {
277  line.remove(0,10);
278  const int i = line.indexOf("\"");
279  if (i > 0) {
280  line.remove(i,line.length());
281  line = QFileInfo(filename).absolutePath() + "/" + line;
282  if (needsReCheck(line, modified, unmodified)) {
283  modified.insert(std::move(line));
284  return true;
285  }
286  }
287  }
288  }
289 
290  return false;
291 }
292 
294 {
295  return mCheckStartTime;
296 }
297 
298 void ThreadHandler::setCheckStartTime(QDateTime checkStartTime)
299 {
300  mCheckStartTime = std::move(checkStartTime);
301 }
Thread to run cppcheck.
Definition: checkthread.h:47
void fileChecked(const QString &file)
void done()
cpp checking is done
Importing project settings.
Definition: importproject.h:52
Widget to show cppcheck progressbar and result.
Definition: resultsview.h:51
void progress(int value, const QString &description)
Slot for updating the checking progress.
void error(const ErrorItem &item)
Slot for new error to be displayed.
This is just a container for general settings so that we don't need to pass individual values to func...
Definition: settings.h:95
std::unordered_set< std::string > addons
addons, either filename of python/json file or json data
Definition: settings.h:109
unsigned int jobs
How many processes/threads should do checking at the same time.
Definition: settings.h:231
bool hasPreviousFiles() const
Have we checked files already?
void done()
Signal that all threads are done.
void check(const Settings &settings)
Start the threads to check the files.
QStringList mClangIncludePaths
bool needsReCheck(const QString &filename, std::set< QString > &modified, std::set< QString > &unmodified) const
Check if a file needs to be rechecked.
int mScanDuration
The previous scan duration in milliseconds.
QStringList mLastFiles
List of files checked last time (used when rechecking)
void removeThreads()
Function to delete all threads.
bool mAnalyseWholeProgram
void threadDone()
Slot that a single thread is done.
QDateTime getCheckStartTime() const
Get start time of last check.
QList< SuppressionList::Suppression > mSuppressions
QStringList mAddonsAndTools
void saveSettings(QSettings &settings) const
Save settings.
QDateTime mCheckStartTime
date and time when current checking started
ThreadResult mResults
Thread results are stored here.
void setThreadCount(const int count)
Set the number of threads to use.
ThreadHandler(QObject *parent=nullptr)
QDateTime mLastCheckTime
when was the files checked the last time (used when rechecking)
QStringList getReCheckFiles(bool all) const
Get files that should be rechecked because they have been changed.
~ThreadHandler() override
void stop()
Slot to stop all threads.
void debugError(const ErrorItem &item)
int mRunningThreadCount
The amount of threads currently running.
bool isChecking() const
Is checking running?
void log(const QString &msg)
QElapsedTimer mTimer
Timer used for measuring scan duration.
void setProject(const ImportProject &prj)
Set project to check.
int getPreviousFilesCount() const
Return count of files we checked last time.
void setCheckStartTime(QDateTime checkStartTime)
Set start time of check.
void clearFiles()
Clear all files from cppcheck.
int getPreviousScanDuration() const
Return the time elapsed while scanning the previous time.
void setCheckFiles(bool all)
Set files to check.
void initialize(const ResultsView *view)
Initialize the threads (connect all signals to resultsview's slots)
void setFiles(const QStringList &files)
Set files to check.
QList< CheckThread * > mThreads
List of threads currently in use.
void loadSettings(const QSettings &settings)
Load settings.
void clearFiles()
Clear files to check.
void error(const ErrorItem &item)
Signal of a new error.
void setProject(const ImportProject &prj)
void debugError(const ErrorItem &item)
Signal of a debug error.
void log(const QString &logline)
Signal of a new log message.
void fileChecked(const QString &file)
Slot threads use to signal this class that a specific file is checked.
void progress(int value, const QString &description)
Progress signal.
void setFiles(const QStringList &files)
Set list of files to check.
int getFileCount() const
Get the number of files to check.
#define SETTINGS_CHECK_THREADS
Definition: common.h:68