parent
bb327be8e8
commit
cc24d6fcef
|
@ -156,21 +156,39 @@ jobs:
|
||||||
if: contains(matrix.os, 'ubuntu')
|
if: contains(matrix.os, 'ubuntu')
|
||||||
run: |
|
run: |
|
||||||
pushd gui
|
pushd gui
|
||||||
qmake HAVE_QCHART=yes
|
qmake CONFIG+=debug HAVE_QCHART=yes
|
||||||
make -j$(nproc)
|
make -j$(nproc)
|
||||||
|
|
||||||
- name: Run GUI tests on ubuntu
|
- name: Run GUI tests on ubuntu
|
||||||
if: contains(matrix.os, 'ubuntu')
|
if: contains(matrix.os, 'ubuntu')
|
||||||
run: |
|
run: |
|
||||||
|
pushd gui/test/cppchecklibrarydata
|
||||||
|
qmake CONFIG+=debug
|
||||||
|
make -j$(nproc)
|
||||||
|
./test-cppchecklibrarydata
|
||||||
|
popd
|
||||||
|
pushd gui/test/filelist
|
||||||
|
qmake CONFIG+=debug
|
||||||
|
make -j$(nproc)
|
||||||
|
# TODO: requires X session
|
||||||
|
#./test-filelist
|
||||||
|
popd
|
||||||
pushd gui/test/projectfile
|
pushd gui/test/projectfile
|
||||||
qmake
|
qmake CONFIG+=debug
|
||||||
make -j$(nproc)
|
make -j$(nproc)
|
||||||
./test-projectfile
|
./test-projectfile
|
||||||
popd
|
popd
|
||||||
pushd gui/test/cppchecklibrarydata
|
pushd gui/test/translationhandler
|
||||||
qmake
|
qmake CONFIG+=debug
|
||||||
make -j$(nproc)
|
make -j$(nproc)
|
||||||
./test-cppchecklibrarydata
|
# TODO: requires X session
|
||||||
|
#./test-translationhandler
|
||||||
|
popd
|
||||||
|
pushd gui/test/xmlreportv2
|
||||||
|
qmake CONFIG+=debug
|
||||||
|
make -j$(nproc)
|
||||||
|
# TODO: requires X session
|
||||||
|
#./test-xmlreportv2
|
||||||
|
|
||||||
- name: Generate Qt help file on ubuntu
|
- name: Generate Qt help file on ubuntu
|
||||||
if: contains(matrix.os, 'ubuntu')
|
if: contains(matrix.os, 'ubuntu')
|
||||||
|
@ -178,6 +196,19 @@ jobs:
|
||||||
pushd gui/help
|
pushd gui/help
|
||||||
qhelpgenerator online-help.qhcp -o online-help.qhc
|
qhelpgenerator online-help.qhcp -o online-help.qhc
|
||||||
|
|
||||||
|
- name: Build triage on ubuntu
|
||||||
|
if: matrix.os == 'ubuntu-20.04'
|
||||||
|
run: |
|
||||||
|
pushd tools/triage
|
||||||
|
qmake CONFIG+=debug
|
||||||
|
make -j$(nproc)
|
||||||
|
|
||||||
|
- name: Build Fuzzer
|
||||||
|
if: matrix.os == 'ubuntu-20.04'
|
||||||
|
run: |
|
||||||
|
pushd oss-fuzz
|
||||||
|
make -j$(nproc) CXX=clang++ CXXFLAGS="-fsanitize=address" fuzz-client translate
|
||||||
|
|
||||||
- name: Self check (build)
|
- name: Self check (build)
|
||||||
if: matrix.os == 'ubuntu-20.04'
|
if: matrix.os == 'ubuntu-20.04'
|
||||||
run: |
|
run: |
|
||||||
|
@ -196,18 +227,4 @@ jobs:
|
||||||
mkdir b2
|
mkdir b2
|
||||||
./cppcheck -q -j$(nproc) --std=c++11 --template=selfcheck --cppcheck-build-dir=b2 -D__CPPCHECK__ -DQT_VERSION=0x050000 -DQ_MOC_OUTPUT_REVISION=67 --error-exitcode=1 --inline-suppr --suppressions-list=.travis_suppressions --library=qt --addon=naming.json -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ --enable=style,performance,portability,warning,missingInclude,internal --exception-handling --debug-warnings gui/*.cpp gui/temp/*.cpp
|
./cppcheck -q -j$(nproc) --std=c++11 --template=selfcheck --cppcheck-build-dir=b2 -D__CPPCHECK__ -DQT_VERSION=0x050000 -DQ_MOC_OUTPUT_REVISION=67 --error-exitcode=1 --inline-suppr --suppressions-list=.travis_suppressions --library=qt --addon=naming.json -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ --enable=style,performance,portability,warning,missingInclude,internal --exception-handling --debug-warnings gui/*.cpp gui/temp/*.cpp
|
||||||
# self check test and tools
|
# self check test and tools
|
||||||
./cppcheck -q -j$(nproc) --std=c++11 --template=selfcheck -D__CPPCHECK__ --error-exitcode=1 --inline-suppr --suppressions-list=.travis_suppressions --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ -Icli -Igui --inconclusive --enable=style,performance,portability,warning,missingInclude,internal --exception-handling --debug-warnings test/*.cpp tools
|
./cppcheck -q -j$(nproc) --std=c++11 --template=selfcheck -D__CPPCHECK__ -DQ_MOC_OUTPUT_REVISION=67 --error-exitcode=1 --inline-suppr --suppressions-list=.travis_suppressions --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ -Icli -Igui --inconclusive --enable=style,performance,portability,warning,missingInclude,internal --exception-handling --debug-warnings test/*.cpp tools
|
||||||
|
|
||||||
- name: Build triage on ubuntu
|
|
||||||
if: matrix.os == 'ubuntu-20.04'
|
|
||||||
run: |
|
|
||||||
pushd tools/triage
|
|
||||||
qmake
|
|
||||||
make -j$(nproc)
|
|
||||||
|
|
||||||
- name: Build Fuzzer
|
|
||||||
if: matrix.os == 'ubuntu-20.04'
|
|
||||||
run: |
|
|
||||||
pushd oss-fuzz
|
|
||||||
make -j$(nproc) CXX=clang++ CXXFLAGS="-fsanitize=address" fuzz-client translate
|
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,8 @@ gui/cppcheck-gui
|
||||||
gui/cppcheck-gui.exe
|
gui/cppcheck-gui.exe
|
||||||
gui/gui.sln
|
gui/gui.sln
|
||||||
gui/gui.vcproj
|
gui/gui.vcproj
|
||||||
|
gui/help/online-help.qch
|
||||||
|
gui/help/online-help.qhc
|
||||||
gui/Makefile
|
gui/Makefile
|
||||||
gui/Makefile.debug
|
gui/Makefile.debug
|
||||||
gui/Makefile.release
|
gui/Makefile.release
|
||||||
|
@ -66,11 +68,11 @@ gui/test/Makefile
|
||||||
gui/test/*/Makefile
|
gui/test/*/Makefile
|
||||||
gui/test/*/*/Makefile
|
gui/test/*/*/Makefile
|
||||||
gui/test/benchmark/simple/benchmark-simple
|
gui/test/benchmark/simple/benchmark-simple
|
||||||
|
gui/test/cppchecklibrarydata/qrc_resources.cpp
|
||||||
|
gui/test/cppchecklibrarydata/test-cppchecklibrarydata
|
||||||
gui/test/filelist/test-filelist
|
gui/test/filelist/test-filelist
|
||||||
gui/test/projectfile/test-projectfile
|
gui/test/projectfile/test-projectfile
|
||||||
gui/test/translationhandler/test-translationhandler
|
gui/test/translationhandler/test-translationhandler
|
||||||
gui/test/xmlreport/test-xmlreport
|
|
||||||
gui/test/xmlreportv1/test-xmlreportv1
|
|
||||||
gui/test/xmlreportv2/test-xmlreportv2
|
gui/test/xmlreportv2/test-xmlreportv2
|
||||||
|
|
||||||
# Doxygen output folder
|
# Doxygen output folder
|
||||||
|
|
|
@ -11,6 +11,7 @@ useStlAlgorithm
|
||||||
simplifyUsing:lib/valueptr.h
|
simplifyUsing:lib/valueptr.h
|
||||||
symbolDatabaseWarning:gui/temp/moc_*.cpp
|
symbolDatabaseWarning:gui/temp/moc_*.cpp
|
||||||
simplifyUsing:gui/temp/moc_*.cpp
|
simplifyUsing:gui/temp/moc_*.cpp
|
||||||
|
symbolDatabaseWarning:tools/triage/moc_*.cpp
|
||||||
|
|
||||||
# debug suppressions
|
# debug suppressions
|
||||||
valueFlowBailout
|
valueFlowBailout
|
||||||
|
|
|
@ -644,13 +644,17 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (projType == ImportProject::Type::MISSING) {
|
if (projType == ImportProject::Type::MISSING) {
|
||||||
printError("failed to open project '" + projectFile + "'.");
|
printError("failed to open project '" + projectFile + "'. The file does not exist.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (projType == ImportProject::Type::UNKNOWN) {
|
if (projType == ImportProject::Type::UNKNOWN) {
|
||||||
printError("failed to load project '" + projectFile + "'. The format is unknown.");
|
printError("failed to load project '" + projectFile + "'. The format is unknown.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (projType == ImportProject::Type::FAILURE) {
|
||||||
|
printError("failed to load project '" + projectFile + "'. An error occurred.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --project-configuration
|
// --project-configuration
|
||||||
|
|
|
@ -48,14 +48,6 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
#if QT_VERSION < 0x050000
|
|
||||||
// Set codecs so that UTF-8 strings in sources are handled correctly.
|
|
||||||
// This is ONLY needed for Qt versions 4.x.
|
|
||||||
// Qt 5.x assumes UTF-8 by default.
|
|
||||||
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
|
|
||||||
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QCoreApplication::setOrganizationName("Cppcheck");
|
QCoreApplication::setOrganizationName("Cppcheck");
|
||||||
QCoreApplication::setApplicationName("Cppcheck-GUI");
|
QCoreApplication::setApplicationName("Cppcheck-GUI");
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,12 @@ SOURCES += testfilelist.cpp \
|
||||||
../../filelist.cpp \
|
../../filelist.cpp \
|
||||||
../../../lib/pathmatch.cpp \
|
../../../lib/pathmatch.cpp \
|
||||||
../../../lib/path.cpp \
|
../../../lib/path.cpp \
|
||||||
|
../../../lib/utils.cpp \
|
||||||
../../../externals/simplecpp/simplecpp.cpp
|
../../../externals/simplecpp/simplecpp.cpp
|
||||||
|
|
||||||
HEADERS += testfilelist.h \
|
HEADERS += testfilelist.h \
|
||||||
../../filelist.h \
|
../../filelist.h \
|
||||||
../../../lib/pathmatch.h \
|
../../../lib/pathmatch.h \
|
||||||
../../../lib/path.h \
|
../../../lib/path.h \
|
||||||
|
../../../lib/utils.h \
|
||||||
../../../externals/simplecpp/simplecpp.h
|
../../../externals/simplecpp/simplecpp.h
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
TARGET = test-projectfile
|
TARGET = test-projectfile
|
||||||
DEPENDPATH += .
|
DEPENDPATH += .
|
||||||
INCLUDEPATH += . ../../../externals/simplecpp
|
INCLUDEPATH += . ../../../externals/simplecpp ../../../externals/tinyxml2 ../../../externals/picojson
|
||||||
OBJECTS_DIR = ../build
|
OBJECTS_DIR = ../build
|
||||||
MOC_DIR = ../build
|
MOC_DIR = ../build
|
||||||
QT -= gui
|
QT -= gui
|
||||||
|
@ -14,11 +14,8 @@ DEFINES += SRCDIR=\\\"$$PWD\\\"
|
||||||
|
|
||||||
# tests
|
# tests
|
||||||
SOURCES += testprojectfile.cpp \
|
SOURCES += testprojectfile.cpp \
|
||||||
../../projectfile.cpp \
|
../../projectfile.cpp
|
||||||
../../../lib/path.cpp \
|
|
||||||
../../../externals/simplecpp/simplecpp.cpp
|
|
||||||
|
|
||||||
HEADERS += testprojectfile.h \
|
HEADERS += testprojectfile.h \
|
||||||
../../projectfile.h \
|
../../projectfile.h \
|
||||||
../../../lib/path.h \
|
../../../externals/picojson/picojson.h
|
||||||
../../../externals/simplecpp/simplecpp.h
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ Settings::Settings() : maxCtuDepth(10), maxTemplateRecursion(100) {}
|
||||||
cppcheck::Platform::Platform() {}
|
cppcheck::Platform::Platform() {}
|
||||||
Library::Library() {}
|
Library::Library() {}
|
||||||
ImportProject::ImportProject() {}
|
ImportProject::ImportProject() {}
|
||||||
|
bool ImportProject::sourceFileExists(const std::string &/*file*/) { return true; }
|
||||||
|
|
||||||
void TestProjectFile::loadInexisting()
|
void TestProjectFile::loadInexisting()
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,6 +9,10 @@ QT += widgets
|
||||||
include(../common.pri)
|
include(../common.pri)
|
||||||
|
|
||||||
# tests
|
# tests
|
||||||
SOURCES += testtranslationhandler.cpp
|
SOURCES += testtranslationhandler.cpp \
|
||||||
|
../../translationhandler.cpp \
|
||||||
|
../../common.cpp
|
||||||
|
|
||||||
HEADERS += testtranslationhandler.h
|
HEADERS += testtranslationhandler.h \
|
||||||
|
../../translationhandler.h \
|
||||||
|
../../common.h
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
TARGET = test-xmlreportv2
|
TARGET = test-xmlreportv2
|
||||||
DEPENDPATH += .
|
DEPENDPATH += .
|
||||||
INCLUDEPATH += . ../../../externals/simplecpp ../../../externals/tinyxml
|
INCLUDEPATH += . ../../../externals/simplecpp
|
||||||
OBJECTS_DIR = ../build
|
OBJECTS_DIR = ../build
|
||||||
MOC_DIR = ../build
|
MOC_DIR = ../build
|
||||||
|
|
||||||
|
|
|
@ -199,29 +199,36 @@ ImportProject::Type ImportProject::import(const std::string &filename, Settings
|
||||||
settings ? settings->fileFilters : std::vector<std::string>();
|
settings ? settings->fileFilters : std::vector<std::string>();
|
||||||
|
|
||||||
if (endsWith(filename, ".json")) {
|
if (endsWith(filename, ".json")) {
|
||||||
importCompileCommands(fin);
|
if (importCompileCommands(fin)) {
|
||||||
setRelativePaths(filename);
|
setRelativePaths(filename);
|
||||||
return ImportProject::Type::COMPILE_DB;
|
return ImportProject::Type::COMPILE_DB;
|
||||||
|
}
|
||||||
} else if (endsWith(filename, ".sln")) {
|
} else if (endsWith(filename, ".sln")) {
|
||||||
importSln(fin, mPath, fileFilters);
|
if (importSln(fin, mPath, fileFilters)) {
|
||||||
setRelativePaths(filename);
|
setRelativePaths(filename);
|
||||||
return ImportProject::Type::VS_SLN;
|
return ImportProject::Type::VS_SLN;
|
||||||
|
}
|
||||||
} else if (endsWith(filename, ".vcxproj")) {
|
} else if (endsWith(filename, ".vcxproj")) {
|
||||||
std::map<std::string, std::string, cppcheck::stricmp> variables;
|
std::map<std::string, std::string, cppcheck::stricmp> variables;
|
||||||
importVcxproj(filename, variables, emptyString, fileFilters);
|
if (importVcxproj(filename, variables, emptyString, fileFilters)) {
|
||||||
setRelativePaths(filename);
|
setRelativePaths(filename);
|
||||||
return ImportProject::Type::VS_VCXPROJ;
|
return ImportProject::Type::VS_VCXPROJ;
|
||||||
|
}
|
||||||
} else if (endsWith(filename, ".bpr")) {
|
} else if (endsWith(filename, ".bpr")) {
|
||||||
importBcb6Prj(filename);
|
if (importBcb6Prj(filename)) {
|
||||||
setRelativePaths(filename);
|
setRelativePaths(filename);
|
||||||
return ImportProject::Type::BORLAND;
|
return ImportProject::Type::BORLAND;
|
||||||
} else if (settings && endsWith(filename, ".cppcheck")) {
|
|
||||||
const bool success = importCppcheckGuiProject(fin, settings);
|
|
||||||
setRelativePaths(filename);
|
|
||||||
return success ? ImportProject::Type::CPPCHECK_GUI : ImportProject::Type::MISSING;
|
|
||||||
}
|
}
|
||||||
|
} else if (settings && endsWith(filename, ".cppcheck")) {
|
||||||
|
if (importCppcheckGuiProject(fin, settings)) {
|
||||||
|
setRelativePaths(filename);
|
||||||
|
return ImportProject::Type::CPPCHECK_GUI;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
return ImportProject::Type::UNKNOWN;
|
return ImportProject::Type::UNKNOWN;
|
||||||
}
|
}
|
||||||
|
return ImportProject::Type::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
static std::string readUntil(const std::string &command, std::string::size_type *pos, const char until[])
|
static std::string readUntil(const std::string &command, std::string::size_type *pos, const char until[])
|
||||||
{
|
{
|
||||||
|
@ -385,12 +392,14 @@ void ImportProject::FileSettings::parseCommand(std::string command)
|
||||||
setDefines(defs);
|
setDefines(defs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportProject::importCompileCommands(std::istream &istr)
|
bool ImportProject::importCompileCommands(std::istream &istr)
|
||||||
{
|
{
|
||||||
picojson::value compileCommands;
|
picojson::value compileCommands;
|
||||||
istr >> compileCommands;
|
istr >> compileCommands;
|
||||||
if (!compileCommands.is<picojson::array>())
|
if (!compileCommands.is<picojson::array>()) {
|
||||||
return;
|
printError("compilation database is not a JSON array");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (const picojson::value &fileInfo : compileCommands.get<picojson::array>()) {
|
for (const picojson::value &fileInfo : compileCommands.get<picojson::array>()) {
|
||||||
picojson::object obj = fileInfo.get<picojson::object>();
|
picojson::object obj = fileInfo.get<picojson::object>();
|
||||||
|
@ -412,14 +421,16 @@ void ImportProject::importCompileCommands(std::istream &istr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return;
|
printError("'arguments' field in compilation database entry is not a JSON array");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} else if (obj.find("command") != obj.end()) {
|
} else if (obj.find("command") != obj.end()) {
|
||||||
if (obj["command"].is<std::string>()) {
|
if (obj["command"].is<std::string>()) {
|
||||||
comm << obj["command"].get<std::string>();
|
comm << obj["command"].get<std::string>();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return;
|
printError("no 'arguments' or 'command' field found in compilation database entry");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string command = comm.str();
|
const std::string command = comm.str();
|
||||||
|
@ -441,19 +452,39 @@ void ImportProject::importCompileCommands(std::istream &istr)
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
fs.filename = Path::simplifyPath(directory + file);
|
fs.filename = Path::simplifyPath(directory + file);
|
||||||
|
if (!sourceFileExists(fs.filename)) {
|
||||||
|
printError("'" + fs.filename + "' from compilation database does not exist");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
fs.parseCommand(command); // read settings; -D, -I, -U, -std, -m*, -f*
|
fs.parseCommand(command); // read settings; -D, -I, -U, -std, -m*, -f*
|
||||||
std::map<std::string, std::string, cppcheck::stricmp> variables;
|
std::map<std::string, std::string, cppcheck::stricmp> variables;
|
||||||
fs.setIncludePaths(directory, fs.includePaths, variables);
|
fs.setIncludePaths(directory, fs.includePaths, variables);
|
||||||
fileSettings.push_back(fs);
|
fileSettings.push_back(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportProject::importSln(std::istream &istr, const std::string &path, const std::vector<std::string> &fileFilters)
|
bool ImportProject::importSln(std::istream &istr, const std::string &path, const std::vector<std::string> &fileFilters)
|
||||||
{
|
{
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
// skip magic word
|
||||||
|
if (!std::getline(istr,line)) {
|
||||||
|
printError("Visual Studio solution file is empty");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!std::getline(istr, line) || line.find("Microsoft Visual Studio Solution File") != 0) {
|
||||||
|
printError("Visual Studio solution file header not found");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::map<std::string,std::string,cppcheck::stricmp> variables;
|
std::map<std::string,std::string,cppcheck::stricmp> variables;
|
||||||
variables["SolutionDir"] = path;
|
variables["SolutionDir"] = path;
|
||||||
|
|
||||||
std::string line;
|
bool found = false;
|
||||||
|
|
||||||
while (std::getline(istr,line)) {
|
while (std::getline(istr,line)) {
|
||||||
if (line.compare(0,8,"Project(")!=0)
|
if (line.compare(0,8,"Project(")!=0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -466,8 +497,19 @@ void ImportProject::importSln(std::istream &istr, const std::string &path, const
|
||||||
std::string vcxproj(line.substr(pos1+1, pos-pos1+7));
|
std::string vcxproj(line.substr(pos1+1, pos-pos1+7));
|
||||||
if (!Path::isAbsolute(vcxproj))
|
if (!Path::isAbsolute(vcxproj))
|
||||||
vcxproj = path + vcxproj;
|
vcxproj = path + vcxproj;
|
||||||
importVcxproj(Path::fromNativeSeparators(vcxproj), variables, emptyString, fileFilters);
|
if (!importVcxproj(Path::fromNativeSeparators(vcxproj), variables, emptyString, fileFilters)) {
|
||||||
|
printError("failed to load '" + vcxproj + "' from Visual Studio solution");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
printError("no projects found in Visual Studio solution file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -659,7 +701,7 @@ static void loadVisualStudioProperties(const std::string &props, std::map<std::s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportProject::importVcxproj(const std::string &filename, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters)
|
bool ImportProject::importVcxproj(const std::string &filename, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters)
|
||||||
{
|
{
|
||||||
variables["ProjectDir"] = Path::simplifyPath(Path::getPathFromFilename(filename));
|
variables["ProjectDir"] = Path::simplifyPath(Path::getPathFromFilename(filename));
|
||||||
|
|
||||||
|
@ -672,11 +714,15 @@ void ImportProject::importVcxproj(const std::string &filename, std::map<std::str
|
||||||
|
|
||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
const tinyxml2::XMLError error = doc.LoadFile(filename.c_str());
|
const tinyxml2::XMLError error = doc.LoadFile(filename.c_str());
|
||||||
if (error != tinyxml2::XML_SUCCESS)
|
if (error != tinyxml2::XML_SUCCESS) {
|
||||||
return;
|
printError(std::string("Visual Studio project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
|
const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
|
||||||
if (rootnode == nullptr)
|
if (rootnode == nullptr) {
|
||||||
return;
|
printError("Visual Studio project file has no XML root node");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
|
for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
|
||||||
if (std::strcmp(node->Name(), "ItemGroup") == 0) {
|
if (std::strcmp(node->Name(), "ItemGroup") == 0) {
|
||||||
const char *labelAttribute = node->Attribute("Label");
|
const char *labelAttribute = node->Attribute("Label");
|
||||||
|
@ -767,17 +813,23 @@ void ImportProject::importVcxproj(const std::string &filename, std::map<std::str
|
||||||
fileSettings.push_back(fs);
|
fileSettings.push_back(fs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportProject::importBcb6Prj(const std::string &projectFilename)
|
bool ImportProject::importBcb6Prj(const std::string &projectFilename)
|
||||||
{
|
{
|
||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
const tinyxml2::XMLError error = doc.LoadFile(projectFilename.c_str());
|
const tinyxml2::XMLError error = doc.LoadFile(projectFilename.c_str());
|
||||||
if (error != tinyxml2::XML_SUCCESS)
|
if (error != tinyxml2::XML_SUCCESS) {
|
||||||
return;
|
printError(std::string("Borland project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
|
const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
|
||||||
if (rootnode == nullptr)
|
if (rootnode == nullptr) {
|
||||||
return;
|
printError("Borland project file has no XML root node");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string& projectDir = Path::simplifyPath(Path::getPathFromFilename(projectFilename));
|
const std::string& projectDir = Path::simplifyPath(Path::getPathFromFilename(projectFilename));
|
||||||
|
|
||||||
|
@ -1027,6 +1079,8 @@ void ImportProject::importBcb6Prj(const std::string &projectFilename)
|
||||||
fs.filename = Path::simplifyPath(Path::isAbsolute(c) ? c : projectDir + c);
|
fs.filename = Path::simplifyPath(Path::isAbsolute(c) ? c : projectDir + c);
|
||||||
fileSettings.push_back(fs);
|
fileSettings.push_back(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string joinRelativePath(const std::string &path1, const std::string &path2)
|
static std::string joinRelativePath(const std::string &path1, const std::string &path2)
|
||||||
|
@ -1069,11 +1123,16 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti
|
||||||
{
|
{
|
||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
const std::string xmldata = istream_to_string(istr);
|
const std::string xmldata = istream_to_string(istr);
|
||||||
if (doc.Parse(xmldata.data(), xmldata.size()) != tinyxml2::XML_SUCCESS)
|
const tinyxml2::XMLError error = doc.Parse(xmldata.data(), xmldata.size());
|
||||||
|
if (error != tinyxml2::XML_SUCCESS) {
|
||||||
|
printError(std::string("Cppcheck GUI project file is not a valid XML - ") + tinyxml2::XMLDocument::ErrorIDToName(error));
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
|
const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
|
||||||
if (rootnode == nullptr || strcmp(rootnode->Name(), CppcheckXml::ProjectElementName) != 0)
|
if (rootnode == nullptr || strcmp(rootnode->Name(), CppcheckXml::ProjectElementName) != 0) {
|
||||||
|
printError("Cppcheck GUI project file has no XML root node");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string &path = mPath;
|
const std::string &path = mPath;
|
||||||
|
|
||||||
|
@ -1211,6 +1270,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti
|
||||||
settings->safeChecks = temp.safeChecks;
|
settings->safeChecks = temp.safeChecks;
|
||||||
settings->bugHunting = temp.bugHunting;
|
settings->bugHunting = temp.bugHunting;
|
||||||
settings->functionContracts = temp.functionContracts;
|
settings->functionContracts = temp.functionContracts;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1259,3 +1319,13 @@ void ImportProject::setRelativePaths(const std::string &filename)
|
||||||
includePath = Path::getRelativePath(includePath, basePaths);
|
includePath = Path::getRelativePath(includePath, basePaths);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImportProject::printError(const std::string &message)
|
||||||
|
{
|
||||||
|
std::cout << "cppcheck: error: " << message << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImportProject::sourceFileExists(const std::string &file)
|
||||||
|
{
|
||||||
|
return Path::fileExists(file);
|
||||||
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ public:
|
||||||
enum class Type {
|
enum class Type {
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
MISSING,
|
MISSING,
|
||||||
|
FAILURE,
|
||||||
COMPILE_DB,
|
COMPILE_DB,
|
||||||
VS_SLN,
|
VS_SLN,
|
||||||
VS_VCXPROJ,
|
VS_VCXPROJ,
|
||||||
|
@ -106,12 +107,15 @@ public:
|
||||||
|
|
||||||
Type import(const std::string &filename, Settings *settings=nullptr);
|
Type import(const std::string &filename, Settings *settings=nullptr);
|
||||||
protected:
|
protected:
|
||||||
void importCompileCommands(std::istream &istr);
|
bool importCompileCommands(std::istream &istr);
|
||||||
bool importCppcheckGuiProject(std::istream &istr, Settings *settings);
|
bool importCppcheckGuiProject(std::istream &istr, Settings *settings);
|
||||||
|
virtual bool sourceFileExists(const std::string &file);
|
||||||
private:
|
private:
|
||||||
void importSln(std::istream &istr, const std::string &path, const std::vector<std::string> &fileFilters);
|
bool importSln(std::istream &istr, const std::string &path, const std::vector<std::string> &fileFilters);
|
||||||
void importVcxproj(const std::string &filename, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters);
|
bool importVcxproj(const std::string &filename, std::map<std::string, std::string, cppcheck::stricmp> &variables, const std::string &additionalIncludeDirectories, const std::vector<std::string> &fileFilters);
|
||||||
void importBcb6Prj(const std::string &projectFilename);
|
bool importBcb6Prj(const std::string &projectFilename);
|
||||||
|
|
||||||
|
void printError(const std::string &message);
|
||||||
|
|
||||||
void setRelativePaths(const std::string &filename);
|
void setRelativePaths(const std::string &filename);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
# python -m pytest test-projects.py
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
from testutils import cppcheck
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("project_ext", ["json", "sln", "vcxproj", "bpr", "cppcheck"])
|
||||||
|
def test_missing_project(project_ext):
|
||||||
|
project_file = "file.{}".format(project_ext)
|
||||||
|
|
||||||
|
ret, stdout, stderr = cppcheck(['--project=' + project_file, '--template=cppcheck1'])
|
||||||
|
assert 1 == ret
|
||||||
|
assert "cppcheck: error: failed to open project '{}'. The file does not exist.\n".format(project_file) == stdout
|
||||||
|
assert "" == stderr
|
||||||
|
|
||||||
|
|
||||||
|
def _test_project_error(tmpdir, ext, content, expected):
|
||||||
|
project_file = os.path.join(tmpdir, "file.{}".format(ext))
|
||||||
|
|
||||||
|
with open(project_file, 'w') as f:
|
||||||
|
if content is not None:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
ret, stdout, stderr = cppcheck(['--project=' + str(project_file)])
|
||||||
|
assert 1 == ret
|
||||||
|
assert "cppcheck: error: " + expected + "\ncppcheck: error: failed to load project '{}'. An error occurred.\n".format(project_file) == stdout
|
||||||
|
assert "" == stderr
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("project_ext, expected", [
|
||||||
|
("json", "compilation database is not a JSON array"),
|
||||||
|
("sln", "Visual Studio solution file is empty"),
|
||||||
|
("vcxproj", "Visual Studio project file is not a valid XML - XML_ERROR_EMPTY_DOCUMENT"),
|
||||||
|
("bpr", "Borland project file is not a valid XML - XML_ERROR_EMPTY_DOCUMENT"),
|
||||||
|
("cppcheck", "Cppcheck GUI project file is not a valid XML - XML_ERROR_EMPTY_DOCUMENT")
|
||||||
|
])
|
||||||
|
def test_empty_project(tmpdir, project_ext, expected):
|
||||||
|
_test_project_error(tmpdir, project_ext, None, expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_json_entry_file_not_found(tmpdir):
|
||||||
|
compilation_db = [
|
||||||
|
{"directory": str(tmpdir),
|
||||||
|
"command": "c++ -o bug1.o -c bug1.cpp",
|
||||||
|
"file": "bug1.cpp",
|
||||||
|
"output": "bug1.o"}
|
||||||
|
]
|
||||||
|
|
||||||
|
expected = "'{}' from compilation database does not exist".format(os.path.join(tmpdir, "bug1.cpp"))
|
||||||
|
|
||||||
|
_test_project_error(tmpdir, "json", json.dumps(compilation_db), expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_json_no_arguments(tmpdir):
|
||||||
|
compilation_db = [
|
||||||
|
{"directory": str(tmpdir),
|
||||||
|
"file": "bug1.cpp",
|
||||||
|
"output": "bug1.o"}
|
||||||
|
]
|
||||||
|
|
||||||
|
expected = "no 'arguments' or 'command' field found in compilation database entry"
|
||||||
|
|
||||||
|
_test_project_error(tmpdir, "json", json.dumps(compilation_db), expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_json_invalid_arguments(tmpdir):
|
||||||
|
compilation_db = [
|
||||||
|
{"directory": str(tmpdir),
|
||||||
|
"arguments": "",
|
||||||
|
"file": "bug1.cpp",
|
||||||
|
"output": "bug1.o"}
|
||||||
|
]
|
||||||
|
|
||||||
|
expected = "'arguments' field in compilation database entry is not a JSON array"
|
||||||
|
|
||||||
|
_test_project_error(tmpdir, "json", json.dumps(compilation_db), expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_sln_invalid_file(tmpdir):
|
||||||
|
content = "some file"
|
||||||
|
|
||||||
|
expected = "Visual Studio solution file header not found"
|
||||||
|
|
||||||
|
_test_project_error(tmpdir, "sln", content, expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_sln_no_header(tmpdir):
|
||||||
|
content = "\xEF\xBB\xBF\r\n" \
|
||||||
|
"some header"
|
||||||
|
|
||||||
|
expected = "Visual Studio solution file header not found"
|
||||||
|
|
||||||
|
_test_project_error(tmpdir, "sln", content, expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_sln_no_projects(tmpdir):
|
||||||
|
content = "\xEF\xBB\xBF\r\n" \
|
||||||
|
"Microsoft Visual Studio Solution File, Format Version 12.00\r\n"
|
||||||
|
|
||||||
|
expected = "no projects found in Visual Studio solution file"
|
||||||
|
|
||||||
|
_test_project_error(tmpdir, "sln", content, expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_sln_project_file_not_found(tmpdir):
|
||||||
|
content = "\xEF\xBB\xBF\r\n" \
|
||||||
|
"Microsoft Visual Studio Solution File, Format Version 12.00\r\n" \
|
||||||
|
"# Visual Studio Version 16\r\n" \
|
||||||
|
"VisualStudioVersion = 16.0.29020.237\r\n" \
|
||||||
|
"MinimumVisualStudioVersion = 10.0.40219.1\r\n" \
|
||||||
|
'Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cli", "cli\\cli.vcxproj", "{35CBDF51-2456-3EC3-99ED-113C30858883}"\r\n' \
|
||||||
|
"ProjectSection(ProjectDependencies) = postProject\r\n" \
|
||||||
|
"{C183DB5B-AD6C-423D-80CA-1F9549555A1A} = {C183DB5B-AD6C-423D-80CA-1F9549555A1A}\r\n" \
|
||||||
|
"EndProjectSection\r\n" \
|
||||||
|
"EndProject\r\n"
|
||||||
|
|
||||||
|
expected = "Visual Studio project file is not a valid XML - XML_ERROR_FILE_NOT_FOUND\n" \
|
||||||
|
"cppcheck: error: failed to load '{}' from Visual Studio solution".format(os.path.join(tmpdir, "cli\\cli.vcxproj"))
|
||||||
|
|
||||||
|
_test_project_error(tmpdir, "sln", content, expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_vcxproj_no_xml_root(tmpdir):
|
||||||
|
content = '<?xml version="1.0" encoding="utf-8"?>'
|
||||||
|
|
||||||
|
expected = "Visual Studio project file has no XML root node"
|
||||||
|
|
||||||
|
_test_project_error(tmpdir, "vcxproj", content, expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bpr_no_xml_root(tmpdir):
|
||||||
|
content = '<?xml version="1.0" encoding="utf-8"?>'
|
||||||
|
|
||||||
|
expected = "Borland project file has no XML root node"
|
||||||
|
|
||||||
|
_test_project_error(tmpdir, "bpr", content, expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cppcheck_no_xml_root(tmpdir):
|
||||||
|
content = '<?xml version="1.0" encoding="utf-8"?>'
|
||||||
|
|
||||||
|
expected = "Cppcheck GUI project file has no XML root node"
|
||||||
|
|
||||||
|
_test_project_error(tmpdir, "cppcheck", content, expected)
|
|
@ -4,6 +4,9 @@ import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
# Create Cppcheck project file
|
# Create Cppcheck project file
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
def create_gui_project_file(project_file, root_path=None, import_project=None, paths=None, exclude_paths=None, suppressions=None, addon=None):
|
def create_gui_project_file(project_file, root_path=None, import_project=None, paths=None, exclude_paths=None, suppressions=None, addon=None):
|
||||||
cppcheck_xml = ('<?xml version="1.0" encoding="UTF-8"?>\n'
|
cppcheck_xml = ('<?xml version="1.0" encoding="UTF-8"?>\n'
|
||||||
'<project version="1">\n')
|
'<project version="1">\n')
|
||||||
|
@ -40,15 +43,28 @@ def create_gui_project_file(project_file, root_path=None, import_project=None, p
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
|
def lookup_cppcheck_exe():
|
||||||
|
# path the script is located in
|
||||||
|
script_path = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
exe_name = "cppcheck"
|
||||||
|
|
||||||
|
if sys.platform == "win32":
|
||||||
|
exe_name += ".exe"
|
||||||
|
|
||||||
|
for base in (script_path + '/../../', './'):
|
||||||
|
for path in ('', 'bin/', 'bin/debug/'):
|
||||||
|
exe_path = base + path + exe_name
|
||||||
|
if os.path.isfile(exe_path):
|
||||||
|
return exe_path
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
# Run Cppcheck with args
|
# Run Cppcheck with args
|
||||||
def cppcheck(args):
|
def cppcheck(args):
|
||||||
exe = None
|
exe = lookup_cppcheck_exe()
|
||||||
for ext in ('', '.exe'):
|
assert exe is not None, 'no cppcheck binary found'
|
||||||
for base in ('../../', '../../../'):
|
|
||||||
for path in ('', 'bin/', 'bin/debug/'):
|
|
||||||
if (exe is None) and os.path.isfile(base + path + 'cppcheck' + ext):
|
|
||||||
exe = base + path + 'cppcheck' + ext
|
|
||||||
assert exe is not None
|
|
||||||
|
|
||||||
logging.info(exe + ' ' + ' '.join(args))
|
logging.info(exe + ' ' + ' '.join(args))
|
||||||
p = subprocess.Popen([exe] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
p = subprocess.Popen([exe] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
|
|
@ -28,6 +28,10 @@ class TestImporter : public ImportProject {
|
||||||
public:
|
public:
|
||||||
using ImportProject::importCompileCommands;
|
using ImportProject::importCompileCommands;
|
||||||
using ImportProject::importCppcheckGuiProject;
|
using ImportProject::importCppcheckGuiProject;
|
||||||
|
|
||||||
|
bool sourceFileExists(const std::string & /*file*/) OVERRIDE {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue