Skip to content

Commit 606e316

Browse files
committed
Fixed danmar#7177 (Support compile_commands.json)
1 parent d220573 commit 606e316

18 files changed

+1002
-381
lines changed

Makefile

Lines changed: 98 additions & 86 deletions
Large diffs are not rendered by default.

cli/cmdlineparser.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,13 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
481481
return false;
482482
}
483483

484+
// --project
485+
else if (std::strncmp(argv[i], "--project=", 10) == 0) {
486+
_settings->project.import(argv[i]+10);
487+
if (std::strstr(argv[i], ".sln") || std::strstr(argv[i], ".vcxproj"))
488+
CppCheckExecutor::tryLoadLibrary(_settings->library, argv[0], "windows");
489+
}
490+
484491
// Report progress
485492
else if (std::strcmp(argv[i], "--report-progress") == 0) {
486493
_settings->reportProgress = true;
@@ -737,6 +744,8 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
737744
}
738745
}
739746

747+
_settings->project.ignorePaths(_ignoredPaths);
748+
740749
if (_settings->force)
741750
_settings->maxConfigs = ~0U;
742751

@@ -766,7 +775,7 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
766775
}
767776

768777
// Print error only if we have "real" command and expect files
769-
if (!_exitAfterPrint && _pathnames.empty()) {
778+
if (!_exitAfterPrint && _pathnames.empty() && _settings->project.fileSettings.empty()) {
770779
PrintMessage("cppcheck: No C or C++ source files found.");
771780
return false;
772781
}
@@ -890,14 +899,19 @@ void CmdLineParser::PrintHelp()
890899
" --language=<language>, -x <language>\n"
891900
" Forces cppcheck to check all files as the given\n"
892901
" language. Valid values are: c, c++\n"
893-
" --library=<cfg>\n"
894-
" Load file <cfg> that contains information about types\n"
902+
" --library=<cfg> Load file <cfg> that contains information about types\n"
895903
" and functions. With such information Cppcheck\n"
896904
" understands your your code better and therefore you\n"
897905
" get better results. The std.cfg file that is\n"
898906
" distributed with Cppcheck is loaded automatically.\n"
899907
" For more information about library files, read the\n"
900908
" manual.\n"
909+
" --project=<file> Run Cppcheck on project. The <file> can be a Visual\n"
910+
" Studio Solution (*.sln), Visual Studio Project\n"
911+
" (*.vcxproj), or compile database\n"
912+
" (compile_commands.json). The files to analyse,\n"
913+
" include paths, defines, platform and undefines in\n"
914+
" the specified file will be used.\n"
901915
" --max-configs=<limit>\n"
902916
" Maximum number of configurations to check in a file\n"
903917
" before skipping it. Default is '12'. If used together\n"

cli/cppcheckexecutor.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c
154154
FileLister::recursiveAddFiles(_files, Path::toNativeSeparators(*iter), _settings->library.markupExtensions(), matcher);
155155
}
156156

157-
if (_files.empty()) {
157+
if (_files.empty() && settings.project.fileSettings.empty()) {
158158
std::cout << "cppcheck: error: could not find or open any of the paths given." << std::endl;
159159
if (!ignored.empty())
160160
std::cout << "cppcheck: Maybe all paths were ignored?" << std::endl;
@@ -825,6 +825,15 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck, int /*argc*/, const cha
825825
}
826826
}
827827

