diff --git a/CMakeLists.txt b/CMakeLists.txt index e52750ace..fbc0c9ef7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,16 @@ if (BUILD_TESTS) enable_testing() endif() +add_custom_target(copy_cfg ALL + ${CMAKE_COMMAND} -E copy_directory "${PROJECT_SOURCE_DIR}/cfg" + "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/cfg" + COMMENT "Copying cfg files to ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}") + +add_custom_target(copy_addons ALL + ${CMAKE_COMMAND} -E copy_directory "${PROJECT_SOURCE_DIR}/addons" + "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/addons" + COMMENT "Copying addons files to ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}") + if(USE_BUNDLED_TINYXML2) message(STATUS "Using bundled version of tinyxml2") add_subdirectory(externals/tinyxml2) diff --git a/addons/cppcheck.py b/addons/cppcheck.py new file mode 100644 index 000000000..23a69ba1d --- /dev/null +++ b/addons/cppcheck.py @@ -0,0 +1,39 @@ + +import cppcheckdata, sys, os + +__checkers__ = [] + +def checker(f): + __checkers__.append(f) + return f + + +__errorid__ = '' +__addon_name__ = '' +def reportError(location, severity, message, errorId=None): + cppcheckdata.reportError(location, severity, message, __addon_name__, errorId or __errorid__) + +def runcheckers(): + # If there are no checkers then dont run + if len(__checkers__) == 0: + return + global __addon_name__ + global __errorid__ + addon = sys.argv[0] + parser = cppcheckdata.ArgumentParser() + args = parser.parse_args() + + __addon_name__ = os.path.splitext(os.path.basename(addon))[0] + + for dumpfile in args.dumpfile: + if not args.quiet: + print('Checking %s...' % dumpfile) + + data = cppcheckdata.CppcheckData(dumpfile) + + for cfg in data.iterconfigurations(): + if not args.quiet: + print('Checking %s, config %s...' % (dumpfile, cfg.name)) + for c in __checkers__: + __errorid__ = c.__name__ + c(cfg, data) diff --git a/addons/findcasts.py b/addons/findcasts.py index 5f7943d57..41fbf2d9b 100755 --- a/addons/findcasts.py +++ b/addons/findcasts.py @@ -3,40 +3,31 @@ # Locate casts in the code # -import cppcheckdata +import cppcheck import sys -for arg in sys.argv[1:]: - if arg.startswith('-'): - continue +@cppcheck.checker +def cast(cfg, data): + for token in cfg.tokenlist: + if token.str != '(' or not token.astOperand1 or token.astOperand2: + continue - print('Checking %s...' % arg) - data = cppcheckdata.CppcheckData(arg) + # Is it a lambda? + if token.astOperand1.str == '{': + continue - for cfg in data.iterconfigurations(): - print('Checking %s, config %s...' % (arg, cfg.name)) - for token in cfg.tokenlist: - if token.str != '(' or not token.astOperand1 or token.astOperand2: - continue + # we probably have a cast.. if there is something inside the parentheses + # there is a cast. Otherwise this is a function call. + typetok = token.next + if not typetok.isName: + continue - # Is it a lambda? - if token.astOperand1.str == '{': - continue + # cast number => skip output + if token.astOperand1.isNumber: + continue - # we probably have a cast.. if there is something inside the parentheses - # there is a cast. Otherwise this is a function call. - typetok = token.next - if not typetok.isName: - continue + # void cast => often used to suppress compiler warnings + if typetok.str == 'void': + continue - # cast number => skip output - if token.astOperand1.isNumber: - continue - - # void cast => often used to suppress compiler warnings - if typetok.str == 'void': - continue - - cppcheckdata.reportError(token, 'information', 'found a cast', 'findcasts', 'cast') - -sys.exit(cppcheckdata.EXIT_CODE) + cppcheck.reportError(token, 'information', 'found a cast') diff --git a/addons/runaddon.py b/addons/runaddon.py new file mode 100644 index 000000000..536abe864 --- /dev/null +++ b/addons/runaddon.py @@ -0,0 +1,12 @@ +import cppcheckdata, cppcheck, runpy, sys, os + +if __name__ == '__main__': + addon = sys.argv[1] + __addon_name__ = os.path.splitext(os.path.basename(addon))[0] + sys.argv.pop(0) + + runpy.run_path(addon, run_name='__main__') + + # Run registered checkers + cppcheck.runcheckers() + sys.exit(cppcheckdata.EXIT_CODE) \ No newline at end of file diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 49b44316c..ccec962e0 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -34,6 +34,9 @@ if(tinyxml2_FOUND AND NOT USE_BUNDLED_TINYXML2) target_link_libraries(cppcheck tinyxml2) endif() +add_dependencies(cppcheck copy_cfg) +add_dependencies(cppcheck copy_addons) + install(TARGETS cppcheck RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} COMPONENT applications) diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 2e8b8e543..1f8dd3e92 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -34,6 +34,7 @@ #include "version.h" #include "exprengine.h" +#include #define PICOJSON_USE_INT64 #include @@ -71,6 +72,7 @@ namespace { std::string args; std::string python; bool ctu = false; + std::string runScript{}; static std::string getFullPath(const std::string &fileName, const std::string &exename) { if (Path::fileExists(fileName)) @@ -153,6 +155,8 @@ namespace { pos2 = std::string::npos; name = scriptFile.substr(pos1, pos2 - pos1); + runScript = getFullPath("runaddon.py", exename); + return ""; } @@ -291,7 +295,8 @@ static std::string executeAddon(const AddonInfo &addonInfo, } const std::string fileArg = (endsWith(file, FILELIST, sizeof(FILELIST)-1) ? " --file-list " : " ") + cmdFileName(file); - const std::string args = cmdFileName(addonInfo.scriptFile) + " --cli" + addonInfo.args + fileArg; + const std::string args = + cmdFileName(addonInfo.runScript) + " " + cmdFileName(addonInfo.scriptFile) + " --cli" + addonInfo.args + fileArg; std::string result; if (!executeCommand(pythonExe, split(args), redirect, &result)) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3d9724588..7e4d73a53 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -34,11 +34,8 @@ if (BUILD_TESTS) target_precompile_headers(testrunner PRIVATE precompiled.h) endif() - add_custom_target(copy_cfg ALL - ${CMAKE_COMMAND} -E copy_directory "${PROJECT_SOURCE_DIR}/cfg" - "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/cfg" - COMMENT "Copying cfg files to ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}") add_dependencies(testrunner copy_cfg) + add_dependencies(testrunner copy_addons) if (LIBXML2_XMLLINT_EXECUTABLE) # TODO: get rid of the copy