Merge branch 'main' into chr_FixCrashLib
This commit is contained in:
commit
d264d3673f
24
Makefile
24
Makefile
|
@ -77,6 +77,8 @@ else # !WINNT
|
|||
endif # !CPPCHK_GLIBCXX_DEBUG
|
||||
endif # GNU/kFreeBSD
|
||||
|
||||
LDFLAGS=-pthread
|
||||
|
||||
endif # WINNT
|
||||
|
||||
ifdef CYGWIN
|
||||
|
@ -207,8 +209,10 @@ EXTOBJ = externals/simplecpp/simplecpp.o \
|
|||
|
||||
CLIOBJ = cli/cmdlineparser.o \
|
||||
cli/cppcheckexecutor.o \
|
||||
cli/executor.o \
|
||||
cli/filelister.o \
|
||||
cli/main.o \
|
||||
cli/processexecutor.o \
|
||||
cli/threadexecutor.o
|
||||
|
||||
TESTOBJ = test/options.o \
|
||||
|
@ -247,6 +251,7 @@ TESTOBJ = test/options.o \
|
|||
test/testplatform.o \
|
||||
test/testpostfixoperator.o \
|
||||
test/testpreprocessor.o \
|
||||
test/testprocessexecutor.o \
|
||||
test/testrunner.o \
|
||||
test/testsimplifytemplate.o \
|
||||
test/testsimplifytokens.o \
|
||||
|
@ -285,7 +290,7 @@ cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ)
|
|||
|
||||
all: cppcheck testrunner
|
||||
|
||||
testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/filelister.o
|
||||
testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/executor.o cli/processexecutor.o cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/filelister.o
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ $^ $(LIBS) $(LDFLAGS) $(RDYNAMIC)
|
||||
|
||||
test: all
|
||||
|
@ -567,16 +572,22 @@ $(libcppdir)/valueflow.o: lib/valueflow.cpp lib/analyzer.h lib/astutils.h lib/ca
|
|||
cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h cli/filelister.h externals/tinyxml2/tinyxml2.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h
|
||||
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/cmdlineparser.o cli/cmdlineparser.cpp
|
||||
|
||||
cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h cli/filelister.h cli/threadexecutor.h externals/simplecpp/simplecpp.h lib/analyzerinfo.h lib/check.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h
|
||||
cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h cli/executor.h cli/filelister.h cli/processexecutor.h cli/threadexecutor.h externals/simplecpp/simplecpp.h lib/analyzerinfo.h lib/check.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h
|
||||
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/cppcheckexecutor.o cli/cppcheckexecutor.cpp
|
||||
|
||||
cli/executor.o: cli/executor.cpp cli/executor.h
|
||||
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/executor.o cli/executor.cpp
|
||||
|
||||
cli/filelister.o: cli/filelister.cpp cli/filelister.h lib/config.h lib/path.h lib/pathmatch.h lib/utils.h
|
||||
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/filelister.o cli/filelister.cpp
|
||||
|
||||
cli/main.o: cli/main.cpp cli/cppcheckexecutor.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h
|
||||
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/main.o cli/main.cpp
|
||||
|
||||
cli/threadexecutor.o: cli/threadexecutor.cpp cli/cppcheckexecutor.h cli/threadexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h
|
||||
cli/processexecutor.o: cli/processexecutor.cpp cli/cppcheckexecutor.h cli/executor.h cli/processexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h
|
||||
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/processexecutor.o cli/processexecutor.cpp
|
||||
|
||||
cli/threadexecutor.o: cli/threadexecutor.cpp cli/cppcheckexecutor.h cli/executor.h cli/threadexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h
|
||||
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o cli/threadexecutor.o cli/threadexecutor.cpp
|
||||
|
||||
test/options.o: test/options.cpp test/options.h
|
||||
|
@ -687,6 +698,9 @@ test/testpostfixoperator.o: test/testpostfixoperator.cpp lib/check.h lib/checkpo
|
|||
test/testpreprocessor.o: test/testpreprocessor.cpp externals/simplecpp/simplecpp.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h test/testsuite.h
|
||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testpreprocessor.o test/testpreprocessor.cpp
|
||||
|
||||
test/testprocessexecutor.o: test/testprocessexecutor.cpp cli/executor.h cli/processexecutor.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h test/testutils.h
|
||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testprocessexecutor.o test/testprocessexecutor.cpp
|
||||
|
||||
test/testrunner.o: test/testrunner.cpp externals/simplecpp/simplecpp.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/preprocessor.h lib/suppressions.h test/options.h test/testsuite.h
|
||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testrunner.o test/testrunner.cpp
|
||||
|
||||
|
@ -717,13 +731,13 @@ test/testsuite.o: test/testsuite.cpp lib/color.h lib/config.h lib/errorlogger.h
|
|||
test/testsummaries.o: test/testsummaries.cpp lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/summaries.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h
|
||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testsummaries.o test/testsummaries.cpp
|
||||
|
||||
test/testsuppressions.o: test/testsuppressions.cpp cli/threadexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h test/testutils.h
|
||||
test/testsuppressions.o: test/testsuppressions.cpp cli/executor.h cli/threadexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h test/testutils.h
|
||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testsuppressions.o test/testsuppressions.cpp
|
||||
|
||||
test/testsymboldatabase.o: test/testsymboldatabase.cpp externals/tinyxml2/tinyxml2.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h test/testutils.h
|
||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testsymboldatabase.o test/testsymboldatabase.cpp
|
||||
|
||||
test/testthreadexecutor.o: test/testthreadexecutor.cpp cli/threadexecutor.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h test/testutils.h
|
||||
test/testthreadexecutor.o: test/testthreadexecutor.cpp cli/executor.h cli/threadexecutor.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h test/testutils.h
|
||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testthreadexecutor.o test/testthreadexecutor.cpp
|
||||
|
||||
test/testtimer.o: test/testtimer.cpp lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/suppressions.h lib/timer.h test/testsuite.h
|
||||
|
|
|
@ -4063,8 +4063,9 @@ class MisraChecker:
|
|||
errmsg = 'misra violation (use --rule-texts=<file> to get proper output)'
|
||||
if self.path_premium_addon:
|
||||
for line in cppcheckdata.cmd_output([self.path_premium_addon, '--cli', '--get-rule-text=' + errorId]).split('\n'):
|
||||
if not line.startswith('{'):
|
||||
errmsg = line
|
||||
if len(line) > 1 and not line.startswith('{'):
|
||||
errmsg = line.strip()
|
||||
break
|
||||
else:
|
||||
errmsg = 'misra violation %s with no text in the supplied rule-texts-file' % (ruleNum)
|
||||
|
||||
|
|
|
@ -36,11 +36,17 @@
|
|||
<define name="G_STRINGIFY_ARG(contents)" value="#contents"/>
|
||||
<define name="G_STRLOC" value="__FILE__ ":" G_STRINGIFY (__LINE__)"/>
|
||||
<define name="G_STRFUNC" value="((const char*) (__FUNCTION__))"/>
|
||||
<define name="G_DEFINE_TYPE(TN, t_n, T_P)" value=""/>
|
||||
<define name="G_DEFINE_TYPE_WITH_PRIVATE(TN, t_n, T_P)" value=""/>
|
||||
<define name="G_DEFINE_TYPE_WITH_CODE(TN, t_n, T_P, _C_)" value=""/>
|
||||
<define name="G_DEFINE_FINAL_TYPE(TN, t_n, T_P)" value=""/>
|
||||
<define name="G_DEFINE_FINAL_TYPE_WITH_PRIVATE(TN, t_n, T_P)" value=""/>
|
||||
<define name="G_DEFINE_FINAL_TYPE_WITH_CODE(TN, t_n, T_P, _C_)" value=""/>
|
||||
<define name="G_DEFINE_ABSTRACT_TYPE(TN, t_n, T_P)" value=""/>
|
||||
<define name="G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(TN, t_n, T_P)" value=""/>
|
||||
<define name="G_DEFINE_ABSTRACT_TYPE_WITH_CODE(TN, t_n, T_P, _C_)" value=""/>
|
||||
<define name="G_DEFINE_DYNAMIC_TYPE(TN, t_n, T_P)" value=""/>
|
||||
<define name="G_DEFINE_DYNAMIC_TYPE_EXTENDED(TN, t_n, T_P, _f_, _C_)" value=""/>
|
||||
<define name="G_DEFINE_BOXED_TYPE(TypeName,type_name,copy_func,free_func)" value=""/>
|
||||
<define name="G_DEFINE_BOXED_TYPE_WITH_CODE(TypeName,type_name,copy_func,free_func,_C_)" value=""/>
|
||||
<define name="G_ADD_PRIVATE(TypeName)" value=""/>
|
||||
|
@ -51,6 +57,9 @@
|
|||
<define name="G_DEFINE_INTERFACE_WITH_CODE(TN, t_n, T_P, _C_)" value=""/>
|
||||
<define name="G_DEFINE_TYPE_EXTENDED(TN, t_n, T_P, _f_, _C_)" value=""/>
|
||||
<define name="G_IMPLEMENT_INTERFACE(TYPE_IFACE, iface_init)" value=""/>
|
||||
<define name="G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TypeName, func)" value=""/>
|
||||
<define name="G_DEFINE_AUTO_CLEANUP_FREE_FUNC(TypeName, func, none)" value=""/>
|
||||
<define name="G_DEFINE_AUTOPTR_CLEANUP_FUNC(TypeName, func)" value=""/>
|
||||
<define name="MAX(a, b)" value="(((a) > (b)) ? (a) : (b))"/>
|
||||
<define name="MIN(a, b)" value="(((a) < (b)) ? (a) : (b))"/>
|
||||
<define name="ABS(a)" value="(((a) < 0) ? -(a) : (a))"/>
|
||||
|
|
|
@ -13679,8 +13679,8 @@ wxItemKind kind = wxITEM_NORMAL) -->
|
|||
<const/>
|
||||
<use-retval/>
|
||||
<leak-ignore/>
|
||||
<arg nr="1" direction="in"/>
|
||||
<arg nr="2" default="0" direction="in">
|
||||
<arg nr="1" direction="out"/>
|
||||
<arg nr="2" default="0" direction="out">
|
||||
<not-uninit/>
|
||||
<not-bool/>
|
||||
</arg>
|
||||
|
|
|
@ -39,9 +39,7 @@ endif()
|
|||
if(tinyxml2_FOUND AND NOT USE_BUNDLED_TINYXML2)
|
||||
target_link_libraries(cppcheck ${tinyxml2_LIBRARIES})
|
||||
endif()
|
||||
if (USE_THREADS)
|
||||
target_link_libraries(cppcheck ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
target_link_libraries(cppcheck ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
add_dependencies(cppcheck copy_cfg)
|
||||
add_dependencies(cppcheck copy_addons)
|
||||
|
|
|
@ -407,7 +407,9 @@
|
|||
<ClInclude Include="..\lib\config.h" />
|
||||
<ClInclude Include="cmdlineparser.h" />
|
||||
<ClInclude Include="cppcheckexecutor.h" />
|
||||
<ClInclude Include="executor.h" />
|
||||
<ClInclude Include="filelister.h" />
|
||||
<ClInclude Include="processexecutor.h" />
|
||||
<ClInclude Include="threadexecutor.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -418,8 +420,10 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="cmdlineparser.cpp" />
|
||||
<ClCompile Include="cppcheckexecutor.cpp" />
|
||||
<ClCompile Include="executor.cpp" />
|
||||
<ClCompile Include="filelister.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="processexecutor.cpp" />
|
||||
<ClCompile Include="threadexecutor.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
@ -36,6 +36,12 @@
|
|||
#include "utils.h"
|
||||
#include "checkunusedfunctions.h"
|
||||
|
||||
#if defined(THREADING_MODEL_THREAD)
|
||||
#include "threadexecutor.h"
|
||||
#elif defined(THREADING_MODEL_FORK)
|
||||
#include "processexecutor.h"
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <csignal>
|
||||
|
@ -122,7 +128,7 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c
|
|||
|
||||
if (parser.getShowErrorMessages()) {
|
||||
mShowAllErrors = true;
|
||||
std::cout << ErrorMessage::getXMLHeader();
|
||||
std::cout << ErrorMessage::getXMLHeader(settings.cppcheckCfgProductName);
|
||||
cppcheck->getErrorMessages();
|
||||
std::cout << ErrorMessage::getXMLFooter() << std::endl;
|
||||
}
|
||||
|
@ -908,7 +914,7 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck)
|
|||
}
|
||||
|
||||
if (settings.xml) {
|
||||
reportErr(ErrorMessage::getXMLHeader());
|
||||
reportErr(ErrorMessage::getXMLHeader(settings.cppcheckCfgProductName));
|
||||
}
|
||||
|
||||
if (!settings.buildDir.empty()) {
|
||||
|
@ -972,8 +978,11 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck)
|
|||
} else if (!ThreadExecutor::isEnabled()) {
|
||||
std::cout << "No thread support yet implemented for this platform." << std::endl;
|
||||
} else {
|
||||
// Multiple processes
|
||||
#if defined(THREADING_MODEL_THREAD)
|
||||
ThreadExecutor executor(mFiles, settings, *this);
|
||||
#elif defined(THREADING_MODEL_FORK)
|
||||
ProcessExecutor executor(mFiles, settings, *this);
|
||||
#endif
|
||||
returnValue = executor.check();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Cppcheck - A tool for static C/C++ code analysis
|
||||
* Copyright (C) 2007-2022 Cppcheck team.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "executor.h"
|
||||
|
||||
Executor::Executor(const std::map<std::string, std::size_t> &files, Settings &settings, ErrorLogger &errorLogger)
|
||||
: mFiles(files), mSettings(settings), mErrorLogger(errorLogger)
|
||||
{}
|
||||
|
||||
Executor::~Executor()
|
||||
{}
|
||||
|
||||
bool Executor::isEnabled() {
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Cppcheck - A tool for static C/C++ code analysis
|
||||
* Copyright (C) 2007-2022 Cppcheck team.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EXECUTOR_H
|
||||
#define EXECUTOR_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class Settings;
|
||||
class ErrorLogger;
|
||||
|
||||
/// @addtogroup CLI
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* This class will take a list of filenames and settings and check then
|
||||
* all files using threads.
|
||||
*/
|
||||
class Executor {
|
||||
public:
|
||||
Executor(const std::map<std::string, std::size_t> &files, Settings &settings, ErrorLogger &errorLogger);
|
||||
Executor(const Executor &) = delete;
|
||||
virtual ~Executor();
|
||||
void operator=(const Executor &) = delete;
|
||||
|
||||
virtual unsigned int check() = 0;
|
||||
|
||||
/**
|
||||
* @return true if support for threads exist.
|
||||
*/
|
||||
static bool isEnabled();
|
||||
|
||||
protected:
|
||||
const std::map<std::string, std::size_t> &mFiles;
|
||||
Settings &mSettings;
|
||||
ErrorLogger &mErrorLogger;
|
||||
std::list<std::string> mErrorList;
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
||||
#endif // EXECUTOR_H
|
|
@ -0,0 +1,383 @@
|
|||
/*
|
||||
* Cppcheck - A tool for static C/C++ code analysis
|
||||
* Copyright (C) 2007-2022 Cppcheck team.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "processexecutor.h"
|
||||
|
||||
#if !defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||
|
||||
#include "color.h"
|
||||
#include "config.h"
|
||||
#include "cppcheck.h"
|
||||
#include "cppcheckexecutor.h"
|
||||
#include "errorlogger.h"
|
||||
#include "errortypes.h"
|
||||
#include "importproject.h"
|
||||
#include "settings.h"
|
||||
#include "suppressions.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <csignal>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <sys/select.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <utility>
|
||||
|
||||
#ifdef __SVR4 // Solaris
|
||||
#include <sys/loadavg.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
|
||||
// NOLINTNEXTLINE(misc-unused-using-decls) - required for FD_ZERO
|
||||
using std::memset;
|
||||
|
||||
|
||||
ProcessExecutor::ProcessExecutor(const std::map<std::string, std::size_t> &files, Settings &settings, ErrorLogger &errorLogger)
|
||||
: Executor(files, settings, errorLogger)
|
||||
{}
|
||||
|
||||
ProcessExecutor::~ProcessExecutor()
|
||||
{}
|
||||
|
||||
class PipeWriter : public ErrorLogger {
|
||||
public:
|
||||
enum PipeSignal {REPORT_OUT='1',REPORT_ERROR='2', REPORT_INFO='3', REPORT_VERIFICATION='4', CHILD_END='5'};
|
||||
|
||||
explicit PipeWriter(int pipe) : mWpipe(pipe) {}
|
||||
|
||||
void reportOut(const std::string &outmsg, Color c) override {
|
||||
writeToPipe(REPORT_OUT, ::toString(c) + outmsg + ::toString(Color::Reset));
|
||||
}
|
||||
|
||||
void reportErr(const ErrorMessage &msg) override {
|
||||
report(msg, MessageType::REPORT_ERROR);
|
||||
}
|
||||
|
||||
void reportInfo(const ErrorMessage &msg) override {
|
||||
report(msg, MessageType::REPORT_INFO);
|
||||
}
|
||||
|
||||
void writeEnd(const std::string& str) {
|
||||
writeToPipe(CHILD_END, str);
|
||||
}
|
||||
|
||||
private:
|
||||
enum class MessageType {REPORT_ERROR, REPORT_INFO};
|
||||
|
||||
void report(const ErrorMessage &msg, MessageType msgType) {
|
||||
PipeSignal pipeSignal;
|
||||
switch (msgType) {
|
||||
case MessageType::REPORT_ERROR:
|
||||
pipeSignal = REPORT_ERROR;
|
||||
break;
|
||||
case MessageType::REPORT_INFO:
|
||||
pipeSignal = REPORT_INFO;
|
||||
break;
|
||||
}
|
||||
|
||||
writeToPipe(pipeSignal, msg.serialize());
|
||||
}
|
||||
|
||||
void writeToPipe(PipeSignal type, const std::string &data)
|
||||
{
|
||||
unsigned int len = static_cast<unsigned int>(data.length() + 1);
|
||||
char *out = new char[len + 1 + sizeof(len)];
|
||||
out[0] = static_cast<char>(type);
|
||||
std::memcpy(&(out[1]), &len, sizeof(len));
|
||||
std::memcpy(&(out[1+sizeof(len)]), data.c_str(), len);
|
||||
if (write(mWpipe, out, len + 1 + sizeof(len)) <= 0) {
|
||||
delete[] out;
|
||||
out = nullptr;
|
||||
std::cerr << "#### ThreadExecutor::writeToPipe, Failed to write to pipe" << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
delete[] out;
|
||||
}
|
||||
|
||||
const int mWpipe;
|
||||
};
|
||||
|
||||
int ProcessExecutor::handleRead(int rpipe, unsigned int &result)
|
||||
{
|
||||
char type = 0;
|
||||
if (read(rpipe, &type, 1) <= 0) {
|
||||
if (errno == EAGAIN)
|
||||
return 0;
|
||||
|
||||
// need to increment so a missing pipe (i.e. premature exit of forked process) results in an error exitcode
|
||||
++result;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (type != PipeWriter::REPORT_OUT && type != PipeWriter::REPORT_ERROR && type != PipeWriter::REPORT_INFO && type != PipeWriter::CHILD_END) {
|
||||
std::cerr << "#### ThreadExecutor::handleRead error, type was:" << type << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
unsigned int len = 0;
|
||||
if (read(rpipe, &len, sizeof(len)) <= 0) {
|
||||
std::cerr << "#### ThreadExecutor::handleRead error, type was:" << type << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Don't rely on incoming data being null-terminated.
|
||||
// Allocate +1 element and null-terminate the buffer.
|
||||
char *buf = new char[len + 1];
|
||||
const ssize_t readIntoBuf = read(rpipe, buf, len);
|
||||
if (readIntoBuf <= 0) {
|
||||
std::cerr << "#### ThreadExecutor::handleRead error, type was:" << type << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
buf[readIntoBuf] = 0;
|
||||
|
||||
if (type == PipeWriter::REPORT_OUT) {
|
||||
mErrorLogger.reportOut(buf);
|
||||
} else if (type == PipeWriter::REPORT_ERROR || type == PipeWriter::REPORT_INFO) {
|
||||
ErrorMessage msg;
|
||||
try {
|
||||
msg.deserialize(buf);
|
||||
} catch (const InternalError& e) {
|
||||
std::cerr << "#### ThreadExecutor::handleRead error, internal error:" << e.errorMessage << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!mSettings.nomsg.isSuppressed(msg.toSuppressionsErrorMessage())) {
|
||||
// Alert only about unique errors
|
||||
std::string errmsg = msg.toString(mSettings.verbose);
|
||||
if (std::find(mErrorList.begin(), mErrorList.end(), errmsg) == mErrorList.end()) {
|
||||
mErrorList.emplace_back(errmsg);
|
||||
if (type == PipeWriter::REPORT_ERROR)
|
||||
mErrorLogger.reportErr(msg);
|
||||
else
|
||||
mErrorLogger.reportInfo(msg);
|
||||
}
|
||||
}
|
||||
} else if (type == PipeWriter::CHILD_END) {
|
||||
std::istringstream iss(buf);
|
||||
unsigned int fileResult = 0;
|
||||
iss >> fileResult;
|
||||
result += fileResult;
|
||||
delete[] buf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
delete[] buf;
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool ProcessExecutor::checkLoadAverage(size_t nchildren)
|
||||
{
|
||||
#if defined(__CYGWIN__) || defined(__QNX__) || defined(__HAIKU__) // getloadavg() is unsupported on Cygwin, Qnx, Haiku.
|
||||
(void)nchildren;
|
||||
return true;
|
||||
#else
|
||||
if (!nchildren || !mSettings.loadAverage) {
|
||||
return true;
|
||||
}
|
||||
|
||||
double sample(0);
|
||||
if (getloadavg(&sample, 1) != 1) {
|
||||
// disable load average checking on getloadavg error
|
||||
return true;
|
||||
} else if (sample < mSettings.loadAverage) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int ProcessExecutor::check()
|
||||
{
|
||||
unsigned int fileCount = 0;
|
||||
unsigned int result = 0;
|
||||
|
||||
std::size_t totalfilesize = 0;
|
||||
for (std::map<std::string, std::size_t>::const_iterator i = mFiles.begin(); i != mFiles.end(); ++i) {
|
||||
totalfilesize += i->second;
|
||||
}
|
||||
|
||||
std::list<int> rpipes;
|
||||
std::map<pid_t, std::string> childFile;
|
||||
std::map<int, std::string> pipeFile;
|
||||
std::size_t processedsize = 0;
|
||||
std::map<std::string, std::size_t>::const_iterator iFile = mFiles.begin();
|
||||
std::list<ImportProject::FileSettings>::const_iterator iFileSettings = mSettings.project.fileSettings.begin();
|
||||
for (;;) {
|
||||
// Start a new child
|
||||
size_t nchildren = childFile.size();
|
||||
if ((iFile != mFiles.end() || iFileSettings != mSettings.project.fileSettings.end()) && nchildren < mSettings.jobs && checkLoadAverage(nchildren)) {
|
||||
int pipes[2];
|
||||
if (pipe(pipes) == -1) {
|
||||
std::cerr << "#### ThreadExecutor::check, pipe() failed: "<< std::strerror(errno) << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int flags = 0;
|
||||
if ((flags = fcntl(pipes[0], F_GETFL, 0)) < 0) {
|
||||
std::cerr << "#### ThreadExecutor::check, fcntl(F_GETFL) failed: "<< std::strerror(errno) << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (fcntl(pipes[0], F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
std::cerr << "#### ThreadExecutor::check, fcntl(F_SETFL) failed: "<< std::strerror(errno) << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
// Error
|
||||
std::cerr << "#### ThreadExecutor::check, Failed to create child process: "<< std::strerror(errno) << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
} else if (pid == 0) {
|
||||
#if defined(__linux__)
|
||||
prctl(PR_SET_PDEATHSIG, SIGHUP);
|
||||
#endif
|
||||
close(pipes[0]);
|
||||
|
||||
PipeWriter pipewriter(pipes[1]);
|
||||
CppCheck fileChecker(pipewriter, false, CppCheckExecutor::executeCommand);
|
||||
fileChecker.settings() = mSettings;
|
||||
unsigned int resultOfCheck = 0;
|
||||
|
||||
if (iFileSettings != mSettings.project.fileSettings.end()) {
|
||||
resultOfCheck = fileChecker.check(*iFileSettings);
|
||||
} else {
|
||||
// Read file from a file
|
||||
resultOfCheck = fileChecker.check(iFile->first);
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << resultOfCheck;
|
||||
pipewriter.writeEnd(oss.str());
|
||||
std::exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
close(pipes[1]);
|
||||
rpipes.push_back(pipes[0]);
|
||||
if (iFileSettings != mSettings.project.fileSettings.end()) {
|
||||
childFile[pid] = iFileSettings->filename + ' ' + iFileSettings->cfg;
|
||||
pipeFile[pipes[0]] = iFileSettings->filename + ' ' + iFileSettings->cfg;
|
||||
++iFileSettings;
|
||||
} else {
|
||||
childFile[pid] = iFile->first;
|
||||
pipeFile[pipes[0]] = iFile->first;
|
||||
++iFile;
|
||||
}
|
||||
}
|
||||
if (!rpipes.empty()) {
|
||||
fd_set rfds;
|
||||
FD_ZERO(&rfds);
|
||||
for (std::list<int>::const_iterator rp = rpipes.begin(); rp != rpipes.end(); ++rp)
|
||||
FD_SET(*rp, &rfds);
|
||||
struct timeval tv; // for every second polling of load average condition
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
int r = select(*std::max_element(rpipes.begin(), rpipes.end()) + 1, &rfds, nullptr, nullptr, &tv);
|
||||
|
||||
if (r > 0) {
|
||||
std::list<int>::iterator rp = rpipes.begin();
|
||||
while (rp != rpipes.end()) {
|
||||
if (FD_ISSET(*rp, &rfds)) {
|
||||
int readRes = handleRead(*rp, result);
|
||||
if (readRes == -1) {
|
||||
std::size_t size = 0;
|
||||
std::map<int, std::string>::iterator p = pipeFile.find(*rp);
|
||||
if (p != pipeFile.end()) {
|
||||
std::string name = p->second;
|
||||
pipeFile.erase(p);
|
||||
std::map<std::string, std::size_t>::const_iterator fs = mFiles.find(name);
|
||||
if (fs != mFiles.end()) {
|
||||
size = fs->second;
|
||||
}
|
||||
}
|
||||
|
||||
fileCount++;
|
||||
processedsize += size;
|
||||
if (!mSettings.quiet)
|
||||
CppCheckExecutor::reportStatus(fileCount, mFiles.size() + mSettings.project.fileSettings.size(), processedsize, totalfilesize);
|
||||
|
||||
close(*rp);
|
||||
rp = rpipes.erase(rp);
|
||||
} else
|
||||
++rp;
|
||||
} else
|
||||
++rp;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!childFile.empty()) {
|
||||
int stat = 0;
|
||||
pid_t child = waitpid(0, &stat, WNOHANG);
|
||||
if (child > 0) {
|
||||
std::string childname;
|
||||
std::map<pid_t, std::string>::iterator c = childFile.find(child);
|
||||
if (c != childFile.end()) {
|
||||
childname = c->second;
|
||||
childFile.erase(c);
|
||||
}
|
||||
|
||||
if (WIFEXITED(stat)) {
|
||||
const int exitstatus = WEXITSTATUS(stat);
|
||||
if (exitstatus != EXIT_SUCCESS) {
|
||||
std::ostringstream oss;
|
||||
oss << "Child process exited with " << exitstatus;
|
||||
reportInternalChildErr(childname, oss.str());
|
||||
}
|
||||
} else if (WIFSIGNALED(stat)) {
|
||||
std::ostringstream oss;
|
||||
oss << "Child process crashed with signal " << WTERMSIG(stat);
|
||||
reportInternalChildErr(childname, oss.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (iFile == mFiles.end() && iFileSettings == mSettings.project.fileSettings.end() && rpipes.empty() && childFile.empty()) {
|
||||
// All done
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ProcessExecutor::reportInternalChildErr(const std::string &childname, const std::string &msg)
|
||||
{
|
||||
std::list<ErrorMessage::FileLocation> locations;
|
||||
locations.emplace_back(childname, 0, 0);
|
||||
const ErrorMessage errmsg(locations,
|
||||
emptyString,
|
||||
Severity::error,
|
||||
"Internal error: " + msg,
|
||||
"cppcheckError",
|
||||
Certainty::normal);
|
||||
|
||||
if (!mSettings.nomsg.isSuppressed(errmsg.toSuppressionsErrorMessage()))
|
||||
mErrorLogger.reportErr(errmsg);
|
||||
}
|
||||
|
||||
#endif // !WIN32
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Cppcheck - A tool for static C/C++ code analysis
|
||||
* Copyright (C) 2007-2022 Cppcheck team.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PROCESSEXECUTOR_H
|
||||
#define PROCESSEXECUTOR_H
|
||||
|
||||
#include "executor.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class Settings;
|
||||
class ErrorLogger;
|
||||
|
||||
/// @addtogroup CLI
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* This class will take a list of filenames and settings and check then
|
||||
* all files using threads.
|
||||
*/
|
||||
class ProcessExecutor : public Executor {
|
||||
public:
|
||||
ProcessExecutor(const std::map<std::string, std::size_t> &files, Settings &settings, ErrorLogger &errorLogger);
|
||||
ProcessExecutor(const ProcessExecutor &) = delete;
|
||||
~ProcessExecutor();
|
||||
void operator=(const ProcessExecutor &) = delete;
|
||||
|
||||
unsigned int check() override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Read from the pipe, parse and handle what ever is in there.
|
||||
*@return -1 in case of error
|
||||
* 0 if there is nothing in the pipe to be read
|
||||
* 1 if we did read something
|
||||
*/
|
||||
int handleRead(int rpipe, unsigned int &result);
|
||||
|
||||
/**
|
||||
* @brief Check load average condition
|
||||
* @param nchildren - count of currently ran children
|
||||
* @return true - if new process can be started
|
||||
*/
|
||||
bool checkLoadAverage(size_t nchildren);
|
||||
|
||||
/**
|
||||
* @brief Reports internal errors related to child processes
|
||||
* @param msg The error message
|
||||
*/
|
||||
void reportInternalChildErr(const std::string &childname, const std::string &msg);
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
||||
#endif // PROCESSEXECUTOR_H
|
|
@ -29,379 +29,33 @@
|
|||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
#ifdef __SVR4 // Solaris
|
||||
#include <sys/loadavg.h>
|
||||
#endif
|
||||
|
||||
#ifdef THREADING_MODEL_FORK
|
||||
#include "config.h"
|
||||
#include "errortypes.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <sys/select.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <csignal>
|
||||
#include <unistd.h>
|
||||
|
||||
// NOLINTNEXTLINE(misc-unused-using-decls) - required for FD_ZERO
|
||||
using std::memset;
|
||||
#endif
|
||||
|
||||
#ifdef THREADING_MODEL_THREAD
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <numeric>
|
||||
#endif
|
||||
#include <mutex>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
ThreadExecutor::ThreadExecutor(const std::map<std::string, std::size_t> &files, Settings &settings, ErrorLogger &errorLogger)
|
||||
: mFiles(files), mSettings(settings), mErrorLogger(errorLogger)
|
||||
: Executor(files, settings, errorLogger)
|
||||
{}
|
||||
|
||||
ThreadExecutor::~ThreadExecutor()
|
||||
{}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
////// This code is for platforms that support fork() only ////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(THREADING_MODEL_FORK)
|
||||
|
||||
class PipeWriter : public ErrorLogger {
|
||||
public:
|
||||
enum PipeSignal {REPORT_OUT='1',REPORT_ERROR='2', REPORT_INFO='3', REPORT_VERIFICATION='4', CHILD_END='5'};
|
||||
|
||||
explicit PipeWriter(int pipe) : mWpipe(pipe) {}
|
||||
|
||||
void reportOut(const std::string &outmsg, Color c) override {
|
||||
writeToPipe(REPORT_OUT, ::toString(c) + outmsg + ::toString(Color::Reset));
|
||||
}
|
||||
|
||||
void reportErr(const ErrorMessage &msg) override {
|
||||
report(msg, MessageType::REPORT_ERROR);
|
||||
}
|
||||
|
||||
void reportInfo(const ErrorMessage &msg) override {
|
||||
report(msg, MessageType::REPORT_INFO);
|
||||
}
|
||||
|
||||
void writeEnd(const std::string& str) {
|
||||
writeToPipe(CHILD_END, str);
|
||||
}
|
||||
|
||||
private:
|
||||
enum class MessageType {REPORT_ERROR, REPORT_INFO};
|
||||
|
||||
void report(const ErrorMessage &msg, MessageType msgType) {
|
||||
PipeSignal pipeSignal;
|
||||
switch (msgType) {
|
||||
case MessageType::REPORT_ERROR:
|
||||
pipeSignal = REPORT_ERROR;
|
||||
break;
|
||||
case MessageType::REPORT_INFO:
|
||||
pipeSignal = REPORT_INFO;
|
||||
break;
|
||||
}
|
||||
|
||||
writeToPipe(pipeSignal, msg.serialize());
|
||||
}
|
||||
|
||||
void writeToPipe(PipeSignal type, const std::string &data)
|
||||
{
|
||||
unsigned int len = static_cast<unsigned int>(data.length() + 1);
|
||||
char *out = new char[len + 1 + sizeof(len)];
|
||||
out[0] = static_cast<char>(type);
|
||||
std::memcpy(&(out[1]), &len, sizeof(len));
|
||||
std::memcpy(&(out[1+sizeof(len)]), data.c_str(), len);
|
||||
if (write(mWpipe, out, len + 1 + sizeof(len)) <= 0) {
|
||||
delete[] out;
|
||||
out = nullptr;
|
||||
std::cerr << "#### ThreadExecutor::writeToPipe, Failed to write to pipe" << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
delete[] out;
|
||||
}
|
||||
|
||||
const int mWpipe;
|
||||
};
|
||||
|
||||
int ThreadExecutor::handleRead(int rpipe, unsigned int &result)
|
||||
{
|
||||
char type = 0;
|
||||
if (read(rpipe, &type, 1) <= 0) {
|
||||
if (errno == EAGAIN)
|
||||
return 0;
|
||||
|
||||
// need to increment so a missing pipe (i.e. premature exit of forked process) results in an error exitcode
|
||||
++result;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (type != PipeWriter::REPORT_OUT && type != PipeWriter::REPORT_ERROR && type != PipeWriter::REPORT_INFO && type != PipeWriter::CHILD_END) {
|
||||
std::cerr << "#### ThreadExecutor::handleRead error, type was:" << type << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
unsigned int len = 0;
|
||||
if (read(rpipe, &len, sizeof(len)) <= 0) {
|
||||
std::cerr << "#### ThreadExecutor::handleRead error, type was:" << type << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Don't rely on incoming data being null-terminated.
|
||||
// Allocate +1 element and null-terminate the buffer.
|
||||
char *buf = new char[len + 1];
|
||||
const ssize_t readIntoBuf = read(rpipe, buf, len);
|
||||
if (readIntoBuf <= 0) {
|
||||
std::cerr << "#### ThreadExecutor::handleRead error, type was:" << type << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
buf[readIntoBuf] = 0;
|
||||
|
||||
if (type == PipeWriter::REPORT_OUT) {
|
||||
mErrorLogger.reportOut(buf);
|
||||
} else if (type == PipeWriter::REPORT_ERROR || type == PipeWriter::REPORT_INFO) {
|
||||
ErrorMessage msg;
|
||||
try {
|
||||
msg.deserialize(buf);
|
||||
} catch (const InternalError& e) {
|
||||
std::cerr << "#### ThreadExecutor::handleRead error, internal error:" << e.errorMessage << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!mSettings.nomsg.isSuppressed(msg.toSuppressionsErrorMessage())) {
|
||||
// Alert only about unique errors
|
||||
std::string errmsg = msg.toString(mSettings.verbose);
|
||||
if (std::find(mErrorList.begin(), mErrorList.end(), errmsg) == mErrorList.end()) {
|
||||
mErrorList.emplace_back(errmsg);
|
||||
if (type == PipeWriter::REPORT_ERROR)
|
||||
mErrorLogger.reportErr(msg);
|
||||
else
|
||||
mErrorLogger.reportInfo(msg);
|
||||
}
|
||||
}
|
||||
} else if (type == PipeWriter::CHILD_END) {
|
||||
std::istringstream iss(buf);
|
||||
unsigned int fileResult = 0;
|
||||
iss >> fileResult;
|
||||
result += fileResult;
|
||||
delete[] buf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
delete[] buf;
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool ThreadExecutor::checkLoadAverage(size_t nchildren)
|
||||
{
|
||||
#if defined(__CYGWIN__) || defined(__QNX__) || defined(__HAIKU__) // getloadavg() is unsupported on Cygwin, Qnx, Haiku.
|
||||
return true;
|
||||
#else
|
||||
if (!nchildren || !mSettings.loadAverage) {
|
||||
return true;
|
||||
}
|
||||
|
||||
double sample(0);
|
||||
if (getloadavg(&sample, 1) != 1) {
|
||||
// disable load average checking on getloadavg error
|
||||
return true;
|
||||
} else if (sample < mSettings.loadAverage) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int ThreadExecutor::check()
|
||||
{
|
||||
unsigned int fileCount = 0;
|
||||
unsigned int result = 0;
|
||||
|
||||
std::size_t totalfilesize = 0;
|
||||
for (std::map<std::string, std::size_t>::const_iterator i = mFiles.begin(); i != mFiles.end(); ++i) {
|
||||
totalfilesize += i->second;
|
||||
}
|
||||
|
||||
std::list<int> rpipes;
|
||||
std::map<pid_t, std::string> childFile;
|
||||
std::map<int, std::string> pipeFile;
|
||||
std::size_t processedsize = 0;
|
||||
std::map<std::string, std::size_t>::const_iterator iFile = mFiles.begin();
|
||||
std::list<ImportProject::FileSettings>::const_iterator iFileSettings = mSettings.project.fileSettings.begin();
|
||||
for (;;) {
|
||||
// Start a new child
|
||||
size_t nchildren = childFile.size();
|
||||
if ((iFile != mFiles.end() || iFileSettings != mSettings.project.fileSettings.end()) && nchildren < mSettings.jobs && checkLoadAverage(nchildren)) {
|
||||
int pipes[2];
|
||||
if (pipe(pipes) == -1) {
|
||||
std::cerr << "#### ThreadExecutor::check, pipe() failed: "<< std::strerror(errno) << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int flags = 0;
|
||||
if ((flags = fcntl(pipes[0], F_GETFL, 0)) < 0) {
|
||||
std::cerr << "#### ThreadExecutor::check, fcntl(F_GETFL) failed: "<< std::strerror(errno) << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (fcntl(pipes[0], F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
std::cerr << "#### ThreadExecutor::check, fcntl(F_SETFL) failed: "<< std::strerror(errno) << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
// Error
|
||||
std::cerr << "#### ThreadExecutor::check, Failed to create child process: "<< std::strerror(errno) << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
} else if (pid == 0) {
|
||||
#if defined(__linux__)
|
||||
prctl(PR_SET_PDEATHSIG, SIGHUP);
|
||||
#endif
|
||||
close(pipes[0]);
|
||||
|
||||
PipeWriter pipewriter(pipes[1]);
|
||||
CppCheck fileChecker(pipewriter, false, CppCheckExecutor::executeCommand);
|
||||
fileChecker.settings() = mSettings;
|
||||
unsigned int resultOfCheck = 0;
|
||||
|
||||
if (iFileSettings != mSettings.project.fileSettings.end()) {
|
||||
resultOfCheck = fileChecker.check(*iFileSettings);
|
||||
} else {
|
||||
// Read file from a file
|
||||
resultOfCheck = fileChecker.check(iFile->first);
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << resultOfCheck;
|
||||
pipewriter.writeEnd(oss.str());
|
||||
std::exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
close(pipes[1]);
|
||||
rpipes.push_back(pipes[0]);
|
||||
if (iFileSettings != mSettings.project.fileSettings.end()) {
|
||||
childFile[pid] = iFileSettings->filename + ' ' + iFileSettings->cfg;
|
||||
pipeFile[pipes[0]] = iFileSettings->filename + ' ' + iFileSettings->cfg;
|
||||
++iFileSettings;
|
||||
} else {
|
||||
childFile[pid] = iFile->first;
|
||||
pipeFile[pipes[0]] = iFile->first;
|
||||
++iFile;
|
||||
}
|
||||
}
|
||||
if (!rpipes.empty()) {
|
||||
fd_set rfds;
|
||||
FD_ZERO(&rfds);
|
||||
for (std::list<int>::const_iterator rp = rpipes.begin(); rp != rpipes.end(); ++rp)
|
||||
FD_SET(*rp, &rfds);
|
||||
struct timeval tv; // for every second polling of load average condition
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
int r = select(*std::max_element(rpipes.begin(), rpipes.end()) + 1, &rfds, nullptr, nullptr, &tv);
|
||||
|
||||
if (r > 0) {
|
||||
std::list<int>::iterator rp = rpipes.begin();
|
||||
while (rp != rpipes.end()) {
|
||||
if (FD_ISSET(*rp, &rfds)) {
|
||||
int readRes = handleRead(*rp, result);
|
||||
if (readRes == -1) {
|
||||
std::size_t size = 0;
|
||||
std::map<int, std::string>::iterator p = pipeFile.find(*rp);
|
||||
if (p != pipeFile.end()) {
|
||||
std::string name = p->second;
|
||||
pipeFile.erase(p);
|
||||
std::map<std::string, std::size_t>::const_iterator fs = mFiles.find(name);
|
||||
if (fs != mFiles.end()) {
|
||||
size = fs->second;
|
||||
}
|
||||
}
|
||||
|
||||
fileCount++;
|
||||
processedsize += size;
|
||||
if (!mSettings.quiet)
|
||||
CppCheckExecutor::reportStatus(fileCount, mFiles.size() + mSettings.project.fileSettings.size(), processedsize, totalfilesize);
|
||||
|
||||
close(*rp);
|
||||
rp = rpipes.erase(rp);
|
||||
} else
|
||||
++rp;
|
||||
} else
|
||||
++rp;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!childFile.empty()) {
|
||||
int stat = 0;
|
||||
pid_t child = waitpid(0, &stat, WNOHANG);
|
||||
if (child > 0) {
|
||||
std::string childname;
|
||||
std::map<pid_t, std::string>::iterator c = childFile.find(child);
|
||||
if (c != childFile.end()) {
|
||||
childname = c->second;
|
||||
childFile.erase(c);
|
||||
}
|
||||
|
||||
if (WIFEXITED(stat)) {
|
||||
const int exitstatus = WEXITSTATUS(stat);
|
||||
if (exitstatus != EXIT_SUCCESS) {
|
||||
std::ostringstream oss;
|
||||
oss << "Child process exited with " << exitstatus;
|
||||
reportInternalChildErr(childname, oss.str());
|
||||
}
|
||||
} else if (WIFSIGNALED(stat)) {
|
||||
std::ostringstream oss;
|
||||
oss << "Child process crashed with signal " << WTERMSIG(stat);
|
||||
reportInternalChildErr(childname, oss.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (iFile == mFiles.end() && iFileSettings == mSettings.project.fileSettings.end() && rpipes.empty() && childFile.empty()) {
|
||||
// All done
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ThreadExecutor::reportInternalChildErr(const std::string &childname, const std::string &msg)
|
||||
{
|
||||
std::list<ErrorMessage::FileLocation> locations;
|
||||
locations.emplace_back(childname, 0, 0);
|
||||
const ErrorMessage errmsg(locations,
|
||||
emptyString,
|
||||
Severity::error,
|
||||
"Internal error: " + msg,
|
||||
"cppcheckError",
|
||||
Certainty::normal);
|
||||
|
||||
if (!mSettings.nomsg.isSuppressed(errmsg.toSuppressionsErrorMessage()))
|
||||
mErrorLogger.reportErr(errmsg);
|
||||
}
|
||||
|
||||
#elif defined(THREADING_MODEL_THREAD)
|
||||
|
||||
class ThreadExecutor::SyncLogForwarder : public ErrorLogger
|
||||
{
|
||||
public:
|
||||
SyncLogForwarder(ThreadExecutor &threadExecutor)
|
||||
explicit SyncLogForwarder(ThreadExecutor &threadExecutor)
|
||||
: mThreadExecutor(threadExecutor), mProcessedFiles(0), mTotalFiles(0), mProcessedSize(0), mTotalFileSize(0) {
|
||||
|
||||
mItNextFile = threadExecutor.mFiles.begin();
|
||||
mItNextFileSettings = threadExecutor.mSettings.project.fileSettings.begin();
|
||||
mItNextFile = mThreadExecutor.mFiles.begin();
|
||||
mItNextFileSettings = mThreadExecutor.mSettings.project.fileSettings.begin();
|
||||
|
||||
mTotalFiles = threadExecutor.mFiles.size() + threadExecutor.mSettings.project.fileSettings.size();
|
||||
for (std::map<std::string, std::size_t>::const_iterator i = threadExecutor.mFiles.begin(); i != threadExecutor.mFiles.end(); ++i) {
|
||||
mTotalFiles = mThreadExecutor.mFiles.size() + mThreadExecutor.mSettings.project.fileSettings.size();
|
||||
for (std::map<std::string, std::size_t>::const_iterator i = mThreadExecutor.mFiles.begin(); i != mThreadExecutor.mFiles.end(); ++i) {
|
||||
mTotalFileSize += i->second;
|
||||
}
|
||||
}
|
||||
|
@ -541,8 +195,3 @@ unsigned int STDCALL ThreadExecutor::threadProc(SyncLogForwarder* logForwarder)
|
|||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ThreadExecutor::isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,9 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "executor.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
|
@ -36,55 +37,18 @@ class ErrorLogger;
|
|||
* This class will take a list of filenames and settings and check then
|
||||
* all files using threads.
|
||||
*/
|
||||
class ThreadExecutor {
|
||||
class ThreadExecutor : public Executor {
|
||||
public:
|
||||
ThreadExecutor(const std::map<std::string, std::size_t> &files, Settings &settings, ErrorLogger &errorLogger);
|
||||
ThreadExecutor(const ThreadExecutor &) = delete;
|
||||
~ThreadExecutor();
|
||||
void operator=(const ThreadExecutor &) = delete;
|
||||
unsigned int check();
|
||||
|
||||
unsigned int check() override;
|
||||
|
||||
private:
|
||||
const std::map<std::string, std::size_t> &mFiles;
|
||||
Settings &mSettings;
|
||||
ErrorLogger &mErrorLogger;
|
||||
std::list<std::string> mErrorList;
|
||||
|
||||
#if defined(THREADING_MODEL_FORK)
|
||||
|
||||
/**
|
||||
* Read from the pipe, parse and handle what ever is in there.
|
||||
*@return -1 in case of error
|
||||
* 0 if there is nothing in the pipe to be read
|
||||
* 1 if we did read something
|
||||
*/
|
||||
int handleRead(int rpipe, unsigned int &result);
|
||||
|
||||
/**
|
||||
* @brief Check load average condition
|
||||
* @param nchildren - count of currently ran children
|
||||
* @return true - if new process can be started
|
||||
*/
|
||||
bool checkLoadAverage(size_t nchildren);
|
||||
|
||||
/**
|
||||
* @brief Reports internal errors related to child processes
|
||||
* @param msg The error message
|
||||
*/
|
||||
void reportInternalChildErr(const std::string &childname, const std::string &msg);
|
||||
|
||||
#elif defined(THREADING_MODEL_THREAD)
|
||||
|
||||
class SyncLogForwarder;
|
||||
static unsigned int STDCALL threadProc(SyncLogForwarder *logforwarder);
|
||||
|
||||
#endif
|
||||
|
||||
public:
|
||||
/**
|
||||
* @return true if support for threads exist.
|
||||
*/
|
||||
static bool isEnabled();
|
||||
static unsigned int STDCALL threadProc(SyncLogForwarder *logForwarder);
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
|
|
@ -68,9 +68,7 @@ if (NOT USE_BUNDLED_TINYXML2)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if (USE_THREADS)
|
||||
find_package(Threads REQUIRED)
|
||||
endif()
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if (USE_BOOST)
|
||||
find_package(Boost COMPONENTS container QUIET)
|
||||
|
|
|
@ -52,9 +52,7 @@ if (HAVE_RULES)
|
|||
endif()
|
||||
message( STATUS )
|
||||
message( STATUS "USE_THREADS = ${USE_THREADS}" )
|
||||
if (USE_THREADS)
|
||||
message( STATUS "CMAKE_THREAD_LIBS_INIT = ${CMAKE_THREAD_LIBS_INIT}" )
|
||||
endif()
|
||||
message( STATUS "CMAKE_THREAD_LIBS_INIT = ${CMAKE_THREAD_LIBS_INIT}" )
|
||||
if (NOT USE_MATCHCOMPILER_OPT MATCHES "Off")
|
||||
message( STATUS )
|
||||
message( STATUS "PYTHON_VERSION_STRING = ${PYTHON_VERSION_STRING}" )
|
||||
|
|
|
@ -45,26 +45,26 @@ Highlighter::Highlighter(QTextDocument *parent,
|
|||
<< "case"
|
||||
<< "catch"
|
||||
<< "char"
|
||||
<< "char8_t"
|
||||
<< "char16_t"
|
||||
<< "char32_t"
|
||||
<< "char8_t"
|
||||
<< "char16_t"
|
||||
<< "char32_t"
|
||||
<< "class"
|
||||
<< "concept"
|
||||
<< "const"
|
||||
<< "consteval"
|
||||
<< "constexpr"
|
||||
<< "constinit"
|
||||
<< "const_cast"
|
||||
<< "const_cast"
|
||||
<< "continue"
|
||||
<< "co_await"
|
||||
<< "co_return"
|
||||
<< "co_yield"
|
||||
<< "co_await"
|
||||
<< "co_return"
|
||||
<< "co_yield"
|
||||
<< "decltype"
|
||||
<< "default"
|
||||
<< "delete"
|
||||
<< "do"
|
||||
<< "double"
|
||||
<< "dynamic_cast"
|
||||
<< "dynamic_cast"
|
||||
<< "else"
|
||||
<< "enum"
|
||||
<< "explicit"
|
||||
|
@ -92,19 +92,19 @@ Highlighter::Highlighter(QTextDocument *parent,
|
|||
<< "private"
|
||||
<< "protected"
|
||||
<< "public"
|
||||
<< "reinterpret_cast"
|
||||
<< "reinterpret_cast"
|
||||
<< "requires"
|
||||
<< "return"
|
||||
<< "short"
|
||||
<< "signed"
|
||||
<< "static"
|
||||
<< "static_assert"
|
||||
<< "static_cast"
|
||||
<< "static_assert"
|
||||
<< "static_cast"
|
||||
<< "struct"
|
||||
<< "switch"
|
||||
<< "template"
|
||||
<< "this"
|
||||
<< "thread_local"
|
||||
<< "thread_local"
|
||||
<< "throw"
|
||||
<< "true"
|
||||
<< "try"
|
||||
|
@ -116,7 +116,7 @@ Highlighter::Highlighter(QTextDocument *parent,
|
|||
<< "virtual"
|
||||
<< "void"
|
||||
<< "volatile"
|
||||
<< "wchar_t"
|
||||
<< "wchar_t"
|
||||
<< "while";
|
||||
for (const QString &pattern : keywordPatterns) {
|
||||
rule.pattern = QRegularExpression("\\b" + pattern + "\\b");
|
||||
|
@ -157,7 +157,9 @@ Highlighter::Highlighter(QTextDocument *parent,
|
|||
mSymbolFormat.setBackground(mWidgetStyle->symbolBGColor);
|
||||
mSymbolFormat.setFontWeight(mWidgetStyle->symbolWeight);
|
||||
|
||||
mCommentStartExpression = QRegularExpression("/\\*");
|
||||
// We use negative lookbehind assertion `(?<!/)`
|
||||
// to ignore case: single line comment and line of asterisk
|
||||
mCommentStartExpression = QRegularExpression("(?<!/)/\\*");
|
||||
mCommentEndExpression = QRegularExpression("\\*/");
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ static CppcheckLibraryData::Container loadContainer(QXmlStreamReader &xmlReader)
|
|||
if (elementName == "type") {
|
||||
container.type.templateParameter = xmlReader.attributes().value("templateParameter").toString();
|
||||
container.type.string = xmlReader.attributes().value("string").toString();
|
||||
} else if (elementName == "size" || elementName == "access" || elementName == "other") {
|
||||
} else if (elementName == "size" || elementName == "access" || elementName == "other" || elementName == "rangeItemRecordType") {
|
||||
const QString indexOperator = xmlReader.attributes().value("indexOperator").toString();
|
||||
if (elementName == "access" && indexOperator == "array-like")
|
||||
container.access_arrayLike = true;
|
||||
|
@ -82,7 +82,12 @@ static CppcheckLibraryData::Container loadContainer(QXmlStreamReader &xmlReader)
|
|||
container.sizeFunctions.append(function);
|
||||
else if (elementName == "access")
|
||||
container.accessFunctions.append(function);
|
||||
else
|
||||
else if (elementName == "rangeItemRecordType") {
|
||||
struct CppcheckLibraryData::Container::RangeItemRecordType rangeItemRecordType;
|
||||
rangeItemRecordType.name = xmlReader.attributes().value("name").toString();
|
||||
rangeItemRecordType.templateParameter = xmlReader.attributes().value("templateParameter").toString();
|
||||
container.rangeItemRecordTypeList.append(rangeItemRecordType);
|
||||
} else
|
||||
container.otherFunctions.append(function);
|
||||
}
|
||||
} else {
|
||||
|
@ -105,9 +110,23 @@ static QString loadUndefine(const QXmlStreamReader &xmlReader)
|
|||
return xmlReader.attributes().value("name").toString();
|
||||
}
|
||||
|
||||
static QString loadSmartPointer(const QXmlStreamReader &xmlReader)
|
||||
static CppcheckLibraryData::SmartPointer loadSmartPointer(QXmlStreamReader &xmlReader)
|
||||
{
|
||||
return xmlReader.attributes().value("class-name").toString();
|
||||
CppcheckLibraryData::SmartPointer smartPointer;
|
||||
smartPointer.name = xmlReader.attributes().value("class-name").toString();
|
||||
QXmlStreamReader::TokenType type;
|
||||
while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement ||
|
||||
xmlReader.name().toString() != "smart-pointer") {
|
||||
if (type != QXmlStreamReader::StartElement)
|
||||
continue;
|
||||
const QString elementName = xmlReader.name().toString();
|
||||
if (elementName == "unique") {
|
||||
smartPointer.unique = true;
|
||||
} else {
|
||||
unhandledElement(xmlReader);
|
||||
}
|
||||
}
|
||||
return smartPointer;
|
||||
}
|
||||
|
||||
static CppcheckLibraryData::TypeChecks loadTypeChecks(QXmlStreamReader &xmlReader)
|
||||
|
@ -210,6 +229,20 @@ static CppcheckLibraryData::Function loadFunction(QXmlStreamReader &xmlReader, c
|
|||
function.warn.reason = xmlReader.attributes().value("reason").toString();
|
||||
function.warn.alternatives = xmlReader.attributes().value("alternatives").toString();
|
||||
function.warn.msg = xmlReader.readElementText();
|
||||
} else if (elementName == "not-overlapping-data") {
|
||||
const QStringList attributeList {"ptr1-arg", "ptr2-arg", "size-arg", "strlen-arg"};
|
||||
for (const QString &attr : attributeList) {
|
||||
if (xmlReader.attributes().hasAttribute(attr)) {
|
||||
function.notOverlappingDataArgs[attr] = xmlReader.attributes().value(attr).toString();
|
||||
}
|
||||
}
|
||||
} else if (elementName == "container") {
|
||||
const QStringList attributeList {"action", "yields"};
|
||||
for (const QString &attr : attributeList) {
|
||||
if (xmlReader.attributes().hasAttribute(attr)) {
|
||||
function.containerAttributes[attr] = xmlReader.attributes().value(attr).toString();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unhandledElement(xmlReader);
|
||||
}
|
||||
|
@ -493,6 +526,20 @@ static void writeContainerFunctions(QXmlStreamWriter &xmlWriter, const QString &
|
|||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
static void writeContainerRangeItemRecords(QXmlStreamWriter &xmlWriter, const QList<struct CppcheckLibraryData::Container::RangeItemRecordType> &rangeItemRecords)
|
||||
{
|
||||
if (rangeItemRecords.isEmpty())
|
||||
return;
|
||||
xmlWriter.writeStartElement("rangeItemRecordType");
|
||||
for (const CppcheckLibraryData::Container::RangeItemRecordType &item : rangeItemRecords) {
|
||||
xmlWriter.writeStartElement("member");
|
||||
xmlWriter.writeAttribute("name", item.name);
|
||||
xmlWriter.writeAttribute("templateParameter", item.templateParameter);
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
static void writeContainer(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Container &container)
|
||||
{
|
||||
xmlWriter.writeStartElement("container");
|
||||
|
@ -519,6 +566,7 @@ static void writeContainer(QXmlStreamWriter &xmlWriter, const CppcheckLibraryDat
|
|||
writeContainerFunctions(xmlWriter, "size", container.size_templateParameter, container.sizeFunctions);
|
||||
writeContainerFunctions(xmlWriter, "access", container.access_arrayLike?1:-1, container.accessFunctions);
|
||||
writeContainerFunctions(xmlWriter, "other", -1, container.otherFunctions);
|
||||
writeContainerRangeItemRecords(xmlWriter, container.rangeItemRecordTypeList);
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
|
@ -632,7 +680,20 @@ static void writeFunction(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData
|
|||
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
if (!function.notOverlappingDataArgs.isEmpty()) {
|
||||
xmlWriter.writeStartElement("not-overlapping-data");
|
||||
foreach (const QString value, function.notOverlappingDataArgs) {
|
||||
xmlWriter.writeAttribute(function.notOverlappingDataArgs.key(value), value);
|
||||
}
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
if (!function.containerAttributes.isEmpty()) {
|
||||
xmlWriter.writeStartElement("container");
|
||||
foreach (const QString value, function.containerAttributes) {
|
||||
xmlWriter.writeAttribute(function.containerAttributes.key(value), value);
|
||||
}
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
|
@ -835,9 +896,12 @@ QString CppcheckLibraryData::toString() const
|
|||
writeTypeChecks(xmlWriter, check);
|
||||
}
|
||||
|
||||
for (const QString &smartPtr : smartPointers) {
|
||||
for (const SmartPointer &smartPtr : smartPointers) {
|
||||
xmlWriter.writeStartElement("smart-pointer");
|
||||
xmlWriter.writeAttribute("class-name", smartPtr);
|
||||
xmlWriter.writeAttribute("class-name", smartPtr.name);
|
||||
if (smartPtr.unique) {
|
||||
xmlWriter.writeEmptyElement("unique");
|
||||
}
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QMap>
|
||||
|
||||
class QIODevice;
|
||||
|
||||
|
@ -47,6 +48,11 @@ public:
|
|||
QString string;
|
||||
} type;
|
||||
|
||||
struct RangeItemRecordType {
|
||||
QString name;
|
||||
QString templateParameter;
|
||||
};
|
||||
|
||||
struct Function {
|
||||
QString name;
|
||||
QString yields;
|
||||
|
@ -55,6 +61,7 @@ public:
|
|||
QList<struct Function> accessFunctions;
|
||||
QList<struct Function> otherFunctions;
|
||||
QList<struct Function> sizeFunctions;
|
||||
QList<struct RangeItemRecordType> rangeItemRecordTypeList;
|
||||
};
|
||||
|
||||
struct Define {
|
||||
|
@ -130,6 +137,9 @@ public:
|
|||
msg.isEmpty();
|
||||
}
|
||||
} warn;
|
||||
|
||||
QMap<QString, QString> notOverlappingDataArgs;
|
||||
QMap<QString, QString> containerAttributes;
|
||||
};
|
||||
|
||||
struct MemoryResource {
|
||||
|
@ -219,6 +229,15 @@ public:
|
|||
QList<Exporter> exporter;
|
||||
};
|
||||
|
||||
struct SmartPointer {
|
||||
SmartPointer() :
|
||||
unique {false}
|
||||
{}
|
||||
|
||||
QString name;
|
||||
bool unique;
|
||||
};
|
||||
|
||||
void clear() {
|
||||
containers.clear();
|
||||
defines.clear();
|
||||
|
@ -258,7 +277,7 @@ public:
|
|||
QList<TypeChecks> typeChecks;
|
||||
QList<struct PlatformType> platformTypes;
|
||||
QStringList undefines;
|
||||
QStringList smartPointers;
|
||||
QList<struct SmartPointer> smartPointers;
|
||||
QList<struct Reflection> reflections;
|
||||
QList<struct Markup> markups;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<def format="2">
|
||||
<container id="stdMultiMap">
|
||||
<rangeItemRecordType>
|
||||
<member name="first" templateParameter="0"/>
|
||||
<member name="second" templateParameter="1"/>
|
||||
</rangeItemRecordType>
|
||||
</container>
|
||||
</def>
|
|
@ -1,6 +1,8 @@
|
|||
<?xml version="1.0"?>
|
||||
<def format="2">
|
||||
<smart-pointer class-name="wxObjectDataPtr"/>
|
||||
<smart-pointer class-name="wxScopedArray"/>
|
||||
<smart-pointer class-name="wxScopedArray">
|
||||
<unique/>
|
||||
</smart-pointer>
|
||||
<smart-pointer class-name="wxScopedPtr"/>
|
||||
</def>
|
|
@ -19,5 +19,6 @@
|
|||
<file>files/markup_mandatory_attribute_missing.cfg</file>
|
||||
<file>files/markup_valid.cfg</file>
|
||||
<file>files/markup_unhandled_element.cfg</file>
|
||||
<file>files/container_valid.cfg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -182,9 +182,12 @@ void TestCppcheckLibraryData::smartPointerValid()
|
|||
// Do size and content checks against swapped data.
|
||||
QCOMPARE(libraryData.smartPointers.size(), 3);
|
||||
|
||||
QCOMPARE(libraryData.smartPointers[0], QString("wxObjectDataPtr"));
|
||||
QCOMPARE(libraryData.smartPointers[1], QString("wxScopedArray"));
|
||||
QCOMPARE(libraryData.smartPointers[2], QString("wxScopedPtr"));
|
||||
QCOMPARE(libraryData.smartPointers[0].name, QString("wxObjectDataPtr"));
|
||||
QCOMPARE(libraryData.smartPointers[0].unique, false);
|
||||
QCOMPARE(libraryData.smartPointers[1].name, QString("wxScopedArray"));
|
||||
QCOMPARE(libraryData.smartPointers[1].unique, true);
|
||||
QCOMPARE(libraryData.smartPointers[2].name, QString("wxScopedPtr"));
|
||||
QCOMPARE(libraryData.smartPointers[2].unique, false);
|
||||
|
||||
// Save library data to file
|
||||
saveCfgFile(TempCfgFile, libraryData);
|
||||
|
@ -199,7 +202,10 @@ void TestCppcheckLibraryData::smartPointerValid()
|
|||
// Verify no data got lost or modified
|
||||
QCOMPARE(libraryData.smartPointers.size(), fileLibraryData.smartPointers.size());
|
||||
QCOMPARE(libraryData.smartPointers.size(), 3);
|
||||
QCOMPARE(libraryData.smartPointers, fileLibraryData.smartPointers);
|
||||
for (int idx=0; idx < libraryData.smartPointers.size(); idx++) {
|
||||
QCOMPARE(libraryData.smartPointers[idx].name, fileLibraryData.smartPointers[idx].name);
|
||||
QCOMPARE(libraryData.smartPointers[idx].unique, fileLibraryData.smartPointers[idx].unique);
|
||||
}
|
||||
}
|
||||
|
||||
void TestCppcheckLibraryData::platformTypeValid()
|
||||
|
@ -543,6 +549,46 @@ void TestCppcheckLibraryData::markupValid()
|
|||
}
|
||||
}
|
||||
|
||||
void TestCppcheckLibraryData::containerValid()
|
||||
{
|
||||
// Load library data from file
|
||||
loadCfgFile(":/files/container_valid.cfg", fileLibraryData, result);
|
||||
QCOMPARE(result.isNull(), true);
|
||||
|
||||
// Swap library data read from file to other object
|
||||
libraryData.swap(fileLibraryData);
|
||||
|
||||
// Do size and content checks against swapped data.
|
||||
QCOMPARE(libraryData.containers.size(), 1);
|
||||
|
||||
QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList.size(), 2);
|
||||
QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[0].name, QString("first"));
|
||||
QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[0].templateParameter, QString("0"));
|
||||
QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[1].name, QString("second"));
|
||||
QCOMPARE(libraryData.containers[0].rangeItemRecordTypeList[1].templateParameter, QString("1"));
|
||||
|
||||
// Save library data to file
|
||||
saveCfgFile(TempCfgFile, libraryData);
|
||||
|
||||
fileLibraryData.clear();
|
||||
QCOMPARE(fileLibraryData.containers.size(), 0);
|
||||
|
||||
// Reload library data from file
|
||||
loadCfgFile(TempCfgFile, fileLibraryData, result, true);
|
||||
QCOMPARE(result.isNull(), true);
|
||||
|
||||
// Verify no data got lost or modified
|
||||
QCOMPARE(libraryData.containers.size(), fileLibraryData.containers.size());
|
||||
for (int idx=0; idx < libraryData.containers.size(); idx++) {
|
||||
CppcheckLibraryData::Container lhs = libraryData.containers[idx];
|
||||
CppcheckLibraryData::Container rhs = fileLibraryData.containers[idx];
|
||||
for (int num=0; num < lhs.rangeItemRecordTypeList.size(); num++) {
|
||||
QCOMPARE(lhs.rangeItemRecordTypeList[num].name, rhs.rangeItemRecordTypeList[num].name);
|
||||
QCOMPARE(lhs.rangeItemRecordTypeList[num].templateParameter, rhs.rangeItemRecordTypeList[num].templateParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestCppcheckLibraryData::loadCfgFile(QString filename, CppcheckLibraryData &data, QString &res, bool removeFile)
|
||||
{
|
||||
QFile file(filename);
|
||||
|
|
|
@ -39,6 +39,7 @@ private slots:
|
|||
void undefineValid();
|
||||
void reflectionValid();
|
||||
void markupValid();
|
||||
void containerValid();
|
||||
|
||||
private:
|
||||
void loadCfgFile(QString filename, CppcheckLibraryData &data, QString &res, bool removeFile = false);
|
||||
|
|
|
@ -72,7 +72,7 @@ void AnalyzerInformation::close()
|
|||
}
|
||||
}
|
||||
|
||||
static bool skipAnalysis(const std::string &analyzerInfoFile, unsigned long long checksum, std::list<ErrorMessage> *errors)
|
||||
static bool skipAnalysis(const std::string &analyzerInfoFile, std::size_t hash, std::list<ErrorMessage> *errors)
|
||||
{
|
||||
tinyxml2::XMLDocument doc;
|
||||
const tinyxml2::XMLError error = doc.LoadFile(analyzerInfoFile.c_str());
|
||||
|
@ -83,8 +83,8 @@ static bool skipAnalysis(const std::string &analyzerInfoFile, unsigned long long
|
|||
if (rootNode == nullptr)
|
||||
return false;
|
||||
|
||||
const char *attr = rootNode->Attribute("checksum");
|
||||
if (!attr || attr != std::to_string(checksum))
|
||||
const char *attr = rootNode->Attribute("hash");
|
||||
if (!attr || attr != std::to_string(hash))
|
||||
return false;
|
||||
|
||||
for (const tinyxml2::XMLElement *e = rootNode->FirstChildElement(); e; e = e->NextSiblingElement()) {
|
||||
|
@ -125,7 +125,7 @@ std::string AnalyzerInformation::getAnalyzerInfoFile(const std::string &buildDir
|
|||
return filename;
|
||||
}
|
||||
|
||||
bool AnalyzerInformation::analyzeFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, unsigned long long checksum, std::list<ErrorMessage> *errors)
|
||||
bool AnalyzerInformation::analyzeFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t hash, std::list<ErrorMessage> *errors)
|
||||
{
|
||||
if (buildDir.empty() || sourcefile.empty())
|
||||
return true;
|
||||
|
@ -133,13 +133,13 @@ bool AnalyzerInformation::analyzeFile(const std::string &buildDir, const std::st
|
|||
|
||||
mAnalyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(buildDir,sourcefile,cfg);
|
||||
|
||||
if (skipAnalysis(mAnalyzerInfoFile, checksum, errors))
|
||||
if (skipAnalysis(mAnalyzerInfoFile, hash, errors))
|
||||
return false;
|
||||
|
||||
mOutputStream.open(mAnalyzerInfoFile);
|
||||
if (mOutputStream.is_open()) {
|
||||
mOutputStream << "<?xml version=\"1.0\"?>\n";
|
||||
mOutputStream << "<analyzerinfo checksum=\"" << checksum << "\">\n";
|
||||
mOutputStream << "<analyzerinfo hash=\"" << hash << "\">\n";
|
||||
} else {
|
||||
mAnalyzerInfoFile.clear();
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ public:
|
|||
|
||||
/** Close current TU.analyzerinfo file */
|
||||
void close();
|
||||
bool analyzeFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, unsigned long long checksum, std::list<ErrorMessage> *errors);
|
||||
bool analyzeFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t hash, std::list<ErrorMessage> *errors);
|
||||
void reportErr(const ErrorMessage &msg, bool verbose);
|
||||
void setFileInfo(const std::string &check, const std::string &fileInfo);
|
||||
static std::string getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg);
|
||||
|
|
|
@ -865,6 +865,34 @@ bool isAliasOf(const Token *tok, nonneg int varid, bool* inconclusive)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool isAliasOf(const Token* tok, const Token* expr, bool* inconclusive)
|
||||
{
|
||||
const bool pointer = astIsPointer(tok);
|
||||
const ValueFlow::Value* value = nullptr;
|
||||
const Token* r = findAstNode(expr, [&](const Token* childTok) {
|
||||
for (const ValueFlow::Value& val : tok->values()) {
|
||||
if (val.isImpossible())
|
||||
continue;
|
||||
if (val.isLocalLifetimeValue() || (pointer && val.isSymbolicValue() && val.intvalue == 0)) {
|
||||
if (findAstNode(val.tokvalue,
|
||||
[&](const Token* aliasTok) {
|
||||
return aliasTok->exprId() == childTok->exprId();
|
||||
})) {
|
||||
if (val.isInconclusive() && inconclusive) { // NOLINT
|
||||
value = &val;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (!r && value && inconclusive)
|
||||
*inconclusive = true;
|
||||
return r || value;
|
||||
}
|
||||
|
||||
static bool isAliased(const Token *startTok, const Token *endTok, nonneg int varid)
|
||||
{
|
||||
if (!precedes(startTok, endTok))
|
||||
|
@ -2452,27 +2480,12 @@ static bool isExpressionChangedAt(const F& getExprTok,
|
|||
if (globalvar && !tok->isKeyword() && Token::Match(tok, "%name% (") && !(tok->function() && tok->function()->isAttributePure()))
|
||||
// TODO: Is global variable really changed by function call?
|
||||
return true;
|
||||
const bool pointer = astIsPointer(tok);
|
||||
bool aliased = false;
|
||||
// If we can't find the expression then assume it is an alias
|
||||
if (!getExprTok())
|
||||
aliased = true;
|
||||
if (!aliased) {
|
||||
aliased = findAstNode(getExprTok(), [&](const Token* childTok) {
|
||||
for (const ValueFlow::Value& val : tok->values()) {
|
||||
if (val.isImpossible())
|
||||
continue;
|
||||
if (val.isLocalLifetimeValue() || (pointer && val.isSymbolicValue() && val.intvalue == 0)) {
|
||||
if (findAstNode(val.tokvalue,
|
||||
[&](const Token* aliasTok) {
|
||||
return aliasTok->exprId() == childTok->exprId();
|
||||
}))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
if (!aliased)
|
||||
aliased = isAliasOf(tok, getExprTok());
|
||||
if (!aliased)
|
||||
return false;
|
||||
if (isVariableChanged(tok, 1, settings, cpp, depth))
|
||||
|
|
|
@ -335,6 +335,8 @@ bool isExpressionChangedAt(const Token* expr,
|
|||
/// If token is an alias if another variable
|
||||
bool isAliasOf(const Token *tok, nonneg int varid, bool* inconclusive = nullptr);
|
||||
|
||||
bool isAliasOf(const Token* tok, const Token* expr, bool* inconclusive = nullptr);
|
||||
|
||||
bool isAliased(const Variable *var);
|
||||
|
||||
const Token* getArgumentStart(const Token* ftok);
|
||||
|
|
|
@ -739,9 +739,18 @@ void CheckBufferOverrun::stringNotZeroTerminated()
|
|||
const ValueFlow::Value &bufferSize = getBufferSize(args[0]);
|
||||
if (bufferSize.intvalue < 0 || sizeToken->getKnownIntValue() < bufferSize.intvalue)
|
||||
continue;
|
||||
const Token *srcValue = args[1]->getValueTokenMaxStrLength();
|
||||
if (srcValue && Token::getStrLength(srcValue) < sizeToken->getKnownIntValue())
|
||||
continue;
|
||||
if (Token::simpleMatch(args[1], "(") && Token::simpleMatch(args[1]->astOperand1(), ". c_str") && args[1]->astOperand1()->astOperand1()) {
|
||||
const std::list<ValueFlow::Value>& contValues = args[1]->astOperand1()->astOperand1()->values();
|
||||
auto it = std::find_if(contValues.begin(), contValues.end(), [](const ValueFlow::Value& value) {
|
||||
return value.isContainerSizeValue() && !value.isImpossible();
|
||||
});
|
||||
if (it != contValues.end() && it->intvalue < sizeToken->getKnownIntValue())
|
||||
continue;
|
||||
} else {
|
||||
const Token* srcValue = args[1]->getValueTokenMaxStrLength();
|
||||
if (srcValue && Token::getStrLength(srcValue) < sizeToken->getKnownIntValue())
|
||||
continue;
|
||||
}
|
||||
// Is the buffer zero terminated after the call?
|
||||
bool isZeroTerminated = false;
|
||||
for (const Token *tok2 = tok->next()->link(); tok2 != scope->bodyEnd; tok2 = tok2->next()) {
|
||||
|
|
|
@ -1803,6 +1803,8 @@ void CheckCondition::checkCompareValueOutOfTypeRange()
|
|||
continue;
|
||||
if (valueTok->getKnownIntValue() < 0 && valueTok->valueType() && valueTok->valueType()->sign != ValueType::Sign::SIGNED)
|
||||
continue;
|
||||
if (valueTok->valueType() && valueTok->valueType()->isTypeEqual(typeTok->valueType()))
|
||||
continue;
|
||||
int bits = 0;
|
||||
switch (typeTok->valueType()->type) {
|
||||
case ValueType::Type::BOOL:
|
||||
|
|
|
@ -658,7 +658,7 @@ void CheckFunctions::returnLocalStdMove()
|
|||
if (retval->variable() && retval->variable()->isLocal() && !retval->variable()->isVolatile())
|
||||
copyElisionError(retval);
|
||||
// RVO
|
||||
if (Token::Match(retval, "(|{") && !retval->isCast())
|
||||
if (Token::Match(retval, "(|{") && !retval->isCast() && !(retval->valueType() && retval->valueType()->reference != Reference::None))
|
||||
copyElisionError(retval);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -991,14 +991,16 @@ void CheckMemoryLeakNoVar::checkForUnreleasedInputArgument(const Scope *scope)
|
|||
// parse the executable scope until tok is reached...
|
||||
for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
|
||||
// allocating memory in parameter for function call..
|
||||
if (!Token::Match(tok, "%name% ("))
|
||||
if (tok->varId() || !Token::Match(tok, "%name% ("))
|
||||
continue;
|
||||
|
||||
// check if the output of the function is assigned
|
||||
const Token* tok2 = tok->next()->astParent();
|
||||
while (tok2 && tok2->isCast())
|
||||
tok2 = tok2->astParent();
|
||||
if (Token::Match(tok2, "%assign%|return"))
|
||||
if (Token::Match(tok2, "%assign%"))
|
||||
continue;
|
||||
if (Token::simpleMatch(tok->astTop(), "return"))
|
||||
continue;
|
||||
|
||||
const std::string& functionName = tok->str();
|
||||
|
@ -1009,15 +1011,22 @@ void CheckMemoryLeakNoVar::checkForUnreleasedInputArgument(const Scope *scope)
|
|||
functionName == "return")
|
||||
continue;
|
||||
|
||||
if (Token::simpleMatch(tok->next()->astParent(), "(")) // passed to another function
|
||||
continue;
|
||||
if (!tok->isKeyword() && mSettings->library.isNotLibraryFunction(tok))
|
||||
continue;
|
||||
if (!CheckMemoryLeakInFunction::test_white_list(functionName, mSettings, mTokenizer->isCPP()))
|
||||
continue;
|
||||
|
||||
const std::vector<const Token *> args = getArguments(tok);
|
||||
for (const Token* arg : args) {
|
||||
if (arg->isOp())
|
||||
if (arg->isOp() && !(tok->isKeyword() && arg->str() == "*")) // e.g. switch (*new int)
|
||||
continue;
|
||||
while (arg->astOperand1())
|
||||
while (arg->astOperand1()) {
|
||||
if (mTokenizer->isCPP() && Token::simpleMatch(arg, "new"))
|
||||
break;
|
||||
arg = arg->astOperand1();
|
||||
}
|
||||
if (getAllocationType(arg, 0) == No)
|
||||
continue;
|
||||
if (isReopenStandardStream(arg))
|
||||
|
@ -1068,7 +1077,13 @@ void CheckMemoryLeakNoVar::checkForUnusedReturnValue(const Scope *scope)
|
|||
if (closingBrace->str() == "}" && Token::Match(closingBrace->link()->tokAt(-1), "%name%") && (!isNew && precedes(tok, closingBrace->link())))
|
||||
continue;
|
||||
returnValueNotUsedError(tok, tok->str());
|
||||
} else if (Token::Match(parent, "%comp%|!")) {
|
||||
} else if (Token::Match(parent, "%comp%|!|,|%oror%|&&|:")) {
|
||||
if (parent->astParent() && parent->str() == ",")
|
||||
continue;
|
||||
if (parent->str() == ":") {
|
||||
if (!(Token::simpleMatch(parent->astParent(), "?") && !parent->astParent()->astParent()))
|
||||
continue;
|
||||
}
|
||||
returnValueNotUsedError(tok, tok->str());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "symboldatabase.h"
|
||||
#include "token.h"
|
||||
#include "tokenize.h"
|
||||
#include "utils.h"
|
||||
#include "valueflow.h"
|
||||
|
||||
#include "checkuninitvar.h" // CheckUninitVar::isVariableUsage
|
||||
|
@ -1556,6 +1557,8 @@ void CheckOther::checkConstPointer()
|
|||
deref = true;
|
||||
else if (Token::simpleMatch(parent, "[") && parent->astOperand1() == tok && tok != nameTok)
|
||||
deref = true;
|
||||
else if (Token::Match(parent, "%op%") && Token::simpleMatch(parent->astParent(), "."))
|
||||
deref = true;
|
||||
else if (astIsRangeBasedForDecl(tok))
|
||||
continue;
|
||||
if (deref) {
|
||||
|
@ -1565,16 +1568,19 @@ void CheckOther::checkConstPointer()
|
|||
if (Token::simpleMatch(gparent, "return"))
|
||||
continue;
|
||||
else if (Token::Match(gparent, "%assign%") && parent == gparent->astOperand2()) {
|
||||
bool takingRef = false;
|
||||
bool takingRef = false, nonConstPtrAssignment = false;
|
||||
const Token *lhs = gparent->astOperand1();
|
||||
if (lhs && lhs->variable() && lhs->variable()->isReference() && lhs->variable()->nameToken() == lhs)
|
||||
takingRef = true;
|
||||
if (!takingRef)
|
||||
if (lhs && lhs->valueType() && lhs->valueType()->pointer && (lhs->valueType()->constness & 1) == 0 &&
|
||||
parent->valueType() && parent->valueType()->pointer)
|
||||
nonConstPtrAssignment = true;
|
||||
if (!takingRef && !nonConstPtrAssignment)
|
||||
continue;
|
||||
} else if (Token::simpleMatch(gparent, "[") && gparent->astOperand2() == parent)
|
||||
continue;
|
||||
} else {
|
||||
if (Token::Match(parent, "%oror%|%comp%|&&|?|!"))
|
||||
if (Token::Match(parent, "%oror%|%comp%|&&|?|!|-"))
|
||||
continue;
|
||||
else if (Token::simpleMatch(parent, "(") && Token::Match(parent->astOperand1(), "if|while"))
|
||||
continue;
|
||||
|
@ -1717,7 +1723,7 @@ void CheckOther::charBitOpError(const Token *tok)
|
|||
|
||||
static bool isType(const Token * tok, bool unknown)
|
||||
{
|
||||
if (Token::Match(tok, "%type%"))
|
||||
if (tok && (tok->isStandardType() || (!tok->isKeyword() && Token::Match(tok, "%type%"))))
|
||||
return true;
|
||||
if (Token::simpleMatch(tok, "::"))
|
||||
return isType(tok->astOperand2(), unknown);
|
||||
|
|
|
@ -128,7 +128,7 @@ void CheckStl::outOfBounds()
|
|||
for (const Scope *function : mTokenizer->getSymbolDatabase()->functionScopes) {
|
||||
for (const Token *tok = function->bodyStart; tok != function->bodyEnd; tok = tok->next()) {
|
||||
const Library::Container *container = getLibraryContainer(tok);
|
||||
if (!container)
|
||||
if (!container || container->stdAssociativeLike)
|
||||
continue;
|
||||
const Token * parent = astParentSkipParens(tok);
|
||||
const Token* accessTok = parent;
|
||||
|
|
|
@ -1518,6 +1518,8 @@ void CheckUninitVar::uninitvarError(const Token *tok, const std::string &varname
|
|||
|
||||
void CheckUninitVar::uninitvarError(const Token* tok, const ValueFlow::Value& v)
|
||||
{
|
||||
if (!mSettings->isEnabled(&v))
|
||||
return;
|
||||
if (diag(tok))
|
||||
return;
|
||||
const Token* ltok = tok;
|
||||
|
@ -1526,13 +1528,15 @@ void CheckUninitVar::uninitvarError(const Token* tok, const ValueFlow::Value& v)
|
|||
const std::string& varname = ltok ? ltok->expressionString() : "x";
|
||||
ErrorPath errorPath = v.errorPath;
|
||||
errorPath.emplace_back(tok, "");
|
||||
auto severity = v.isKnown() ? Severity::error : Severity::warning;
|
||||
auto certainty = v.isInconclusive() ? Certainty::inconclusive : Certainty::normal;
|
||||
if (v.subexpressions.empty()) {
|
||||
reportError(errorPath,
|
||||
Severity::error,
|
||||
severity,
|
||||
"uninitvar",
|
||||
"$symbol:" + varname + "\nUninitialized variable: $symbol",
|
||||
CWE_USE_OF_UNINITIALIZED_VARIABLE,
|
||||
Certainty::normal);
|
||||
certainty);
|
||||
return;
|
||||
}
|
||||
std::string vars = v.subexpressions.size() == 1 ? "variable: " : "variables: ";
|
||||
|
@ -1542,11 +1546,11 @@ void CheckUninitVar::uninitvarError(const Token* tok, const ValueFlow::Value& v)
|
|||
prefix = ", ";
|
||||
}
|
||||
reportError(errorPath,
|
||||
Severity::error,
|
||||
severity,
|
||||
"uninitvar",
|
||||
"$symbol:" + varname + "\nUninitialized " + vars,
|
||||
CWE_USE_OF_UNINITIALIZED_VARIABLE,
|
||||
Certainty::normal);
|
||||
certainty);
|
||||
}
|
||||
|
||||
void CheckUninitVar::uninitStructMemberError(const Token *tok, const std::string &membername)
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "tokenize.h"
|
||||
#include "tokenlist.h"
|
||||
#include "utils.h"
|
||||
#include "valueflow.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
|
|
|
@ -497,17 +497,21 @@ void clangimport::AstNode::dumpAst(int num, int indent) const
|
|||
void clangimport::AstNode::setLocations(TokenList *tokenList, int file, int line, int col)
|
||||
{
|
||||
for (const std::string &ext: mExtTokens) {
|
||||
if (ext.compare(0,5,"<col:") == 0)
|
||||
if (ext.compare(0, 5, "<col:") == 0)
|
||||
col = std::atoi(ext.substr(5).c_str());
|
||||
else if (ext.compare(0,6,"<line:") == 0) {
|
||||
else if (ext.compare(0, 6, "<line:") == 0) {
|
||||
line = std::atoi(ext.substr(6).c_str());
|
||||
if (ext.find(", col:") != std::string::npos)
|
||||
col = std::atoi(ext.c_str() + ext.find(", col:") + 6);
|
||||
} else if (ext[0] == '<' && ext.find(":") != std::string::npos) {
|
||||
std::string::size_type sep1 = ext.find(":");
|
||||
std::string::size_type sep2 = ext.find(":", sep1+1);
|
||||
file = tokenList->appendFileIfNew(ext.substr(1, sep1 - 1));
|
||||
line = MathLib::toLongNumber(ext.substr(sep1+1, sep2-sep1));
|
||||
} else if (ext[0] == '<') {
|
||||
const std::string::size_type colon = ext.find(':');
|
||||
if (colon != std::string::npos) {
|
||||
const bool windowsPath = colon == 2 && ext.size() > 4 && ext[3] == '\\';
|
||||
std::string::size_type sep1 = windowsPath ? ext.find(':', 4) : colon;
|
||||
std::string::size_type sep2 = ext.find(':', sep1 + 1);
|
||||
file = tokenList->appendFileIfNew(ext.substr(1, sep1 - 1));
|
||||
line = MathLib::toLongNumber(ext.substr(sep1 + 1, sep2 - sep1 - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
mFile = file;
|
||||
|
|
|
@ -112,6 +112,7 @@ static const std::string emptyString;
|
|||
#define STDCALL
|
||||
#elif ((defined(__GNUC__) || defined(__sun)) && !defined(__MINGW32__)) || defined(__CPPCHECK__)
|
||||
#define THREADING_MODEL_FORK
|
||||
#define STDCALL
|
||||
#else
|
||||
#error "No threading model defined"
|
||||
#endif
|
||||
|
|
|
@ -707,10 +707,10 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
|
|||
toolinfo << mSettings.userDefines;
|
||||
mSettings.nomsg.dump(toolinfo);
|
||||
|
||||
// Calculate checksum so it can be compared with old checksum / future checksums
|
||||
const unsigned int checksum = preprocessor.calculateChecksum(tokens1, toolinfo.str());
|
||||
// Calculate hash so it can be compared with old hash / future hashes
|
||||
const std::size_t hash = preprocessor.calculateHash(tokens1, toolinfo.str());
|
||||
std::list<ErrorMessage> errors;
|
||||
if (!mAnalyzerInformation.analyzeFile(mSettings.buildDir, filename, cfgname, checksum, &errors)) {
|
||||
if (!mAnalyzerInformation.analyzeFile(mSettings.buildDir, filename, cfgname, hash, &errors)) {
|
||||
while (!errors.empty()) {
|
||||
reportErr(errors.front());
|
||||
errors.pop_front();
|
||||
|
@ -775,7 +775,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
|
|||
}
|
||||
}
|
||||
|
||||
std::set<unsigned long long> checksums;
|
||||
std::set<unsigned long long> hashes;
|
||||
int checkCount = 0;
|
||||
bool hasValidConfig = false;
|
||||
std::list<std::string> configurationError;
|
||||
|
@ -871,18 +871,18 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
|
|||
fdump << "</dump>" << std::endl;
|
||||
}
|
||||
|
||||
// Need to call this even if the checksum will skip this configuration
|
||||
// Need to call this even if the hash will skip this configuration
|
||||
mSettings.nomsg.markUnmatchedInlineSuppressionsAsChecked(tokenizer);
|
||||
|
||||
// Skip if we already met the same simplified token list
|
||||
if (mSettings.force || mSettings.maxConfigs > 1) {
|
||||
const unsigned long long checksum = tokenizer.list.calculateChecksum();
|
||||
if (checksums.find(checksum) != checksums.end()) {
|
||||
const std::size_t hash = tokenizer.list.calculateHash();
|
||||
if (hashes.find(hash) != hashes.end()) {
|
||||
if (mSettings.debugwarnings)
|
||||
purgedConfigurationMessage(filename, mCurrentConfig);
|
||||
continue;
|
||||
}
|
||||
checksums.insert(checksum);
|
||||
hashes.insert(hash);
|
||||
}
|
||||
|
||||
// Check normal tokens
|
||||
|
@ -1432,7 +1432,12 @@ void CppCheck::executeAddonsWholeProgram(const std::map<std::string, std::size_t
|
|||
ctuInfoFiles.push_back(getCtuInfoFileName(dumpFileName));
|
||||
}
|
||||
|
||||
executeAddons(ctuInfoFiles);
|
||||
try {
|
||||
executeAddons(ctuInfoFiles);
|
||||
} catch (const InternalError& e) {
|
||||
internalError("", "Internal error during whole program analysis: " + e.errorMessage);
|
||||
mExitCode = 1;
|
||||
}
|
||||
|
||||
for (const std::string &f: ctuInfoFiles) {
|
||||
std::remove(f.c_str());
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "tokenlist.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iterator> // back_inserter
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include "mathlib.h"
|
||||
#include "valueflow.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
|
|
@ -368,7 +368,7 @@ bool ErrorMessage::deserialize(const std::string &data)
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string ErrorMessage::getXMLHeader()
|
||||
std::string ErrorMessage::getXMLHeader(const std::string& productName)
|
||||
{
|
||||
tinyxml2::XMLPrinter printer;
|
||||
|
||||
|
@ -380,6 +380,8 @@ std::string ErrorMessage::getXMLHeader()
|
|||
|
||||
printer.PushAttribute("version", 2);
|
||||
printer.OpenElement("cppcheck", false);
|
||||
if (!productName.empty())
|
||||
printer.PushAttribute("product-name", productName.c_str());
|
||||
printer.PushAttribute("version", CppCheck::version());
|
||||
printer.CloseElement(false);
|
||||
printer.OpenElement("errors", false);
|
||||
|
@ -489,7 +491,7 @@ static std::string readCode(const std::string &file, int linenr, int column, con
|
|||
std::string::size_type pos = 0;
|
||||
while ((pos = line.find('\t', pos)) != std::string::npos)
|
||||
line[pos] = ' ';
|
||||
return line + endl + std::string((column>0 ? column-1 : column), ' ') + '^';
|
||||
return line + endl + std::string((column>0 ? column-1 : 0), ' ') + '^';
|
||||
}
|
||||
|
||||
static void replaceColors(std::string& source)
|
||||
|
|
|
@ -160,7 +160,7 @@ public:
|
|||
*/
|
||||
std::string toXML() const;
|
||||
|
||||
static std::string getXMLHeader();
|
||||
static std::string getXMLHeader(const std::string& productName);
|
||||
static std::string getXMLFooter();
|
||||
|
||||
/**
|
||||
|
|
|
@ -1037,23 +1037,6 @@ std::string MathLib::subtract(const std::string &first, const std::string &secon
|
|||
#endif
|
||||
}
|
||||
|
||||
std::string MathLib::incdec(const std::string & var, const std::string & op)
|
||||
{
|
||||
#ifdef TEST_MATHLIB_VALUE
|
||||
if (op == "++")
|
||||
return value(var).add(1).str();
|
||||
else if (op == "--")
|
||||
return value(var).add(-1).str();
|
||||
#else
|
||||
if (op == "++")
|
||||
return MathLib::add(var, "1");
|
||||
else if (op == "--")
|
||||
return MathLib::subtract(var, "1");
|
||||
#endif
|
||||
|
||||
throw InternalError(nullptr, std::string("Unexpected operation '") + op + "' in MathLib::incdec(). Please report this to Cppcheck developers.");
|
||||
}
|
||||
|
||||
std::string MathLib::divide(const std::string &first, const std::string &second)
|
||||
{
|
||||
#ifdef TEST_MATHLIB_VALUE
|
||||
|
|
|
@ -106,7 +106,6 @@ public:
|
|||
static std::string multiply(const std::string & first, const std::string & second);
|
||||
static std::string divide(const std::string & first, const std::string & second);
|
||||
static std::string mod(const std::string & first, const std::string & second);
|
||||
static std::string incdec(const std::string & var, const std::string & op);
|
||||
static std::string calculate(const std::string & first, const std::string & second, char action);
|
||||
|
||||
static std::string sin(const std::string & tok);
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
#include "path.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstddef>
|
||||
|
||||
PathMatch::PathMatch(const std::vector<std::string> &excludedPaths, bool caseSensitive)
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iterator> // back_inserter
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
@ -971,74 +972,20 @@ void Preprocessor::dump(std::ostream &out) const
|
|||
}
|
||||
}
|
||||
|
||||
static const std::uint32_t crc32Table[] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
static void crc32(const std::string &data, uint32_t& crc)
|
||||
std::size_t Preprocessor::calculateHash(const simplecpp::TokenList &tokens1, const std::string &toolinfo) const
|
||||
{
|
||||
for (char c : data) {
|
||||
crc = crc32Table[(crc ^ (unsigned char)c) & 0xFF] ^ (crc >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Preprocessor::calculateChecksum(const simplecpp::TokenList &tokens1, const std::string &toolinfo) const
|
||||
{
|
||||
std::uint32_t crc = ~0U;
|
||||
crc32(toolinfo, crc);
|
||||
std::string hashData = toolinfo;
|
||||
for (const simplecpp::Token *tok = tokens1.cfront(); tok; tok = tok->next) {
|
||||
if (!tok->comment)
|
||||
crc32(tok->str(), crc);
|
||||
hashData += tok->str();
|
||||
}
|
||||
for (std::map<std::string, simplecpp::TokenList *>::const_iterator it = mTokenLists.begin(); it != mTokenLists.end(); ++it) {
|
||||
for (const simplecpp::Token *tok = it->second->cfront(); tok; tok = tok->next) {
|
||||
if (!tok->comment)
|
||||
crc32(tok->str(), crc);
|
||||
hashData += tok->str();
|
||||
}
|
||||
}
|
||||
return crc ^ ~0U;
|
||||
return (std::hash<std::string>{})(hashData);
|
||||
}
|
||||
|
||||
void Preprocessor::simplifyPragmaAsm(simplecpp::TokenList *tokenList) const
|
||||
|
|
|
@ -164,13 +164,13 @@ public:
|
|||
void validateCfgError(const std::string &file, const unsigned int line, const std::string &cfg, const std::string ¯o);
|
||||
|
||||
/**
|
||||
* Calculate CRC32 checksum. Using toolinfo, tokens1, filedata.
|
||||
* Calculate HASH. Using toolinfo, tokens1, filedata.
|
||||
*
|
||||
* @param tokens1 Sourcefile tokens
|
||||
* @param toolinfo Arbitrary extra toolinfo
|
||||
* @return CRC32 checksum
|
||||
* @return HASH
|
||||
*/
|
||||
uint32_t calculateChecksum(const simplecpp::TokenList &tokens1, const std::string &toolinfo) const;
|
||||
std::size_t calculateHash(const simplecpp::TokenList &tokens1, const std::string &toolinfo) const;
|
||||
|
||||
void simplifyPragmaAsm(simplecpp::TokenList *tokenList) const;
|
||||
|
||||
|
|
|
@ -632,6 +632,8 @@ static ValueFlow::Value executeImpl(const Token* expr, ProgramMemory& pm, const
|
|||
if (MathLib::isFloat(expr->str()))
|
||||
return unknown;
|
||||
return ValueFlow::Value{MathLib::toLongNumber(expr->str())};
|
||||
} else if (expr->isBoolean()) {
|
||||
return ValueFlow::Value{ expr->str() == "true" };
|
||||
} else if (Token::Match(expr->tokAt(-2), ". %name% (") && astIsContainer(expr->tokAt(-2)->astOperand1())) {
|
||||
const Token* containerTok = expr->tokAt(-2)->astOperand1();
|
||||
Library::Container::Yield yield = containerTok->valueType()->container->getYield(expr->strAt(-1));
|
||||
|
|
|
@ -6508,7 +6508,7 @@ static const Token* parsedecl(const Token* type,
|
|||
} else if (const Library::SmartPointer* smartPointer = settings->library.detectSmartPointer(type)) {
|
||||
const Token* argTok = Token::findsimplematch(type, "<");
|
||||
if (!argTok)
|
||||
continue;
|
||||
break;
|
||||
valuetype->smartPointer = smartPointer;
|
||||
valuetype->smartPointerTypeToken = argTok->next();
|
||||
valuetype->smartPointerType = argTok->next()->type();
|
||||
|
|
|
@ -3791,8 +3791,10 @@ void TemplateSimplifier::simplifyTemplates(
|
|||
specializations,
|
||||
maxtime,
|
||||
expandedtemplates);
|
||||
if (instantiated)
|
||||
if (instantiated) {
|
||||
mInstantiatedTemplates.push_back(*iter1);
|
||||
mTemplateNamePos.clear(); // positions might be invalid after instantiations
|
||||
}
|
||||
}
|
||||
|
||||
for (std::list<TokenAndName>::const_iterator it = mInstantiatedTemplates.begin(); it != mInstantiatedTemplates.end(); ++it) {
|
||||
|
|
1130
lib/tokenize.cpp
1130
lib/tokenize.cpp
File diff suppressed because it is too large
Load Diff
|
@ -159,23 +159,6 @@ public:
|
|||
void splitTemplateRightAngleBrackets(bool check);
|
||||
|
||||
|
||||
/**
|
||||
* Deletes dead code between 'begin' and 'end'.
|
||||
* In general not everything can be erased, such as:
|
||||
* - code after labels;
|
||||
* - code outside the scope where the function is called;
|
||||
* - code after a change of scope caused by 'switch(...);'
|
||||
* instructions, like 'case %any%;' or 'default;'
|
||||
* Also, if the dead code contains a 'switch' block
|
||||
* and inside it there's a label, the function removes all
|
||||
* the 'switch(..)' tokens and every occurrence of 'case %any%; | default;'
|
||||
* expression, such as the 'switch' block is reduced to a simple block.
|
||||
*
|
||||
* @param begin Tokens after this have a possibility to be erased.
|
||||
* @param end Tokens before this have a possibility to be erased.
|
||||
*/
|
||||
static void eraseDeadCode(Token *begin, const Token *end);
|
||||
|
||||
/**
|
||||
* Calculates sizeof value for given type.
|
||||
* @param type Token which will contain e.g. "int", "*", or string.
|
||||
|
@ -196,13 +179,6 @@ public:
|
|||
/** Simplify assignment where rhs is a block : "x=({123;});" => "{x=123;}" */
|
||||
void simplifyAssignmentBlock();
|
||||
|
||||
/**
|
||||
* Simplify constant calculations such as "1+2" => "3"
|
||||
* @return true if modifications to token-list are done.
|
||||
* false if no modifications are done.
|
||||
*/
|
||||
bool simplifyCalculations();
|
||||
|
||||
/** Insert array size where it isn't given */
|
||||
void arraySize();
|
||||
|
||||
|
@ -329,35 +305,9 @@ public:
|
|||
*/
|
||||
bool simplifyUsing();
|
||||
|
||||
/**
|
||||
* A simplify function that replaces a variable with its value in cases
|
||||
* when the value is known. e.g. "x=10; if(x)" => "x=10;if(10)"
|
||||
*
|
||||
* @return true if modifications to token-list are done.
|
||||
* false if no modifications are done.
|
||||
*/
|
||||
bool simplifyKnownVariables();
|
||||
|
||||
/**
|
||||
* Utility function for simplifyKnownVariables. Get data about an
|
||||
* assigned variable.
|
||||
*/
|
||||
static bool simplifyKnownVariablesGetData(nonneg int varid, Token **_tok2, Token **_tok3, std::string &value, nonneg int &valueVarId, bool &valueIsPointer, bool floatvar);
|
||||
|
||||
/**
|
||||
* utility function for simplifyKnownVariables. Perform simplification
|
||||
* of a given variable
|
||||
*/
|
||||
bool simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, nonneg int varid, const std::string &structname, std::string &value, nonneg int valueVarId, bool valueIsPointer, const Token * const valueToken, int indentlevel) const;
|
||||
|
||||
/** Simplify useless C++ empty namespaces, like: 'namespace %name% { }'*/
|
||||
void simplifyEmptyNamespaces();
|
||||
|
||||
/** Simplify redundant code placed after control flow statements :
|
||||
* 'return', 'throw', 'goto', 'break' and 'continue'
|
||||
*/
|
||||
void simplifyFlowControl();
|
||||
|
||||
/** Simplify "if else" */
|
||||
void elseif();
|
||||
|
||||
|
|
|
@ -461,27 +461,17 @@ void TokenList::createTokens(simplecpp::TokenList&& tokenList)
|
|||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
uint64_t TokenList::calculateChecksum() const
|
||||
std::size_t TokenList::calculateHash() const
|
||||
{
|
||||
uint64_t checksum = 0;
|
||||
std::string hashData;
|
||||
for (const Token* tok = front(); tok; tok = tok->next()) {
|
||||
const uint32_t subchecksum1 = tok->flags() + tok->varId() + tok->tokType();
|
||||
uint32_t subchecksum2 = 0;
|
||||
for (char i : tok->str())
|
||||
subchecksum2 += (uint32_t)i;
|
||||
if (!tok->originalName().empty()) {
|
||||
for (char i : tok->originalName())
|
||||
subchecksum2 += (uint32_t)i;
|
||||
}
|
||||
|
||||
checksum ^= ((static_cast<uint64_t>(subchecksum1) << 32) | subchecksum2);
|
||||
|
||||
const bool bit1 = (checksum & 1) != 0;
|
||||
checksum >>= 1;
|
||||
if (bit1)
|
||||
checksum |= (1ULL << 63);
|
||||
hashData += MathLib::toString(tok->flags());
|
||||
hashData += MathLib::toString(tok->varId());
|
||||
hashData += MathLib::toString(tok->tokType());
|
||||
hashData += tok->str();
|
||||
hashData += tok->originalName();
|
||||
}
|
||||
return checksum;
|
||||
return (std::hash<std::string>{})(hashData);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -153,10 +153,10 @@ public:
|
|||
std::string fileLine(const Token *tok) const;
|
||||
|
||||
/**
|
||||
* Calculates a 64-bit checksum of the token list used to compare
|
||||
* multiple token lists with each other as quickly as possible.
|
||||
* Calculates a hash of the token list used to compare multiple
|
||||
* token lists with each other as quickly as possible.
|
||||
*/
|
||||
uint64_t calculateChecksum() const;
|
||||
std::size_t calculateHash() const;
|
||||
|
||||
/**
|
||||
* Create abstract syntax tree.
|
||||
|
|
|
@ -986,8 +986,7 @@ static void setTokenValue(Token* tok,
|
|||
ValueFlow::Value v(val);
|
||||
v.intvalue = ~v.intvalue;
|
||||
int bits = 0;
|
||||
if (settings &&
|
||||
tok->valueType() &&
|
||||
if (tok->valueType() &&
|
||||
tok->valueType()->sign == ValueType::Sign::UNSIGNED &&
|
||||
tok->valueType()->pointer == 0) {
|
||||
if (tok->valueType()->type == ValueType::Type::INT)
|
||||
|
|
|
@ -25,9 +25,7 @@ if (BUILD_TESTS)
|
|||
if(tinyxml2_FOUND AND NOT USE_BUNDLED_TINYXML2)
|
||||
target_link_libraries(testrunner ${tinyxml2_LIBRARIES})
|
||||
endif()
|
||||
if (USE_THREADS)
|
||||
target_link_libraries(testrunner ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
target_link_libraries(testrunner ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
if (NOT CMAKE_DISABLE_PRECOMPILE_HEADERS)
|
||||
target_precompile_headers(testrunner PRIVATE precompiled.h)
|
||||
|
|
|
@ -71,8 +71,8 @@ TEST(Test, warning_in_assert_macros)
|
|||
ASSERT_GE(i, i);
|
||||
|
||||
unsigned int u = errno;
|
||||
// cppcheck-suppress [unsignedPositive, compareValueOutOfTypeRangeError]
|
||||
// cppcheck-suppress [unsignedPositive]
|
||||
ASSERT_GE(u, 0);
|
||||
// cppcheck-suppress [unsignedLessThanZero, compareValueOutOfTypeRangeError]
|
||||
// cppcheck-suppress [unsignedLessThanZero]
|
||||
ASSERT_LT(u, 0);
|
||||
}
|
||||
|
|
|
@ -22,12 +22,27 @@
|
|||
#include <wx/memory.h>
|
||||
#include <wx/frame.h>
|
||||
#include <wx/menu.h>
|
||||
#include <wx/regex.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/propgrid/property.h>
|
||||
|
||||
void uninitvar_wxRegEx_GetMatch(wxRegEx &obj, size_t *start, size_t *len, size_t index)
|
||||
{
|
||||
size_t s,l;
|
||||
size_t *sPtr,*lPtr;
|
||||
// cppcheck-suppress uninitvar
|
||||
(void)obj.GetMatch(&s,lPtr);
|
||||
// TODO cppcheck-suppress uninitvar
|
||||
(void)obj.GetMatch(sPtr,&l);
|
||||
(void)obj.GetMatch(&s,&l);
|
||||
(void)obj.GetMatch(start,len);
|
||||
(void)obj.GetMatch(start,len,0);
|
||||
(void)obj.GetMatch(start,len,index);
|
||||
}
|
||||
|
||||
#ifdef __VISUALC__
|
||||
// Ensure no duplicateBreak warning is issued after wxLogApiError() calls.
|
||||
// This function does not terminate execution.
|
||||
|
|
|
@ -191,6 +191,7 @@ private:
|
|||
TEST_CASE(array_index_64); // #10878
|
||||
TEST_CASE(array_index_65); // #11066
|
||||
TEST_CASE(array_index_66); // #10740
|
||||
TEST_CASE(array_index_67); // #1596
|
||||
TEST_CASE(array_index_multidim);
|
||||
TEST_CASE(array_index_switch_in_for);
|
||||
TEST_CASE(array_index_for_in_for); // FP: #2634
|
||||
|
@ -288,6 +289,7 @@ private:
|
|||
TEST_CASE(terminateStrncpy2);
|
||||
TEST_CASE(terminateStrncpy3);
|
||||
TEST_CASE(terminateStrncpy4);
|
||||
TEST_CASE(terminateStrncpy5); // #9944
|
||||
TEST_CASE(recursive_long_time);
|
||||
|
||||
TEST_CASE(crash1); // Ticket #1587 - crash
|
||||
|
@ -1852,6 +1854,25 @@ private:
|
|||
errout.str());
|
||||
}
|
||||
|
||||
void array_index_67() {
|
||||
check("void func(int i) {\n" // #1596
|
||||
" int types[3];\n"
|
||||
" int type_cnt = 0;\n"
|
||||
" if (i == 0) {\n"
|
||||
" types[type_cnt] = 0;\n"
|
||||
" type_cnt++;\n"
|
||||
" types[type_cnt] = 0;\n"
|
||||
" type_cnt++;\n"
|
||||
" types[type_cnt] = 0;\n"
|
||||
" type_cnt++;\n"
|
||||
" } else {\n"
|
||||
" types[type_cnt] = 1;\n"
|
||||
" type_cnt++;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void array_index_multidim() {
|
||||
check("void f()\n"
|
||||
"{\n"
|
||||
|
@ -4322,6 +4343,23 @@ private:
|
|||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) The buffer 'buf' may not be null-terminated after the call to strncpy().\n", errout.str());
|
||||
}
|
||||
|
||||
void terminateStrncpy5() { // #9944
|
||||
check("void f(const std::string& buf) {\n"
|
||||
" char v[255];\n"
|
||||
" if (buf.size() >= sizeof(v))\n"
|
||||
" return;\n"
|
||||
" strncpy(v, buf.c_str(), sizeof(v));\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("void f(const std::string& buf) {\n"
|
||||
" char v[255];\n"
|
||||
" if (buf.size() >= sizeof(v))\n"
|
||||
" strncpy(v, buf.c_str(), sizeof(v));\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:4]: (warning, inconclusive) The buffer 'v' may not be null-terminated after the call to strncpy().\n", errout.str());
|
||||
}
|
||||
// extracttests.enable
|
||||
|
||||
void recursive_long_time() {
|
||||
|
|
|
@ -584,7 +584,10 @@ private:
|
|||
}
|
||||
|
||||
void cxxRecordDecl1() {
|
||||
const char clang[] = "`-CXXRecordDecl 0x34cc5f8 <1.cpp:2:1, col:7> col:7 class Foo";
|
||||
const char* clang = "`-CXXRecordDecl 0x34cc5f8 <1.cpp:2:1, col:7> col:7 class Foo";
|
||||
ASSERT_EQUALS("class Foo ;", parse(clang));
|
||||
|
||||
clang = "`-CXXRecordDecl 0x34cc5f8 <C:\\Foo\\Bar Baz\\1.cpp:2:1, col:7> col:7 class Foo";
|
||||
ASSERT_EQUALS("class Foo ;", parse(clang));
|
||||
}
|
||||
|
||||
|
|
|
@ -5258,6 +5258,12 @@ private:
|
|||
"}", &settingsUnix64);
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("int f(int x) {\n"
|
||||
" const int i = 0xFFFFFFFF;\n"
|
||||
" if (x == i) {}\n"
|
||||
"}", &settingsUnix64);
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" char c;\n"
|
||||
" if ((c = foo()) != -1) {}\n"
|
||||
|
|
|
@ -192,7 +192,7 @@ private:
|
|||
header += " <cppcheck version=\"";
|
||||
header += CppCheck::version();
|
||||
header += "\"/>\n <errors>";
|
||||
ASSERT_EQUALS(header, ErrorMessage::getXMLHeader());
|
||||
ASSERT_EQUALS(header, ErrorMessage::getXMLHeader(""));
|
||||
ASSERT_EQUALS(" </errors>\n</results>", ErrorMessage::getXMLFooter());
|
||||
std::string message(" <error id=\"errorId\" severity=\"error\"");
|
||||
message += " msg=\"Programming error.\" verbose=\"Verbose error\">\n";
|
||||
|
@ -208,7 +208,7 @@ private:
|
|||
header += " <cppcheck version=\"";
|
||||
header += CppCheck::version();
|
||||
header += "\"/>\n <errors>";
|
||||
ASSERT_EQUALS(header, ErrorMessage::getXMLHeader());
|
||||
ASSERT_EQUALS(header, ErrorMessage::getXMLHeader(""));
|
||||
ASSERT_EQUALS(" </errors>\n</results>", ErrorMessage::getXMLFooter());
|
||||
std::string message(" <error id=\"errorId\" severity=\"error\"");
|
||||
message += " msg=\"Programming error.\" verbose=\"Verbose error\">\n";
|
||||
|
|
|
@ -1731,6 +1731,18 @@ private:
|
|||
check("struct A{} a; A f1() { return std::move(a); }\n"
|
||||
"A f2() { volatile A var; return std::move(var); }");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("struct S { std::string msg{ \"abc\" }; };\n"
|
||||
"std::unique_ptr<S> get(std::vector<std::unique_ptr<S>>& v) {\n"
|
||||
" return std::move(v.front());\n"
|
||||
"}\n"
|
||||
"int main() {\n"
|
||||
" std::vector<std::unique_ptr<S>> v;\n"
|
||||
" v.emplace_back(std::make_unique<S>());\n"
|
||||
" auto p = get(v);\n"
|
||||
" std::cout << p->msg;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void negativeMemoryAllocationSizeError() { // #389
|
||||
|
|
|
@ -662,6 +662,11 @@ private:
|
|||
" +\" y = \" + b;\n"
|
||||
"}\n", /*inconclusive*/ true);
|
||||
ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) Found suspicious operator '+', result is not used.\n", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" *new int;\n"
|
||||
"}\n", /*inconclusive*/ true);
|
||||
ASSERT_EQUALS("[test.cpp:2]: (warning, inconclusive) Found suspicious operator '*', result is not used.\n", errout.str());
|
||||
}
|
||||
|
||||
void vardecl() {
|
||||
|
|
|
@ -93,6 +93,7 @@ private:
|
|||
TEST_CASE(assign21); // #10186
|
||||
TEST_CASE(assign22); // #9139
|
||||
TEST_CASE(assign23);
|
||||
TEST_CASE(assign24); // #7440
|
||||
|
||||
TEST_CASE(isAutoDealloc);
|
||||
|
||||
|
@ -504,6 +505,23 @@ private:
|
|||
settings = s;
|
||||
}
|
||||
|
||||
void assign24() { // #7440
|
||||
check("void f() {\n"
|
||||
" char* data = new char[100];\n"
|
||||
" char** dataPtr = &data;\n"
|
||||
" delete[] *dataPtr;\n"
|
||||
"}\n", true);
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" char* data = new char[100];\n"
|
||||
" char** dataPtr = &data;\n"
|
||||
" printf(\"test\");\n"
|
||||
" delete[] *dataPtr;\n"
|
||||
"}\n", true);
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void isAutoDealloc() {
|
||||
check("void f() {\n"
|
||||
" char *p = new char[100];"
|
||||
|
|
|
@ -57,7 +57,6 @@ private:
|
|||
TEST_CASE(toDoubleNumber);
|
||||
TEST_CASE(naninf);
|
||||
TEST_CASE(isNullValue);
|
||||
TEST_CASE(incdec);
|
||||
TEST_CASE(sin);
|
||||
TEST_CASE(cos);
|
||||
TEST_CASE(tan);
|
||||
|
@ -1192,27 +1191,6 @@ private:
|
|||
ASSERT_EQUALS(false, MathLib::isNullValue("-ENOMEM"));
|
||||
}
|
||||
|
||||
void incdec() const {
|
||||
// increment
|
||||
{
|
||||
const MathLib::biguint num = ~10U;
|
||||
const std::string op = "++";
|
||||
const std::string strNum = MathLib::incdec(MathLib::toString(num), op);
|
||||
const MathLib::biguint incrementedNum = MathLib::toULongNumber(strNum);
|
||||
ASSERT_EQUALS(num + 1U, incrementedNum);
|
||||
}
|
||||
// decrement
|
||||
{
|
||||
const MathLib::biguint num = ~10U;
|
||||
const std::string op = "--";
|
||||
const std::string strNum = MathLib::incdec(MathLib::toString(num), op);
|
||||
const MathLib::biguint decrementedNum = MathLib::toULongNumber(strNum);
|
||||
ASSERT_EQUALS(num - 1U, decrementedNum);
|
||||
}
|
||||
// invalid operation
|
||||
ASSERT_THROW(MathLib::incdec("1", "x"), InternalError); // throw
|
||||
}
|
||||
|
||||
void sin() const {
|
||||
ASSERT_EQUALS("0.0", MathLib::sin("0"));
|
||||
}
|
||||
|
|
|
@ -2401,6 +2401,38 @@ private:
|
|||
" return static_cast<int*>(malloc(size));\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("void f() { if (new int[42]) {} }\n" // #10857
|
||||
"void g() { if (malloc(42)) {} }\n");
|
||||
ASSERT_EQUALS("[test.cpp:1]: (error) Allocation with new, if doesn't release it.\n"
|
||||
"[test.cpp:2]: (error) Allocation with malloc, if doesn't release it.\n",
|
||||
errout.str());
|
||||
|
||||
check("const char* string(const char* s) {\n"
|
||||
" StringSet::iterator it = strings_.find(s);\n"
|
||||
" if (it != strings_.end())\n"
|
||||
" return *it;\n"
|
||||
" return *strings_.insert(it, std::strcpy(new char[std::strlen(s) + 1], s));\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("struct S {\n"
|
||||
" static void load(const QString& projPath) {\n"
|
||||
" if (proj_)\n"
|
||||
" return;\n"
|
||||
" proj_ = new ProjectT(projPath);\n"
|
||||
" proj_->open(new OpenCallback());\n"
|
||||
" }\n"
|
||||
"private:\n"
|
||||
" static Core::ProjectBase* proj_;\n"
|
||||
"};\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("void f(const std::string& s, int n) {\n"
|
||||
" std::unique_ptr<char[]> u;\n"
|
||||
" u.reset(strcpy(new char[n], s.c_str()));\n"
|
||||
"};\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void missingAssignment() {
|
||||
|
@ -2452,7 +2484,7 @@ private:
|
|||
"{\n"
|
||||
" 42,malloc(42);\n"
|
||||
"}");
|
||||
TODO_ASSERT_EQUALS("[test.cpp:3]: (error) Return value of allocation function 'malloc' is not stored.\n", "", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:3]: (error) Return value of allocation function 'malloc' is not stored.\n", errout.str());
|
||||
|
||||
check("void *f()\n"
|
||||
"{\n"
|
||||
|
@ -2595,6 +2627,33 @@ private:
|
|||
" C{ new QWidget, 1 };\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("void f(bool b) { if (b && malloc(42)) {} }\n" // // #10858
|
||||
"void g(bool b) { if (b || malloc(42)) {} }\n");
|
||||
ASSERT_EQUALS("[test.cpp:1]: (error) Return value of allocation function 'malloc' is not stored.\n"
|
||||
"[test.cpp:2]: (error) Return value of allocation function 'malloc' is not stored.\n",
|
||||
errout.str());
|
||||
|
||||
check("void f0(const bool b) { b ? new int : nullptr; }\n" // #11155
|
||||
"void f1(const bool b) { b ? nullptr : new int; }\n"
|
||||
"int* g0(const bool b) { return b ? new int : nullptr; }\n"
|
||||
"void g1(const bool b) { h(b, b ? nullptr : new int); }\n");
|
||||
ASSERT_EQUALS("[test.cpp:1]: (error) Return value of allocation function 'new' is not stored.\n"
|
||||
"[test.cpp:2]: (error) Return value of allocation function 'new' is not stored.\n",
|
||||
errout.str());
|
||||
|
||||
check("void f() {\n" // #11157
|
||||
" switch (*new int) { case 42: break; }\n"
|
||||
" switch (*malloc(42)) { case 42: break; }\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:2]: (error) Allocation with new, switch doesn't release it.\n"
|
||||
"[test.cpp:3]: (error) Allocation with malloc, switch doesn't release it.\n",
|
||||
errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" Ref<StringBuffer> remove(new StringBuffer());\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void smartPointerFunctionParam() {
|
||||
|
|
|
@ -64,6 +64,7 @@ private:
|
|||
TEST_CASE(zeroDiv11);
|
||||
TEST_CASE(zeroDiv12);
|
||||
TEST_CASE(zeroDiv13);
|
||||
TEST_CASE(zeroDiv14); // #1169
|
||||
|
||||
TEST_CASE(zeroDivCond); // division by zero / useless condition
|
||||
|
||||
|
@ -587,6 +588,17 @@ private:
|
|||
ASSERT_EQUALS("[test.cpp:4]: (error) Division by zero.\n", errout.str());
|
||||
}
|
||||
|
||||
void zeroDiv14() {
|
||||
check("void f() {\n" // #1169
|
||||
" double dx = 1.;\n"
|
||||
" int ix = 1;\n"
|
||||
" int i = 1;\n"
|
||||
" std::cout << ix / (i >> 1) << std::endl;\n"
|
||||
" std::cout << dx / (i >> 1) << std::endl;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Division by zero.\n", errout.str());
|
||||
}
|
||||
|
||||
void zeroDivCond() {
|
||||
check("void f(unsigned int x) {\n"
|
||||
" int y = 17 / x;\n"
|
||||
|
@ -3230,6 +3242,21 @@ private:
|
|||
ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'p' can be declared as pointer to const\n"
|
||||
"[test.cpp:5]: (style) Variable 'p' can be declared as pointer to const\n",
|
||||
errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" char a[1][1];\n"
|
||||
" char* b[1];\n"
|
||||
" b[0] = a[0];\n"
|
||||
" **b = 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("ptrdiff_t f(int *p0, int *p1) {\n" // #11148
|
||||
" return p0 - p1;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:1]: (style) Parameter 'p0' can be declared as pointer to const\n"
|
||||
"[test.cpp:1]: (style) Parameter 'p1' can be declared as pointer to const\n",
|
||||
errout.str());
|
||||
}
|
||||
|
||||
void switchRedundantAssignmentTest() {
|
||||
|
@ -9383,7 +9410,7 @@ private:
|
|||
" int local_argc = 0;\n"
|
||||
" local_argv[local_argc++] = argv[0];\n"
|
||||
"}\n", "test.c");
|
||||
ASSERT_EQUALS("[test.c:1]: (style) Parameter 'argv' can be declared as const array\n", errout.str());
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" int x = 0;\n"
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Cppcheck - A tool for static C/C++ code analysis
|
||||
* Copyright (C) 2007-2022 Cppcheck team.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "processexecutor.h"
|
||||
#include "settings.h"
|
||||
#include "testsuite.h"
|
||||
#include "testutils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class TestProcessExecutor : public TestFixture {
|
||||
public:
|
||||
TestProcessExecutor() : TestFixture("TestProcessExecutor") {}
|
||||
|
||||
private:
|
||||
Settings settings;
|
||||
|
||||
/**
|
||||
* Execute check using n jobs for y files which are have
|
||||
* identical data, given within data.
|
||||
*/
|
||||
void check(unsigned int jobs, int files, int result, const std::string &data) {
|
||||
errout.str("");
|
||||
output.str("");
|
||||
|
||||
std::map<std::string, std::size_t> filemap;
|
||||
for (int i = 1; i <= files; ++i) {
|
||||
std::ostringstream oss;
|
||||
oss << "file_" << i << ".cpp";
|
||||
filemap[oss.str()] = data.size();
|
||||
}
|
||||
|
||||
settings.jobs = jobs;
|
||||
ProcessExecutor executor(filemap, settings, *this);
|
||||
std::vector<ScopedFile> scopedfiles;
|
||||
scopedfiles.reserve(filemap.size());
|
||||
for (std::map<std::string, std::size_t>::const_iterator i = filemap.begin(); i != filemap.end(); ++i)
|
||||
scopedfiles.emplace_back(i->first, data);
|
||||
|
||||
ASSERT_EQUALS(result, executor.check());
|
||||
}
|
||||
|
||||
void run() override {
|
||||
#if !defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||
LOAD_LIB_2(settings.library, "std.cfg");
|
||||
|
||||
TEST_CASE(deadlock_with_many_errors);
|
||||
TEST_CASE(many_threads);
|
||||
TEST_CASE(no_errors_more_files);
|
||||
TEST_CASE(no_errors_less_files);
|
||||
TEST_CASE(no_errors_equal_amount_files);
|
||||
TEST_CASE(one_error_less_files);
|
||||
TEST_CASE(one_error_several_files);
|
||||
#endif // !WIN32
|
||||
}
|
||||
|
||||
void deadlock_with_many_errors() {
|
||||
std::ostringstream oss;
|
||||
oss << "int main()\n"
|
||||
<< "{\n";
|
||||
for (int i = 0; i < 500; i++)
|
||||
oss << " {char *a = malloc(10);}\n";
|
||||
|
||||
oss << " return 0;\n"
|
||||
<< "}\n";
|
||||
check(2, 3, 3, oss.str());
|
||||
}
|
||||
|
||||
void many_threads() {
|
||||
check(16, 100, 100,
|
||||
"int main()\n"
|
||||
"{\n"
|
||||
" char *a = malloc(10);\n"
|
||||
" return 0;\n"
|
||||
"}");
|
||||
}
|
||||
|
||||
void no_errors_more_files() {
|
||||
check(2, 3, 0,
|
||||
"int main()\n"
|
||||
"{\n"
|
||||
" return 0;\n"
|
||||
"}");
|
||||
}
|
||||
|
||||
void no_errors_less_files() {
|
||||
check(2, 1, 0,
|
||||
"int main()\n"
|
||||
"{\n"
|
||||
" return 0;\n"
|
||||
"}");
|
||||
}
|
||||
|
||||
void no_errors_equal_amount_files() {
|
||||
check(2, 2, 0,
|
||||
"int main()\n"
|
||||
"{\n"
|
||||
" return 0;\n"
|
||||
"}");
|
||||
}
|
||||
|
||||
void one_error_less_files() {
|
||||
check(2, 1, 1,
|
||||
"int main()\n"
|
||||
"{\n"
|
||||
" {char *a = malloc(10);}\n"
|
||||
" return 0;\n"
|
||||
"}");
|
||||
}
|
||||
|
||||
void one_error_several_files() {
|
||||
check(2, 20, 20,
|
||||
"int main()\n"
|
||||
"{\n"
|
||||
" {char *a = malloc(10);}\n"
|
||||
" return 0;\n"
|
||||
"}");
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestProcessExecutor)
|
|
@ -27,6 +27,8 @@
|
|||
<ClCompile Include="..\cli\cmdlineparser.cpp" />
|
||||
<ClCompile Include="..\cli\cppcheckexecutor.cpp" />
|
||||
<ClCompile Include="..\cli\filelister.cpp" />
|
||||
<ClCompile Include="..\cli\executor.cpp" />
|
||||
<ClCompile Include="..\cli\processexecutor.cpp" />
|
||||
<ClCompile Include="..\cli\threadexecutor.cpp" />
|
||||
<ClCompile Include="..\lib\astutils.cpp" />
|
||||
<ClCompile Include="options.cpp" />
|
||||
|
@ -64,6 +66,7 @@
|
|||
<ClCompile Include="testplatform.cpp" />
|
||||
<ClCompile Include="testpostfixoperator.cpp" />
|
||||
<ClCompile Include="testpreprocessor.cpp" />
|
||||
<ClCompile Include="testprocessexecutor.cpp" />
|
||||
<ClCompile Include="testrunner.cpp" />
|
||||
<ClCompile Include="testsimplifytemplate.cpp" />
|
||||
<ClCompile Include="testsimplifytokens.cpp" />
|
||||
|
|
|
@ -218,6 +218,7 @@ private:
|
|||
TEST_CASE(template173); // #10332 crash
|
||||
TEST_CASE(template174); // #10506 hang
|
||||
TEST_CASE(template175); // #10908
|
||||
TEST_CASE(template176); // #11146
|
||||
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
||||
TEST_CASE(template_specialization_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
||||
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)
|
||||
|
@ -4458,7 +4459,7 @@ private:
|
|||
ASSERT_EQUALS(exp, tok(code));
|
||||
}
|
||||
|
||||
void template175()
|
||||
void template175() // #10908
|
||||
{
|
||||
const char code[] = "template <typename T, int value> T Get() {return value;}\n"
|
||||
"char f() { Get<int,10>(); }\n";
|
||||
|
@ -4468,6 +4469,27 @@ private:
|
|||
ASSERT_EQUALS(exp, tok(code));
|
||||
}
|
||||
|
||||
void template176() // #11146 don't crash
|
||||
{
|
||||
const char code[] = "struct a {\n"
|
||||
" template <typename> class b {};\n"
|
||||
"};\n"
|
||||
"struct c {\n"
|
||||
" template <typename> a::b<int> d();\n"
|
||||
" ;\n"
|
||||
"};\n"
|
||||
"template <typename> a::b<int> c::d() {}\n"
|
||||
"template <> class a::b<int> c::d<int>() { return {}; };\n";
|
||||
const char exp[] = "struct a { "
|
||||
"class b<int> c :: d<int> ( ) ; "
|
||||
"template < typename > class b { } ; "
|
||||
"} ; "
|
||||
"struct c { a :: b<int> d<int> ( ) ; } ; "
|
||||
"class a :: b<int> c :: d<int> ( ) { return { } ; } ; "
|
||||
"a :: b<int> c :: d<int> ( ) { }";
|
||||
ASSERT_EQUALS(exp, tok(code));
|
||||
}
|
||||
|
||||
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
||||
const char code[] = "template <typename T> struct C {};\n"
|
||||
"template <typename T> struct S {a};\n"
|
||||
|
|
|
@ -62,7 +62,6 @@ private:
|
|||
TEST_CASE(double_plus);
|
||||
TEST_CASE(redundant_plus);
|
||||
TEST_CASE(redundant_plus_numbers);
|
||||
TEST_CASE(parentheses1);
|
||||
TEST_CASE(declareVar);
|
||||
|
||||
TEST_CASE(declareArray);
|
||||
|
@ -90,20 +89,13 @@ private:
|
|||
// Simplify "?:"
|
||||
TEST_CASE(simplifyConditionOperator);
|
||||
|
||||
// Simplify calculations
|
||||
TEST_CASE(calculations);
|
||||
TEST_CASE(comparisons);
|
||||
TEST_CASE(simplifyCalculations);
|
||||
|
||||
TEST_CASE(simplifyOperator1);
|
||||
TEST_CASE(simplifyOperator2);
|
||||
|
||||
TEST_CASE(simplifyArrayAccessSyntax);
|
||||
|
||||
TEST_CASE(pointeralias1);
|
||||
TEST_CASE(pointeralias2);
|
||||
TEST_CASE(pointeralias3);
|
||||
TEST_CASE(pointeralias4);
|
||||
|
||||
// struct ABC { } abc; => struct ABC { }; ABC abc;
|
||||
TEST_CASE(simplifyStructDecl1);
|
||||
|
@ -137,58 +129,35 @@ private:
|
|||
TEST_CASE(simplifyNamespaceAliases1);
|
||||
TEST_CASE(simplifyNamespaceAliases2); // ticket #10281
|
||||
|
||||
TEST_CASE(simplifyKnownVariables1);
|
||||
TEST_CASE(simplifyKnownVariables2);
|
||||
TEST_CASE(simplifyKnownVariables3);
|
||||
TEST_CASE(simplifyKnownVariables4);
|
||||
TEST_CASE(simplifyKnownVariables5);
|
||||
TEST_CASE(simplifyKnownVariables6);
|
||||
TEST_CASE(simplifyKnownVariables7);
|
||||
TEST_CASE(simplifyKnownVariables8);
|
||||
TEST_CASE(simplifyKnownVariables9);
|
||||
TEST_CASE(simplifyKnownVariables10);
|
||||
TEST_CASE(simplifyKnownVariables11);
|
||||
TEST_CASE(simplifyKnownVariables13);
|
||||
TEST_CASE(simplifyKnownVariables14);
|
||||
TEST_CASE(simplifyKnownVariables15);
|
||||
TEST_CASE(simplifyKnownVariables16);
|
||||
TEST_CASE(simplifyKnownVariables17);
|
||||
TEST_CASE(simplifyKnownVariables18);
|
||||
TEST_CASE(simplifyKnownVariables19);
|
||||
TEST_CASE(simplifyKnownVariables20);
|
||||
TEST_CASE(simplifyKnownVariables21);
|
||||
TEST_CASE(simplifyKnownVariables22);
|
||||
TEST_CASE(simplifyKnownVariables23);
|
||||
TEST_CASE(simplifyKnownVariables25);
|
||||
TEST_CASE(simplifyKnownVariables27);
|
||||
TEST_CASE(simplifyKnownVariables28);
|
||||
// FIXME Does expression id handle these? TEST_CASE(simplifyKnownVariables29); // ticket #1811
|
||||
TEST_CASE(simplifyKnownVariables30);
|
||||
TEST_CASE(simplifyKnownVariables31);
|
||||
TEST_CASE(simplifyKnownVariables32); // const
|
||||
TEST_CASE(simplifyKnownVariables33); // struct variable
|
||||
TEST_CASE(simplifyKnownVariables34);
|
||||
TEST_CASE(simplifyKnownVariables36); // ticket #2304 - known value for strcpy parameter
|
||||
TEST_CASE(simplifyKnownVariables39);
|
||||
TEST_CASE(simplifyKnownVariables41); // p=&x; if (p) ..
|
||||
TEST_CASE(simplifyKnownVariables42); // ticket #2031 - known string value after strcpy
|
||||
TEST_CASE(simplifyKnownVariables43);
|
||||
TEST_CASE(simplifyKnownVariables44); // ticket #3117 - don't simplify static variables
|
||||
TEST_CASE(simplifyKnownVariables45); // ticket #3281 - static constant variable not simplified
|
||||
TEST_CASE(simplifyKnownVariables46); // ticket #3587 - >>
|
||||
TEST_CASE(simplifyKnownVariables47); // ticket #3627 - >>
|
||||
TEST_CASE(simplifyKnownVariables48); // ticket #3754 - wrong simplification in for loop header
|
||||
TEST_CASE(simplifyKnownVariables49); // #3691 - continue in switch
|
||||
TEST_CASE(simplifyKnownVariables50); // #4066 sprintf changes
|
||||
TEST_CASE(simplifyKnownVariables51); // #4409 hang
|
||||
TEST_CASE(simplifyKnownVariables53); // references
|
||||
TEST_CASE(simplifyKnownVariables54); // #4913 'x' is not 0 after *--x=0;
|
||||
TEST_CASE(simplifyKnownVariables55); // pointer alias
|
||||
TEST_CASE(simplifyKnownVariables56); // ticket #5301 - >>
|
||||
TEST_CASE(simplifyKnownVariables57); // ticket #4724
|
||||
TEST_CASE(simplifyKnownVariables58); // ticket #5268
|
||||
TEST_CASE(simplifyKnownVariables59); // skip for header
|
||||
TEST_CASE(simplifyKnownVariables60); // #6829
|
||||
TEST_CASE(simplifyKnownVariables61); // #7805
|
||||
TEST_CASE(simplifyKnownVariables62); // #5666 - p=&str[0]
|
||||
TEST_CASE(simplifyKnownVariables63); // #10798
|
||||
|
@ -203,11 +172,8 @@ private:
|
|||
TEST_CASE(simplifyKnownVariablesClassMember); // #2815 - value of class member may be changed by function call
|
||||
TEST_CASE(simplifyKnownVariablesFunctionCalls); // Function calls (don't assume pass by reference)
|
||||
TEST_CASE(simplifyKnownVariablesGlobalVars);
|
||||
TEST_CASE(simplifyKnownVariablesPointerAliasFunctionCall); // #7440
|
||||
TEST_CASE(simplifyKnownVariablesNamespace); // #10059
|
||||
|
||||
TEST_CASE(simplify_constants2);
|
||||
TEST_CASE(simplify_constants4);
|
||||
TEST_CASE(simplify_constants6); // Ticket #5625: Ternary operator as template parameter
|
||||
TEST_CASE(simplifyVarDeclInitLists);
|
||||
}
|
||||
|
@ -1887,11 +1853,6 @@ private:
|
|||
}
|
||||
|
||||
|
||||
void parentheses1() {
|
||||
ASSERT_EQUALS("a <= 110 ;", tok("a <= (10+100);"));
|
||||
ASSERT_EQUALS("{ while ( x ( ) == -1 ) { } }", tok("{while((x()) == -1){ }}"));
|
||||
}
|
||||
|
||||
void declareVar() {
|
||||
const char code[] = "void f ( ) { char str [ 100 ] = \"100\" ; }";
|
||||
ASSERT_EQUALS(code, tok(code));
|
||||
|
@ -2334,7 +2295,7 @@ private:
|
|||
|
||||
{
|
||||
const char code[] = "tr = (struct reg){ .a = (1), .c = (2) };";
|
||||
const char expected[] = "tr = ( struct reg ) { . a = 1 , . c = 2 } ;";
|
||||
const char expected[] = "tr = ( struct reg ) { . a = 1 , . c = ( 2 ) } ;";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
}
|
||||
|
@ -2414,120 +2375,6 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void calculations() {
|
||||
{
|
||||
const char code[] = "a[i+8+2];";
|
||||
ASSERT_EQUALS("a [ i + 10 ] ;", tok(code));
|
||||
}
|
||||
{
|
||||
const char code[] = "a[8+2+i];";
|
||||
ASSERT_EQUALS("a [ 10 + i ] ;", tok(code));
|
||||
}
|
||||
{
|
||||
const char code[] = "a[i + 2 * (2 * 4)];";
|
||||
ASSERT_EQUALS("a [ i + 16 ] ;", tok(code));
|
||||
}
|
||||
{
|
||||
const char code[] = "a[i + 100 - 90];";
|
||||
ASSERT_EQUALS("a [ i + 10 ] ;", tok(code));
|
||||
}
|
||||
{
|
||||
const char code[] = "a[1+1+1+1+1+1+1+1+1+1-2+5-3];";
|
||||
ASSERT_EQUALS("a [ 10 ] ;", tok(code));
|
||||
}
|
||||
{
|
||||
const char code[] = "a[10+10-10-10];";
|
||||
ASSERT_EQUALS("a [ 0 ] ;", tok(code));
|
||||
}
|
||||
|
||||
ASSERT_EQUALS("a [ 4 ] ;", tok("a[1+3|4];"));
|
||||
ASSERT_EQUALS("a [ 4U ] ;", tok("a[1+3|4U];"));
|
||||
ASSERT_EQUALS("a [ 3 ] ;", tok("a[1+2&3];"));
|
||||
ASSERT_EQUALS("a [ 3U ] ;", tok("a[1+2&3U];"));
|
||||
ASSERT_EQUALS("a [ 5 ] ;", tok("a[1-0^4];"));
|
||||
ASSERT_EQUALS("a [ 5U ] ;", tok("a[1-0^4U];"));
|
||||
|
||||
ASSERT_EQUALS("x = 1 + 2 * y ;", tok("x=1+2*y;"));
|
||||
ASSERT_EQUALS("x = 7 ;", tok("x=1+2*3;"));
|
||||
ASSERT_EQUALS("x = 47185 ;", tok("x=(65536*72/100);"));
|
||||
ASSERT_EQUALS("x = 1500000 / ( ( 90000 ) * 1000 / 54000 ) ;", tok("x = 1500000 / ((145000 - 55000) * 1000 / 54000);"));
|
||||
ASSERT_EQUALS("int a [ 8 ] ;", tok("int a[5+6/2];"));
|
||||
ASSERT_EQUALS("int a [ 4 ] ;", tok("int a[(10)-1-5];"));
|
||||
ASSERT_EQUALS("int a [ i - 9 ] ;", tok("int a[i - 10 + 1];"));
|
||||
ASSERT_EQUALS("int a [ i - 11 ] ;", tok("int a[i - 10 - 1];"));
|
||||
|
||||
ASSERT_EQUALS("x = y ;", tok("x=0+y+0-0;"));
|
||||
ASSERT_EQUALS("x = 0 ;", tok("x=0*y;"));
|
||||
|
||||
ASSERT_EQUALS("x = 501 ;", tok("x = 1000 + 2 >> 1;"));
|
||||
ASSERT_EQUALS("x = 125 ;", tok("x = 1000 / 2 >> 2;"));
|
||||
|
||||
{
|
||||
// Ticket #1997
|
||||
const char code[] = "void * operator new[](size_t);";
|
||||
ASSERT_EQUALS("void * operatornew[] ( long ) ;", tok(code, true, Settings::Win32A));
|
||||
}
|
||||
|
||||
ASSERT_EQUALS("; a [ 0 ] ;", tok(";a[0*(*p)];"));
|
||||
|
||||
ASSERT_EQUALS(";", tok("; x = x + 0;"));
|
||||
|
||||
ASSERT_EQUALS("{ if ( a == 2 ) { } }", tok("{if (a==1+1){}}"));
|
||||
ASSERT_EQUALS("{ if ( a + 2 != 6 ) { } }", tok("{if (a+1+1!=1+2+3){}}"));
|
||||
ASSERT_EQUALS("{ if ( 4 < a ) { } }", tok("{if (14-2*5<a*4/(2*2)){}}"));
|
||||
|
||||
ASSERT_EQUALS("( y / 2 - 2 ) ;", tok("(y / 2 - 2);"));
|
||||
ASSERT_EQUALS("( y % 2 - 2 ) ;", tok("(y % 2 - 2);"));
|
||||
|
||||
ASSERT_EQUALS("( 4 ) ;", tok("(1 * 2 / 1 * 2);")); // #3722
|
||||
|
||||
ASSERT_EQUALS("x ( 60129542144 ) ;", tok("x(14<<4+17<<300%17);")); // #4931
|
||||
ASSERT_EQUALS("x ( 1 ) ;", tok("x(8|5&6+0 && 7);")); // #6104
|
||||
ASSERT_EQUALS("x ( 1 ) ;", tok("x(2 && 4<<4<<5 && 4);")); // #4933
|
||||
ASSERT_EQUALS("x ( 1 ) ;", tok("x(9&&8%5%4/3);")); // #4931
|
||||
ASSERT_EQUALS("x ( 1 ) ;", tok("x(2 && 2|5<<2%4);")); // #4931
|
||||
ASSERT_EQUALS("x ( -2 << 6 | 1 ) ;", tok("x(1-3<<6|5/3);")); // #4931
|
||||
ASSERT_EQUALS("x ( 2 ) ;", tok("x(2|0*0&2>>1+0%2*1);")); // #4931
|
||||
ASSERT_EQUALS("x ( 0 & 4 != 1 ) ;", tok("x(4%1<<1&4!=1);")); // #4931 (can be simplified further but it's not a problem)
|
||||
ASSERT_EQUALS("x ( 1 ) ;", tok("x(0&&4>0==2||4);")); // #4931
|
||||
|
||||
// don't remove these spaces..
|
||||
ASSERT_EQUALS("new ( auto ) ( 4 ) ;", tok("new (auto)(4);"));
|
||||
}
|
||||
|
||||
void comparisons() {
|
||||
ASSERT_EQUALS("( 1 ) ;", tok("( 1 < 2 );"));
|
||||
ASSERT_EQUALS("( x && 1 ) ;", tok("( x && 1 < 2 );"));
|
||||
ASSERT_EQUALS("( 5 ) ;", tok("( 1 < 2 && 3 < 4 ? 5 : 6 );"));
|
||||
ASSERT_EQUALS("( 6 ) ;", tok("( 1 > 2 && 3 > 4 ? 5 : 6 );"));
|
||||
}
|
||||
|
||||
void simplifyCalculations() {
|
||||
ASSERT_EQUALS("void foo ( char str [ ] ) { char x ; x = ( * str ) ; }",
|
||||
tok("void foo ( char str [ ] ) { char x = 0 | ( * str ) ; }"));
|
||||
ASSERT_EQUALS("void foo ( ) { if ( b ) { } }",
|
||||
tok("void foo ( ) { if (b + 0) { } }"));
|
||||
ASSERT_EQUALS("void foo ( ) { if ( b ) { } }",
|
||||
tok("void foo ( ) { if (0 + b) { } }"));
|
||||
ASSERT_EQUALS("void foo ( ) { if ( b ) { } }",
|
||||
tok("void foo ( ) { if (b - 0) { } }"));
|
||||
ASSERT_EQUALS("void foo ( ) { if ( b ) { } }",
|
||||
tok("void foo ( ) { if (b * 1) { } }"));
|
||||
ASSERT_EQUALS("void foo ( ) { if ( b ) { } }",
|
||||
tok("void foo ( ) { if (1 * b) { } }"));
|
||||
//ASSERT_EQUALS("void foo ( ) { if ( b ) { } }",
|
||||
// tok("void foo ( ) { if (b / 1) { } }"));
|
||||
ASSERT_EQUALS("void foo ( ) { if ( b ) { } }",
|
||||
tok("void foo ( ) { if (b | 0) { } }"));
|
||||
ASSERT_EQUALS("void foo ( ) { if ( b ) { } }",
|
||||
tok("void foo ( ) { if (0 | b) { } }"));
|
||||
ASSERT_EQUALS("void foo ( int b ) { int a ; a = b ; bar ( a ) ; }",
|
||||
tok("void foo ( int b ) { int a = b | 0 ; bar ( a ) ; }"));
|
||||
ASSERT_EQUALS("void foo ( int b ) { int a ; a = b ; bar ( a ) ; }",
|
||||
tok("void foo ( int b ) { int a = 0 | b ; bar ( a ) ; }"));
|
||||
}
|
||||
|
||||
|
||||
void simplifyOperator1() {
|
||||
// #3237 - error merging namespaces with operators
|
||||
const char code[] = "class c {\n"
|
||||
|
@ -2607,16 +2454,6 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void pointeralias2() {
|
||||
const char code[] = "void f()\n"
|
||||
"{\n"
|
||||
" int i;\n"
|
||||
" int *p = &i;\n"
|
||||
" return *p;\n"
|
||||
"}\n";
|
||||
ASSERT_EQUALS("void f ( ) { int i ; int * p ; return i ; }", tok(code));
|
||||
}
|
||||
|
||||
void pointeralias3() {
|
||||
const char code[] = "void f()\n"
|
||||
"{\n"
|
||||
|
@ -2635,18 +2472,6 @@ private:
|
|||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
void pointeralias4() {
|
||||
const char code[] = "int f()\n"
|
||||
"{\n"
|
||||
" int i;\n"
|
||||
" int *p = &i;\n"
|
||||
" *p = 5;\n"
|
||||
" return i;\n"
|
||||
"}\n";
|
||||
const char expected[] = "int f ( ) { int i ; int * p ; i = 5 ; return 5 ; }";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
void simplifyStructDecl1() {
|
||||
{
|
||||
const char code[] = "struct ABC { } abc;";
|
||||
|
@ -3228,37 +3053,9 @@ private:
|
|||
std::istringstream istr(code);
|
||||
ASSERT_LOC(tokenizer.tokenize(istr, "test.cpp"), file, line);
|
||||
|
||||
(tokenizer.simplifyKnownVariables)();
|
||||
|
||||
return tokenizer.tokens()->stringifyList(nullptr, false);
|
||||
}
|
||||
|
||||
void simplifyKnownVariables1() {
|
||||
{
|
||||
const char code[] = "void f()\n"
|
||||
"{\n"
|
||||
" int a = 10;\n"
|
||||
" if (a);\n"
|
||||
"}\n";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"void f ( ) { int a ; a = 10 ; if ( 10 ) { ; } }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "void f()\n"
|
||||
"{\n"
|
||||
" int a = 10;\n"
|
||||
" if (!a);\n"
|
||||
"}\n";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"void f ( ) { int a ; a = 10 ; if ( ! 10 ) { ; } }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
}
|
||||
|
||||
void simplifyKnownVariables2() {
|
||||
const char code[] = "void f()\n"
|
||||
"{\n"
|
||||
|
@ -3313,136 +3110,6 @@ private:
|
|||
simplifyKnownVariables(code));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables6() {
|
||||
const char code[] = "void f()\n"
|
||||
"{\n"
|
||||
" char str[2];"
|
||||
" int a = 4;\n"
|
||||
" str[a] = 0;\n"
|
||||
"}\n";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"void f ( ) { char str [ 2 ] ; int a ; a = 4 ; str [ 4 ] = 0 ; }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables7() {
|
||||
const char code[] = "void foo()\n"
|
||||
"{\n"
|
||||
" int i = 22;\n"
|
||||
" abc[i++] = 1;\n"
|
||||
" abc[++i] = 2;\n"
|
||||
"}\n";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"void foo ( ) { int i ; i = 24 ; abc [ 22 ] = 1 ; abc [ 24 ] = 2 ; }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables8() {
|
||||
const char code[] = "void foo()\n"
|
||||
"{\n"
|
||||
" int i = 22;\n"
|
||||
" i++;\n"
|
||||
" abc[i] = 0;\n"
|
||||
"}\n";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"void foo ( ) { int i ; i = 23 ; abc [ 23 ] = 0 ; }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables9() {
|
||||
const char code[] = "void foo()\n"
|
||||
"{\n"
|
||||
" int a = 1, b = 2;\n"
|
||||
" if (a < b)\n"
|
||||
" ;\n"
|
||||
"}\n";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"void foo ( ) { int a ; a = 1 ; int b ; b = 2 ; if ( 1 < 2 ) { ; } }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables10() {
|
||||
{
|
||||
const char code[] = "void f()\n"
|
||||
"{\n"
|
||||
" bool b=false;\n"
|
||||
"\n"
|
||||
" {\n"
|
||||
" b = true;\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" if( b )\n"
|
||||
" {\n"
|
||||
" a();\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
|
||||
const std::string expected1("void f ( ) {"
|
||||
" bool b ; b = false ;"
|
||||
" { b = true ; }");
|
||||
|
||||
TODO_ASSERT_EQUALS(
|
||||
expected1 + " if ( true ) { a ( ) ; } }",
|
||||
expected1 + " if ( b ) { a ( ) ; } }",
|
||||
simplifyKnownVariables(code));
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "void f()\n"
|
||||
"{\n"
|
||||
" bool b=false;\n"
|
||||
" { b = false; }\n"
|
||||
" {\n"
|
||||
" b = true;\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" if( b )\n"
|
||||
" {\n"
|
||||
" a();\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
|
||||
TODO_ASSERT_EQUALS(
|
||||
"void f ( ) { bool b ; b = false ; { b = false ; } { b = true ; } if ( true ) { a ( ) ; } }",
|
||||
"void f ( ) { bool b ; b = false ; { b = false ; } { b = true ; } if ( b ) { a ( ) ; } }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "void f()\n"
|
||||
"{\n"
|
||||
" int b=0;\n"
|
||||
" b = 1;\n"
|
||||
" for( int i = 0; i < 10; i++ )"
|
||||
" {\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" return b;\n"
|
||||
"}\n";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"void f ( ) { int b ; b = 0 ; b = 1 ; for ( int i = 0 ; i < 10 ; i ++ ) { } return 1 ; }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
}
|
||||
|
||||
void simplifyKnownVariables11() {
|
||||
const char code[] = "const int foo = 0;\n"
|
||||
"int main()\n"
|
||||
"{\n"
|
||||
" int foo=0;\n"
|
||||
"}\n";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"int main ( ) { int foo ; foo = 0 ; }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables13() {
|
||||
const char code[] = "void f()\n"
|
||||
"{\n"
|
||||
|
@ -3461,32 +3128,6 @@ private:
|
|||
ASSERT_EQUALS(code, simplifyKnownVariables(code));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables15() {
|
||||
{
|
||||
const char code[] = "int main()\n"
|
||||
"{\n"
|
||||
" int x=5;\n"
|
||||
" std::cout << 10 / x << std::endl;\n"
|
||||
"}\n";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"int main ( ) { int x ; x = 5 ; std :: cout << 10 / 5 << std :: endl ; }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "int main()\n"
|
||||
"{\n"
|
||||
" int x=5;\n"
|
||||
" std::cout << x / ( x == 1 ) << std::endl;\n"
|
||||
"}\n";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"int main ( ) { int x ; x = 5 ; std :: cout << 5 / ( 5 == 1 ) << std :: endl ; }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
}
|
||||
|
||||
void simplifyKnownVariables16() {
|
||||
// ticket #807 - segmentation fault when macro isn't found
|
||||
const char code[] = "void f ( ) { int n = 1; DISPATCH(while); }";
|
||||
|
@ -3515,111 +3156,12 @@ private:
|
|||
simplifyKnownVariables(code));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables20() {
|
||||
const char code[] = "void f()\n"
|
||||
"{\n"
|
||||
" int i = 0;\n"
|
||||
" if (x) {\n"
|
||||
" if (i) i=0;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"void f ( ) { int i ; i = 0 ; if ( x ) { if ( 0 ) { i = 0 ; } } }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables21() {
|
||||
const char code[] = "void foo() { int n = 10; for (int i = 0; i < n; ++i) { } }";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"void foo ( ) { int n ; n = 10 ; for ( int i = 0 ; i < 10 ; ++ i ) { } }",
|
||||
simplifyKnownVariables(code));
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"void foo ( int i ) { int n ; n = i ; for ( i = 0 ; i < n ; ++ i ) { } }",
|
||||
simplifyKnownVariables("void foo(int i) { int n = i; for (i = 0; i < n; ++i) { } }"));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables22() {
|
||||
// This testcase is related to ticket #1169
|
||||
{
|
||||
const char code[] = "void foo()\n"
|
||||
"{\n"
|
||||
" int n = 10;\n"
|
||||
" i = (n >> 1);\n"
|
||||
"}\n";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"void foo ( ) { int n ; n = 10 ; i = 10 >> 1 ; }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
{
|
||||
const char code[] = "void foo()\n"
|
||||
"{\n"
|
||||
" int n = 10;\n"
|
||||
" i = (n << 1);\n"
|
||||
"}\n";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"void foo ( ) { int n ; n = 10 ; i = 10 << 1 ; }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
{
|
||||
const char code[] = "void foo()\n"
|
||||
"{\n"
|
||||
" int n = 10;\n"
|
||||
" i = (1 << n);\n"
|
||||
"}\n";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"void foo ( ) { int n ; n = 10 ; i = 1 << 10 ; }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
{
|
||||
const char code[] = "void foo()\n"
|
||||
"{\n"
|
||||
" int n = 10;\n"
|
||||
" i = (1 >> n);\n"
|
||||
"}\n";
|
||||
|
||||
ASSERT_EQUALS(
|
||||
"void foo ( ) { int n ; n = 10 ; i = 1 >> 10 ; }",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
}
|
||||
|
||||
void simplifyKnownVariables23() {
|
||||
// This testcase is related to ticket #1596
|
||||
const char code[] = "void foo(int x)\n"
|
||||
"{\n"
|
||||
" int a[10], c = 0;\n"
|
||||
" if (x) {\n"
|
||||
" a[c] = 0;\n"
|
||||
" c++;\n"
|
||||
" } else {\n"
|
||||
" a[c] = 0;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
|
||||
TODO_ASSERT_EQUALS(
|
||||
"void foo ( int x ) "
|
||||
"{"
|
||||
" int a [ 10 ] ; int c ; c = 0 ;"
|
||||
" if ( x ) { a [ 0 ] = 0 ; c = 1 ; }"
|
||||
" else { a [ 0 ] = 0 ; } "
|
||||
"}",
|
||||
|
||||
"void foo ( int x ) "
|
||||
"{"
|
||||
" int a [ 10 ] ; int c ; c = 0 ;"
|
||||
" if ( x ) { a [ 0 ] = 0 ; c ++ ; }"
|
||||
" else { a [ c ] = 0 ; } "
|
||||
"}",
|
||||
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables25() {
|
||||
{
|
||||
// This testcase is related to ticket #1646
|
||||
|
@ -3672,43 +3214,6 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void simplifyKnownVariables27() {
|
||||
// This testcase is related to ticket #1633
|
||||
const char code[] = "void foo()\n"
|
||||
"{\n"
|
||||
" int i1 = 1;\n"
|
||||
" int i2 = 2;\n"
|
||||
" int i3 = (i1 + i2) * 3;\n"
|
||||
"}\n";
|
||||
ASSERT_EQUALS(
|
||||
"void foo ( ) "
|
||||
"{"
|
||||
" int i1 ; i1 = 1 ;"
|
||||
" int i2 ; i2 = 2 ;"
|
||||
" int i3 ; i3 = ( 1 + 2 ) * 3 ; "
|
||||
"}",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables28() {
|
||||
const char code[] = "void foo(int g)\n"
|
||||
"{\n"
|
||||
" int i = 2;\n"
|
||||
" if (g) {\n"
|
||||
" }\n"
|
||||
" if (i > 0) {\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ASSERT_EQUALS(
|
||||
"void foo ( int g ) "
|
||||
"{"
|
||||
" int i ; i = 2 ;"
|
||||
" if ( g ) { }"
|
||||
" if ( 2 > 0 ) { } "
|
||||
"}",
|
||||
simplifyKnownVariables(code));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables29() { // ticket #1811
|
||||
{
|
||||
const char code[] = "int foo(int u, int v)\n"
|
||||
|
@ -4049,48 +3554,6 @@ private:
|
|||
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables31() {
|
||||
const char code[] = "void foo(const char str[]) {\n"
|
||||
" const char *p = str;\n"
|
||||
" if (p[0] == 0) {\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
const char expected[] = "void foo ( const char str [ ] ) {\n"
|
||||
"const char * p ; p = str ;\n"
|
||||
"if ( str [ 0 ] == 0 ) {\n"
|
||||
"}\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables32() {
|
||||
{
|
||||
const char code[] = "void foo() {\n"
|
||||
" const int x = 0;\n"
|
||||
" bar(0,x);\n"
|
||||
"}\n";
|
||||
const char expected[] = "void foo ( ) {\n\nbar ( 0 , 0 ) ;\n}";
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "static int const SZ = 22; char str[SZ];\n";
|
||||
ASSERT_EQUALS("char str [ 22 ] ;", tokenizeAndStringify(code,true));
|
||||
}
|
||||
}
|
||||
|
||||
void simplifyKnownVariables33() {
|
||||
const char code[] = "static void foo(struct Foo *foo) {\n"
|
||||
" foo->a = 23;\n"
|
||||
" x[foo->a] = 0;\n"
|
||||
"}\n";
|
||||
const char expected[] = "static void foo ( struct Foo * foo ) {\n"
|
||||
"foo . a = 23 ;\n"
|
||||
"x [ 23 ] = 0 ;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables34() {
|
||||
const char code[] = "void f() {\n"
|
||||
" int x = 10;\n"
|
||||
|
@ -4106,13 +3569,6 @@ private:
|
|||
}
|
||||
|
||||
void simplifyKnownVariables36() {
|
||||
// Ticket #2304
|
||||
const char code[] = "void f() {"
|
||||
" const char *q = \"hello\";"
|
||||
" strcpy(p, q);"
|
||||
"}";
|
||||
const char expected[] = "void f ( ) { const char * q ; q = \"hello\" ; strcpy ( p , \"hello\" ) ; }";
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
|
||||
|
||||
// Ticket #5972
|
||||
const char code2[] = "void f() {"
|
||||
|
@ -4123,50 +3579,7 @@ private:
|
|||
ASSERT_EQUALS(expected2, tokenizeAndStringify(code2, true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables39() {
|
||||
// Ticket #2296 - simplify pointer alias 'delete p;'
|
||||
{
|
||||
const char code[] = "void f() {\n"
|
||||
" int *x;\n"
|
||||
" int *y = x;\n"
|
||||
" delete y;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS("void f ( ) {\nint * x ;\nint * y ; y = x ;\ndelete x ;\n}", tokenizeAndStringify(code, true));
|
||||
}
|
||||
{
|
||||
const char code[] = "void f() {\n"
|
||||
" int *x;\n"
|
||||
" int *y = x;\n"
|
||||
" delete [] y;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS("void f ( ) {\nint * x ;\nint * y ; y = x ;\ndelete [ ] x ;\n}", tokenizeAndStringify(code, true));
|
||||
}
|
||||
}
|
||||
|
||||
void simplifyKnownVariables41() {
|
||||
const char code[] = "void f() {\n"
|
||||
" int x = 0;\n"
|
||||
" const int *p; p = &x;\n"
|
||||
" if (p) { return 0; }\n"
|
||||
"}";
|
||||
ASSERT_EQUALS("void f ( ) {\nint x ; x = 0 ;\nconst int * p ; p = & x ;\nif ( & x ) { return 0 ; }\n}", tokenizeAndStringify(code, true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables42() {
|
||||
{
|
||||
const char code[] = "void f() {\n"
|
||||
" char str1[10], str2[10];\n"
|
||||
" strcpy(str1, \"abc\");\n"
|
||||
" strcpy(str2, str1);\n"
|
||||
"}";
|
||||
const char expected[] = "void f ( ) {\n"
|
||||
"char str1 [ 10 ] ; char str2 [ 10 ] ;\n"
|
||||
"strcpy ( str1 , \"abc\" ) ;\n"
|
||||
"strcpy ( str2 , \"abc\" ) ;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "void f() {\n"
|
||||
" char a[10];\n"
|
||||
|
@ -4261,20 +3674,6 @@ private:
|
|||
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables45() {
|
||||
const char code[] = "class Fred {\n"
|
||||
"private:\n"
|
||||
" const static int NUM = 2;\n"
|
||||
" int array[NUM];\n"
|
||||
"}";
|
||||
const char expected[] = "class Fred {\n"
|
||||
"private:\n"
|
||||
"\n"
|
||||
"int array [ 2 ] ;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables46() {
|
||||
const char code[] = "void f() {\n"
|
||||
" int x = 0;\n"
|
||||
|
@ -4335,45 +3734,6 @@ private:
|
|||
}
|
||||
|
||||
void simplifyKnownVariables50() { // #4066
|
||||
{
|
||||
const char code[] = "void f() {\n"
|
||||
" char str1[10], str2[10];\n"
|
||||
" sprintf(str1, \"%%\");\n"
|
||||
" strcpy(str2, str1);\n"
|
||||
"}";
|
||||
const char expected[] = "void f ( ) {\n"
|
||||
"char str1 [ 10 ] ; char str2 [ 10 ] ;\n"
|
||||
"sprintf ( str1 , \"%%\" ) ;\n"
|
||||
"strcpy ( str2 , \"%\" ) ;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
|
||||
}
|
||||
{
|
||||
const char code[] = "void f() {\n"
|
||||
" char str1[25], str2[25];\n"
|
||||
" sprintf(str1, \"abcdef%%%% and %% and %\");\n"
|
||||
" strcpy(str2, str1);\n"
|
||||
"}";
|
||||
const char expected[] = "void f ( ) {\n"
|
||||
"char str1 [ 25 ] ; char str2 [ 25 ] ;\n"
|
||||
"sprintf ( str1 , \"abcdef%%%% and %% and %\" ) ;\n"
|
||||
"strcpy ( str2 , \"abcdef%% and % and %\" ) ;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
|
||||
}
|
||||
{
|
||||
const char code[] = "void f() {\n"
|
||||
" char str1[10], str2[10];\n"
|
||||
" sprintf(str1, \"abc\");\n"
|
||||
" strcpy(str2, str1);\n"
|
||||
"}";
|
||||
const char expected[] = "void f ( ) {\n"
|
||||
"char str1 [ 10 ] ; char str2 [ 10 ] ;\n"
|
||||
"sprintf ( str1 , \"abc\" ) ;\n"
|
||||
"strcpy ( str2 , \"abc\" ) ;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
|
||||
}
|
||||
{
|
||||
//don't simplify '&x'!
|
||||
const char code[] = "const char * foo ( ) {\n"
|
||||
|
@ -4425,31 +3785,15 @@ private:
|
|||
ASSERT_THROW(tokenizeAndStringify(code, true), InternalError);
|
||||
}
|
||||
|
||||
void simplifyKnownVariables53() { // references
|
||||
ASSERT_EQUALS("void f ( ) { int x ; x = abc ( ) ; }", tokenizeAndStringify("void f() { int x; int &ref=x; ref=abc(); }", true));
|
||||
ASSERT_EQUALS("void f ( ) { int * p ; p = abc ( ) ; }", tokenizeAndStringify("void f() { int *p; int *&ref=p; ref=abc(); }", true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables54() { // #4913
|
||||
ASSERT_EQUALS("void f ( int * p ) { * -- p = 0 ; * p = 0 ; }", tokenizeAndStringify("void f(int*p) { *--p=0; *p=0; }", true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables55() { // pointer alias
|
||||
ASSERT_EQUALS("void f ( ) { int a ; int * p ; if ( a > 0 ) { } }", tokenizeAndStringify("void f() { int a; int *p=&a; if (*p>0) {} }", true));
|
||||
ASSERT_EQUALS("void f ( ) { int a ; struct AB ab ; ab . a = & a ; if ( a > 0 ) { } }", tokenizeAndStringify("void f() { int a; struct AB ab; ab.a = &a; if (*ab.a>0) {} }", true));
|
||||
ASSERT_EQUALS("void f ( ) { int a ; int * p ; if ( x > a ) { } }", tokenizeAndStringify("void f() { int a; int *p=&a; if (x>*p) {} }", true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables56() { // ticket #5301 - >>
|
||||
ASSERT_EQUALS("void f ( ) { int a ; a = 0 ; int b ; b = 0 ; * p >> a >> b ; return a / b ; }",
|
||||
tokenizeAndStringify("void f() { int a=0,b=0; *p>>a>>b; return a/b; }", true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables57() { // #4724
|
||||
ASSERT_EQUALS("unsigned long long x ; x = 9223372036854775808UL ;", tokenizeAndStringify("unsigned long long x = 1UL << 63 ;", true));
|
||||
ASSERT_EQUALS("long long x ; x = -9223372036854775808L ;", tokenizeAndStringify("long long x = 1L << 63 ;", true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables58() { // #5268
|
||||
const char code[] = "enum e { VAL1 = 1, VAL2 }; "
|
||||
"typedef char arr_t[VAL2]; "
|
||||
|
@ -4485,21 +3829,6 @@ private:
|
|||
"}", tokenizeAndStringify(code, true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables60() { // #6829
|
||||
const char code[] = "void f() {\n"
|
||||
" int i = 1;\n"
|
||||
" const int * const constPtrToConst = &i;\n"
|
||||
" std::cout << *constPtrToConst << std::endl;\n"
|
||||
" std::cout << constPtrToConst << std::endl;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS("void f ( ) {\n"
|
||||
"int i ; i = 1 ;\n"
|
||||
"const int * const constPtrToConst ; constPtrToConst = & i ;\n"
|
||||
"std :: cout << i << std :: endl ;\n"
|
||||
"std :: cout << & i << std :: endl ;\n"
|
||||
"}", tokenizeAndStringify(code, true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables61() { // #7805
|
||||
tokenizeAndStringify("static const int XX = 0;\n"
|
||||
"enum E { XX };\n"
|
||||
|
@ -4679,22 +4008,6 @@ private:
|
|||
ASSERT_EQUALS("static int x ; void f ( ) { x = 123 ; while ( ! x ) { dostuff ( ) ; } }", tokenizeAndStringify(code,true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariablesPointerAliasFunctionCall() { // #7440
|
||||
const char code[] = "int main() {\n"
|
||||
" char* data = new char[100];\n"
|
||||
" char** dataPtr = &data;\n"
|
||||
" printf(\"test\");\n"
|
||||
" delete [] *dataPtr;\n"
|
||||
"}";
|
||||
const char exp[] = "int main ( ) {\n"
|
||||
"char * data ; data = new char [ 100 ] ;\n"
|
||||
"char * * dataPtr ; dataPtr = & data ;\n"
|
||||
"printf ( \"test\" ) ;\n"
|
||||
"delete [ ] data ;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(exp, tokenizeAndStringify(code, /*simplify=*/ true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariablesNamespace() {
|
||||
{ // #10059
|
||||
const char code[] = "namespace N {\n"
|
||||
|
@ -4785,25 +4098,6 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void simplify_constants2() {
|
||||
const char code[] =
|
||||
"void f( Foo &foo, Foo *foo2 ) {\n"
|
||||
"const int a = 45;\n"
|
||||
"foo.a=a+a;\n"
|
||||
"foo2->a=a;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS("void f ( Foo & foo , Foo * foo2 ) { foo . a = 90 ; foo2 . a = 45 ; }", tok(code));
|
||||
}
|
||||
|
||||
void simplify_constants4() {
|
||||
const char code[] = "static const int bSize = 4;\n"
|
||||
"static const int aSize = 50;\n"
|
||||
"x = bSize;\n"
|
||||
"y = aSize;\n";
|
||||
ASSERT_EQUALS("x = 4 ; y = 50 ;", tok(code));
|
||||
}
|
||||
|
||||
void simplify_constants6() { // Ticket #5625
|
||||
{
|
||||
const char code[] = "template < class T > struct foo ;\n"
|
||||
|
|
|
@ -854,6 +854,12 @@ private:
|
|||
" return d;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
checkNormal("std::string f() {\n"
|
||||
" std::map<int, std::string> m = { { 1, \"1\" } };\n"
|
||||
" return m.at(1);\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void outOfBoundsSymbolic()
|
||||
|
|
|
@ -490,6 +490,7 @@ private:
|
|||
TEST_CASE(auto14);
|
||||
TEST_CASE(auto15); // C++17 auto deduction from braced-init-list
|
||||
TEST_CASE(auto16);
|
||||
TEST_CASE(auto17); // #11163
|
||||
|
||||
TEST_CASE(unionWithConstructor);
|
||||
|
||||
|
@ -8601,6 +8602,18 @@ private:
|
|||
ASSERT_EQUALS(ValueType::Type::RECORD, i->valueType()->type);
|
||||
}
|
||||
|
||||
void auto17() { // #11163 don't hang
|
||||
GET_SYMBOL_DB("void f() {\n"
|
||||
" std::shared_ptr<int> s1;\n"
|
||||
" auto s2 = std::shared_ptr(s1);\n"
|
||||
"}\n"
|
||||
"void g() {\n"
|
||||
" std::shared_ptr<int> s;\n"
|
||||
" auto w = std::weak_ptr(s);\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS(5, db->variableList().size());
|
||||
}
|
||||
|
||||
void unionWithConstructor() {
|
||||
GET_SYMBOL_DB("union Fred {\n"
|
||||
" Fred(int x) : i(x) { }\n"
|
||||
|
|
|
@ -3525,7 +3525,7 @@ private:
|
|||
" if (!x) i = 0;\n"
|
||||
" if (!x || i>0) {}\n" // <- error
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (error) Uninitialized variable: i\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (warning) Uninitialized variable: i\n", errout.str());
|
||||
|
||||
valueFlowUninit("void f(int x) {\n"
|
||||
" int i;\n"
|
||||
|
@ -3540,7 +3540,7 @@ private:
|
|||
" else i = 0;\n"
|
||||
" if (x || i>0) {}\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:5]: (error) Uninitialized variable: i\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:5]: (warning) Uninitialized variable: i\n", errout.str());
|
||||
|
||||
valueFlowUninit("void f(int x) {\n"
|
||||
" int i;\n"
|
||||
|
@ -3573,7 +3573,7 @@ private:
|
|||
" a = y;\n"
|
||||
" return y ? 2*a : 3*a;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:5]: (error) Uninitialized variable: a\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:5]: (warning) Uninitialized variable: a\n", errout.str());
|
||||
|
||||
valueFlowUninit("void f() {\n" // Don't crash
|
||||
" int a;\n"
|
||||
|
@ -3623,6 +3623,17 @@ private:
|
|||
" if (a[i]) {}\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
valueFlowUninit("void f(void) {\n"
|
||||
" char *c;\n"
|
||||
" char x;\n"
|
||||
" while (true) {\n"
|
||||
" c = &x;\n"
|
||||
" break;\n"
|
||||
" }\n"
|
||||
" ++c;\n"
|
||||
"}", "test.c");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void uninitStructMember() { // struct members
|
||||
|
@ -4675,7 +4686,7 @@ private:
|
|||
" s.x = 42;\n"
|
||||
" bar(&s);\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:18] -> [test.cpp:12] -> [test.cpp:8]: (error) Uninitialized variable: s->flag\n",
|
||||
ASSERT_EQUALS("[test.cpp:18] -> [test.cpp:12] -> [test.cpp:8]: (warning) Uninitialized variable: s->flag\n",
|
||||
errout.str());
|
||||
|
||||
// Ticket #2207 - False negative
|
||||
|
@ -4820,7 +4831,7 @@ private:
|
|||
" p = new S(io);\n"
|
||||
" p->Write();\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:10]: (error) Uninitialized variable: p.rIo\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:10]: (warning) Uninitialized variable: p.rIo\n", errout.str());
|
||||
|
||||
// Unknown types
|
||||
{
|
||||
|
@ -5140,7 +5151,7 @@ private:
|
|||
" }\n"
|
||||
" printf(\"\", value);\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:6] -> [test.cpp:9]: (error) Uninitialized variable: value\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:6] -> [test.cpp:9]: (warning) Uninitialized variable: value\n", errout.str());
|
||||
|
||||
valueFlowUninit("void f(int x)\n"
|
||||
"{\n"
|
||||
|
@ -5242,7 +5253,7 @@ private:
|
|||
" else\n"
|
||||
" return -1;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:6]: (error) Uninitialized variable: a\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:6]: (warning) Uninitialized variable: a\n", errout.str());
|
||||
|
||||
// #9772
|
||||
valueFlowUninit("int func(void) {\n"
|
||||
|
@ -5366,7 +5377,7 @@ private:
|
|||
" increment(n);\n"
|
||||
" return n;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:1]: (error) Uninitialized variable: i\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:1]: (warning) Uninitialized variable: i\n", errout.str());
|
||||
}
|
||||
|
||||
void valueFlowUninitBreak() { // Do not show duplicate warnings about the same uninitialized value
|
||||
|
@ -5418,7 +5429,7 @@ private:
|
|||
" someType_t gVar;\n"
|
||||
" bar(&gVar);\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:9] -> [test.cpp:5]: (error) Uninitialized variable: p->flags\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:9] -> [test.cpp:5]: (warning) Uninitialized variable: p->flags\n", errout.str());
|
||||
|
||||
valueFlowUninit("typedef struct\n"
|
||||
"{\n"
|
||||
|
@ -5619,7 +5630,7 @@ private:
|
|||
" bool copied_all = true;\n"
|
||||
" g(&copied_all, 5, 6, &bytesCopied);\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:2]: (error) Uninitialized variable: *buflen\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:2]: (warning) Uninitialized variable: *buflen\n", errout.str());
|
||||
|
||||
// # 9953
|
||||
valueFlowUninit("uint32_t f(uint8_t *mem) {\n"
|
||||
|
@ -5657,7 +5668,7 @@ private:
|
|||
" ab.a = 0;\n"
|
||||
" do_something(ab);\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:6] -> [test.cpp:2]: (error) Uninitialized variable: ab.b\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:6] -> [test.cpp:2]: (warning) Uninitialized variable: ab.b\n", errout.str());
|
||||
|
||||
valueFlowUninit("struct AB { int a; int b; };\n"
|
||||
"void f(void) {\n"
|
||||
|
@ -6187,8 +6198,17 @@ private:
|
|||
"}\n");
|
||||
TODO_ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:3]: (error) Uninitialized variable: abc->b\n"
|
||||
"[test.cpp:8] -> [test.cpp:3]: (error) Uninitialized variable: abc->c\n",
|
||||
"[test.cpp:8] -> [test.cpp:3]: (error) Uninitialized variable: abc->b\n",
|
||||
"[test.cpp:8] -> [test.cpp:3]: (warning) Uninitialized variable: abc->b\n",
|
||||
errout.str());
|
||||
|
||||
valueFlowUninit("struct S { int* p; };\n" // #10463
|
||||
"void f(S* in) {\n"
|
||||
" S* s;\n"
|
||||
" memcpy(in, s, sizeof(S));\n"
|
||||
" s->p = NULL;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: s\n",
|
||||
errout.str());
|
||||
}
|
||||
|
||||
void uninitvar_memberfunction() {
|
||||
|
|
|
@ -315,6 +315,8 @@ int main(int argc, char **argv)
|
|||
<< " endif # !CPPCHK_GLIBCXX_DEBUG\n"
|
||||
<< " endif # GNU/kFreeBSD\n"
|
||||
<< "\n"
|
||||
<< " LDFLAGS=-pthread\n"
|
||||
<< "\n"
|
||||
<< "endif # WINNT\n"
|
||||
<< "\n";
|
||||
|
||||
|
@ -413,7 +415,7 @@ int main(int argc, char **argv)
|
|||
fout << "cppcheck: $(LIBOBJ) $(CLIOBJ) $(EXTOBJ)\n";
|
||||
fout << "\t$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ $^ $(LIBS) $(LDFLAGS) $(RDYNAMIC)\n\n";
|
||||
fout << "all:\tcppcheck testrunner\n\n";
|
||||
fout << "testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/filelister.o\n";
|
||||
fout << "testrunner: $(TESTOBJ) $(LIBOBJ) $(EXTOBJ) cli/executor.o cli/processexecutor.o cli/threadexecutor.o cli/cmdlineparser.o cli/cppcheckexecutor.o cli/filelister.o\n";
|
||||
fout << "\t$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ $^ $(LIBS) $(LDFLAGS) $(RDYNAMIC)\n\n";
|
||||
fout << "test:\tall\n";
|
||||
fout << "\t./testrunner\n\n";
|
||||
|
|
Loading…
Reference in New Issue