828+
// filesettings
829+
c = 0;
830+
for (std::list<ImportProject::FileSettings>::const_iterator fs = settings.project.fileSettings.begin(); fs != settings.project.fileSettings.end(); ++fs) {
831+
returnValue += cppcheck.check(*fs);
832+
++c;
833+
if (!settings.quiet)
834+
reportStatus(c, settings.project.fileSettings.size(), c, settings.project.fileSettings.size());
835+
}
836+
828837
// second loop to parse all markup files which may not work until all
829838
// c/cpp files have been parsed and checked
830839
for (std::map<std::string, std::size_t>::const_iterator i = _files.begin(); i != _files.end(); ++i) {

cli/threadexecutor.cpp

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -175,11 +175,12 @@ unsigned int ThreadExecutor::check()
175175
std::map<pid_t, std::string> childFile;
176176
std::map<int, std::string> pipeFile;
177177
std::size_t processedsize = 0;
178-
std::map<std::string, std::size_t>::const_iterator i = _files.begin();
178+
std::map<std::string, std::size_t>::const_iterator iFile = _files.begin();
179+
std::list<ImportProject::FileSettings>::const_iterator iFileSettings = _settings.project.fileSettings.begin();
179180
for (;;) {
180181
// Start a new child
181182
size_t nchildren = rpipes.size();
182-
if (i != _files.end() && nchildren < _settings.jobs && checkLoadAverage(nchildren)) {
183+
if ((iFile != _files.end() || iFileSettings != _settings.project.fileSettings.end()) && nchildren < _settings.jobs && checkLoadAverage(nchildren)) {
183184
int pipes[2];
184185
if (pipe(pipes) == -1) {
185186
std::cerr << "pipe() failed: "<< std::strerror(errno) << std::endl;
@@ -210,12 +211,14 @@ unsigned int ThreadExecutor::check()
210211
fileChecker.settings() = _settings;
211212
unsigned int resultOfCheck = 0;
212213

213-
if (!_fileContents.empty() && _fileContents.find(i->first) != _fileContents.end()) {
214+
if (iFileSettings != _settings.project.fileSettings.end()) {
215+
resultOfCheck = fileChecker.check(*iFileSettings);
216+
} else if (!_fileContents.empty() && _fileContents.find(iFile->first) != _fileContents.end()) {
214217
// File content was given as a string
215-
resultOfCheck = fileChecker.check(i->first, _fileContents[ i->first ]);
218+
resultOfCheck = fileChecker.check(iFile->first, _fileContents[ iFile->first ]);
216219
} else {
217220
// Read file from a file
218-
resultOfCheck = fileChecker.check(i->first);
221+
resultOfCheck = fileChecker.check(iFile->first);
219222
}
220223

221224
std::ostringstream oss;
@@ -226,10 +229,15 @@ unsigned int ThreadExecutor::check()
226229

227230
close(pipes[1]);
228231
rpipes.push_back(pipes[0]);
229-
childFile[pid] = i->first;
230-
pipeFile[pipes[0]] = i->first;
231-
232-
++i;
232+
if (iFileSettings != _settings.project.fileSettings.end()) {
233+
childFile[pid] = iFileSettings->filename + ' ' + iFileSettings->cfg;
234+
pipeFile[pipes[0]] = iFileSettings->filename + ' ' + iFileSettings->cfg;
235+
++iFileSettings;
236+
} else {
237+
childFile[pid] = iFile->first;
238+
pipeFile[pipes[0]] = iFile->first;
239+
++iFile;
240+
}
233241
} else if (!rpipes.empty()) {
234242
fd_set rfds;
235243
FD_ZERO(&rfds);
@@ -260,7 +268,7 @@ unsigned int ThreadExecutor::check()
260268
_fileCount++;
261269
processedsize += size;
262270
if (!_settings.quiet)
263-
CppCheckExecutor::reportStatus(_fileCount, _files.size(), processedsize, totalfilesize);
271+
CppCheckExecutor::reportStatus(_fileCount, _files.size() + _settings.project.fileSettings.size(), processedsize, totalfilesize);
264272

265273
close(*rp);
266274
rp = rpipes.erase(rp);
@@ -352,10 +360,11 @@ unsigned int ThreadExecutor::check()
352360
HANDLE *threadHandles = new HANDLE[_settings.jobs];
353361

354362
_itNextFile = _files.begin();
363+
_itNextFileSettings = _settings.project.fileSettings.begin();
355364

356365
_processedFiles = 0;
357366
_processedSize = 0;
358-
_totalFiles = _files.size();
367+
_totalFiles = _files.size() + _settings.project.fileSettings.size();
359368
_totalFileSize = 0;
360369
for (std::map<std::string, std::size_t>::const_iterator i = _files.begin(); i != _files.end(); ++i) {
361370
_totalFileSize += i->second;
@@ -415,7 +424,8 @@ unsigned int __stdcall ThreadExecutor::threadProc(void *args)
415424
unsigned int result = 0;
416425

417426
ThreadExecutor *threadExecutor = static_cast<ThreadExecutor*>(args);
418-
std::map<std::string, std::size_t>::const_iterator &it = threadExecutor->_itNextFile;
427+
std::map<std::string, std::size_t>::const_iterator &itFile = threadExecutor->_itNextFile;
428+
std::list<ImportProject::FileSettings>::const_iterator &itFileSettings = threadExecutor->_itNextFileSettings;
419429

420430
// guard static members of CppCheck against concurrent access
421431
EnterCriticalSection(&threadExecutor->_fileSync);
@@ -424,24 +434,32 @@ unsigned int __stdcall ThreadExecutor::threadProc(void *args)
424434
fileChecker.settings() = threadExecutor->_settings;
425435

426436
for (;;) {
427-
if (it == threadExecutor->_files.end()) {
437+
if (itFile == threadExecutor->_files.end() && itFileSettings == threadExecutor->_settings.project.fileSettings.end()) {
428438
LeaveCriticalSection(&threadExecutor->_fileSync);
429439
break;
430-
431440
}
432-
const std::string &file = it->first;
433-
const std::size_t fileSize = it->second;
434-
++it;
435441

436-
LeaveCriticalSection(&threadExecutor->_fileSync);
442+
std::size_t fileSize = 0;
443+
if (itFile != threadExecutor->_files.end()) {
444+
const std::string &file = itFile->first;
445+
fileSize = itFile->second;
446+
++itFile;
437447

438-
std::map<std::string, std::string>::const_iterator fileContent = threadExecutor->_fileContents.find(file);
439-
if (fileContent != threadExecutor->_fileContents.end()) {
440-
// File content was given as a string
441-
result += fileChecker.check(file, fileContent->second);
442-
} else {
443-
// Read file from a file
444-
result += fileChecker.check(file);
448+
LeaveCriticalSection(&threadExecutor->_fileSync);
449+
450+
std::map<std::string, std::string>::const_iterator fileContent = threadExecutor->_fileContents.find(file);
451+
if (fileContent != threadExecutor->_fileContents.end()) {
452+
// File content was given as a string
453+
result += fileChecker.check(file, fileContent->second);
454+
} else {
455+
// Read file from a file
456+
result += fileChecker.check(file);
457+
}
458+
} else { // file settings..
459+
const ImportProject::FileSettings &fs = *itFileSettings;
460+
++itFileSettings;
461+
LeaveCriticalSection(&threadExecutor->_fileSync);
462+
result += fileChecker.check(fs);
445463
}
446464

447465
EnterCriticalSection(&threadExecutor->_fileSync);

cli/threadexecutor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <string>
2424
#include <list>
2525
#include "errorlogger.h"
26+
#include "importproject.h"
2627

2728
#if (defined(__GNUC__) || defined(__sun)) && !defined(__MINGW32__)
2829
#define THREADING_MODEL_FORK
@@ -109,6 +110,7 @@ class ThreadExecutor : public ErrorLogger {
109110

110111
std::map<std::string, std::string> _fileContents;
111112
std::map<std::string, std::size_t>::const_iterator _itNextFile;
113+
std::list<ImportProject::FileSettings>::const_iterator _itNextFileSettings;
112114
std::size_t _processedFiles;
113115
std::size_t _totalFiles;
114116
std::size_t _processedSize;

lib/cppcheck.cpp

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,30 @@ const char * CppCheck::extraVersion()
7171
unsigned int CppCheck::check(const std::string &path)
7272
{
7373
std::ifstream fin(path.c_str());
74-
return processFile(path, fin);
74+
return processFile(path, "", fin);
7575
}
7676

7777
unsigned int CppCheck::check(const std::string &path, const std::string &content)
7878
{
7979
std::istringstream iss(content);
80-
return processFile(path, iss);
80+
return processFile(path, "", iss);
8181
}
8282

83-
unsigned int CppCheck::processFile(const std::string& filename, std::istream& fileStream)
83+
unsigned int CppCheck::check(const ImportProject::FileSettings &fs)
84+
{
85+
CppCheck temp(*this, _useGlobalSuppressions);
86+
temp._settings = _settings;
87+
temp._settings.userDefines = fs.defines;
88+
temp._settings.includePaths = fs.includePaths;
89+
// TODO: temp._settings.userUndefs = fs.undefs;
90+
if (fs.platformType != Settings::Unspecified) {
91+
temp._settings.platform(fs.platformType);
92+
}
93+
std::ifstream fin(fs.filename.c_str());
94+
return temp.processFile(fs.filename, fs.cfg, fin);
95+
}
96+
97+
unsigned int CppCheck::processFile(const std::string& filename, const std::string &cfgname, std::istream& fileStream)
8498
{
8599
exitcode = 0;
86100

@@ -94,7 +108,16 @@ unsigned int CppCheck::processFile(const std::string& filename, std::istream& fi
94108
if (_settings.quiet == false) {
95109
std::string fixedpath = Path::simplifyPath(filename);
96110
fixedpath = Path::toNativeSeparators(fixedpath);
97-
_errorLogger.reportOut(std::string("Checking ") + fixedpath + std::string("..."));
111+
_errorLogger.reportOut(std::string("Checking ") + fixedpath + ' ' + cfgname + std::string("..."));
112+
113+
if (_settings.verbose) {
114+
_errorLogger.reportOut("Defines: " + _settings.userDefines);
115+
std::string includePaths;
116+
for (std::list<std::string>::const_iterator I = _settings.includePaths.begin(); I != _settings.includePaths.end(); ++I)
117+
includePaths += " -I" + *I;
118+
_errorLogger.reportOut("Includes:" + includePaths);
119+
_errorLogger.reportOut(std::string("Platform:") + _settings.platformString());
120+
}
98121
}
99122

100123
bool internalErrorFound(false);

lib/cppcheck.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class CPPCHECKLIB CppCheck : ErrorLogger {
6868
* settings()).
6969
*/
7070
unsigned int check(const std::string &path);
71+
unsigned int check(const ImportProject::FileSettings &fs);
7172

7273
/**
7374
* @brief Check the file.
@@ -139,10 +140,11 @@ class CPPCHECKLIB CppCheck : ErrorLogger {
139140
/**
140141
* @brief Process one file.
141142
* @param filename file name
143+
* @param cfgname cfg name
142144
* @param fileStream stream the file content can be read from
143145
* @return amount of errors found
144146
*/
145-
unsigned int processFile(const std::string& filename, std::istream& fileStream);
147+
unsigned int processFile(const std::string& filename, const std::string &cfgname, std::istream& fileStream);
146148

147149
/**
148150
* @brief Check raw tokens

lib/cppcheck.vcxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@
7878
<ClCompile Include="library.cpp" />
7979
<ClCompile Include="mathlib.cpp" />
8080
<ClCompile Include="path.cpp" />
81+
<ClCompile Include="platform.cpp" />
8182
<ClCompile Include="preprocessor.cpp" />
83+
<ClCompile Include="importproject.cpp" />
8284
<ClCompile Include="settings.cpp" />
8385
<ClCompile Include="suppressions.cpp" />
8486
<ClCompile Include="symboldatabase.cpp" />
@@ -125,7 +127,9 @@
125127
<ClInclude Include="library.h" />
126128
<ClInclude Include="mathlib.h" />
127129
<ClInclude Include="path.h" />
130+
<ClInclude Include="platform.h" />
128131
<ClInclude Include="preprocessor.h" />
132+
<ClInclude Include="importproject.h" />
129133
<ClInclude Include="settings.h" />
130134
<ClInclude Include="suppressions.h" />
131135
<ClInclude Include="symboldatabase.h" />

lib/cppcheck.vcxproj.filters

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,12 @@
143143
<ClCompile Include="..\externals\simplecpp\simplecpp.cpp">
144144
<Filter>Source Files</Filter>
145145
</ClCompile>
146+
<ClCompile Include="importproject.cpp">
147+
<Filter>Source Files</Filter>
148+
</ClCompile>
149+
<ClCompile Include="platform.cpp">
150+
<Filter>Source Files</Filter>
151+
</ClCompile>
146152
</ItemGroup>
147153
<ItemGroup>
148154
<ClInclude Include="checkbufferoverrun.h">
@@ -286,6 +292,12 @@
286292
<ClInclude Include="..\externals\simplecpp\simplecpp.h">
287293
<Filter>Header Files</Filter>
288294
</ClInclude>
295+
<ClInclude Include="importproject.h">
296+
<Filter>Header Files</Filter>
297+
</ClInclude>
298+
<ClInclude Include="platform.h">
299+
<Filter>Header Files</Filter>
300+
</ClInclude>
289301
</ItemGroup>
290302
<ItemGroup>
291303
<ResourceCompile Include="version.rc" />

0 commit comments

Comments
 (0)