Compare commits

...

18 Commits

Author SHA1 Message Date
Daniel Marjamäki 392741715b Import Project: Fix problem with define value with space 2022-04-15 20:23:30 +02:00
Daniel Marjamäki ef8a499c8d GUI: allow that misra addon is executed without rule texts file 2022-04-15 20:23:04 +02:00
Wolfgang Stöggl 1cc234ac2c
Set tinyxml2_LIBRARIES after find_package() (#3932)
If tinyxml2 is found by find_package(), then tinyxml2_LIBRARIES
is empty. Set tinyxml2_LIBRARIES to "tinyxml2::tinyxml2" in this case.

- Fixes "undefined reference to `tinyxml2::"
- printInfo.cmake: Fix indentation of tinyxml2_LIBRARIES
2022-03-25 06:58:59 +01:00
Daniel Marjamäki 9ef14d179d exename: Set proper exename when cppcheck is executed from PATH and argv[0] does not contain path information 2022-03-25 06:27:42 +01:00
Daniel Marjamäki 41872f9a6d 2.7.4: Set version 2022-03-24 23:05:05 +01:00
Daniel Marjamäki 635059603a cppcheck.cfg: support custom productname and about message 2022-03-24 23:01:20 +01:00
Daniel Marjamäki 4c650289ad compile_commands.json: ensure that order of include paths are kept 2022-03-24 22:59:18 +01:00
Daniel Marjamäki 760436c56e Fixed #10887 (compile database: include path with space is not handled) 2022-03-24 22:59:00 +01:00
Daniel Marjamäki 355866f0cf Import project: do not crash when importing compile database generated by IAR workbench 2022-03-24 22:58:45 +01:00
Daniel Marjamäki 97bf53515b 2.7.3: Set version 2022-03-19 12:35:06 +01:00
Daniel Marjamäki a06898dc8e cppcheckdata.py: code cleanup 2022-03-19 12:30:53 +01:00
Daniel Marjamäki a045149181 Addons: Variable.constness will never be None 2022-03-19 12:30:35 +01:00
Daniel Marjamäki 54d079387e cli: in linux set proper exename value when cppcheck is executed from PATH and argv[0] does not have path information 2022-03-19 12:30:22 +01:00
Georgi D. Sotirov 199fe343c3 Replace tinyxml2_LIBRARY with tinyxml2_LIBRARIES (#3897) 2022-03-19 08:35:59 +01:00
Oliver Stöneberg d922a3b0bc only use bundled tinyxml2 in CMake when configured to do so (#3806) 2022-03-19 08:35:13 +01:00
Daniel Marjamäki f0150069c8 ImportProject: Fix loading of sln without BOM 2022-03-12 13:03:04 +01:00
Daniel Marjamäki 6ef6b02153 ValueFlow: Fix crash 2022-03-10 20:16:12 +01:00
Daniel Marjamäki c5b3fafe84 update scripts 2022-03-10 20:13:11 +01:00
29 changed files with 375 additions and 180 deletions

View File

@ -27,7 +27,7 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install libxml2-utils
sudo apt-get install z3 libz3-dev
sudo apt-get install libz3-dev libtinyxml2-dev
sudo apt-get install qtbase5-dev qttools5-dev libqt5charts5-dev qt5-default
- name: Fix missing z3_version.h
@ -45,6 +45,20 @@ jobs:
python -m pip install pip --upgrade
python -m pip install pytest
- name: CMake build on ubuntu (with GUI / system tinyxml2)
if: contains(matrix.os, 'ubuntu')
run: |
mkdir cmake.output.tinyxml2
cd cmake.output.tinyxml2
cmake -G "Unix Makefiles" -DUSE_Z3=On -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DUSE_BUNDLED_TINYXML2=Off ..
cmake --build . -- -j$(nproc)
cd ..
- name: Run CMake test (system tinyxml2)
if: contains(matrix.os, 'ubuntu')
run: |
cmake --build cmake.output.tinyxml2 --target check -- -j$(nproc)
- name: CMake build on ubuntu (with GUI)
if: contains(matrix.os, 'ubuntu')
run: |

View File

@ -13,6 +13,7 @@ import argparse
import cppcheckdata
import sys
import re
import subprocess
VERIFY = ('-verify' in sys.argv)
VERIFY_EXPECTED = []
@ -195,7 +196,9 @@ def int31(data, platform):
if to_value_type is None or not from_values:
continue
bits = None
if to_value_type.type == 'char':
if token.valueType.pointer > 0:
bits = platform.pointer_bit
elif to_value_type.type == 'char':
bits = platform.char_bit
elif to_value_type.type == 'short':
bits = platform.short_bit
@ -399,6 +402,8 @@ if __name__ == '__main__':
parser = get_args_parser()
args = parser.parse_args()
path_premium_addon = cppcheckdata.get_path_premium_addon()
if args.verify:
VERIFY = True
@ -411,6 +416,14 @@ if __name__ == '__main__':
if not args.quiet:
print('Checking %s...' % dumpfile)
if path_premium_addon:
premium_command = [path_premium_addon, '--cert', dumpfile]
if args.cli:
premium_command.append('--cli')
for line in subprocess.check_output(premium_command).decode('ascii').split('\n'):
if line.find('cert-') > 0:
print(line.strip())
data = cppcheckdata.CppcheckData(dumpfile)
if VERIFY:

View File

@ -8,6 +8,8 @@ License: No restrictions, use this as you need.
import argparse
import json
import os
import pathlib
import sys
from xml.etree import ElementTree
@ -141,21 +143,11 @@ class ValueType:
def __init__(self, element):
self.type = element.get('valueType-type')
self.sign = element.get('valueType-sign')
bits = element.get('valueType-bits')
if bits:
self.bits = int(bits)
self.bits = int(element.get('valueType-bits', 0))
self.typeScopeId = element.get('valueType-typeScope')
self.originalTypeName = element.get('valueType-originalTypeName')
constness = element.get('valueType-constness')
if constness:
self.constness = int(constness)
else:
self.constness = 0
pointer = element.get('valueType-pointer')
if pointer:
self.pointer = int(pointer)
else:
self.pointer = 0
self.constness = int(element.get('valueType-constness', 0))
self.pointer = int(element.get('valueType-pointer', 0))
def __repr__(self):
attrs = ["type", "sign", "bits", "typeScopeId", "originalTypeName",
@ -618,9 +610,7 @@ class Variable:
self.isPointer = element.get('isPointer') == 'true'
self.isReference = element.get('isReference') == 'true'
self.isStatic = element.get('isStatic') == 'true'
self.constness = element.get('constness')
if self.constness:
self.constness = int(self.constness)
self.constness = int(element.get('constness',0))
def __repr__(self):
attrs = ["Id", "nameTokenId", "typeStartTokenId", "typeEndTokenId",
@ -1364,3 +1354,14 @@ def reportSummary(dumpfile, summary_type, summary_data):
with open(ctu_info_file, 'at') as f:
msg = {'summary': summary_type, 'data': summary_data}
f.write(json.dumps(msg) + '\n')
def get_path_premium_addon():
p = pathlib.Path(sys.argv[0]).parent.parent
for ext in ('.exe', ''):
p1 = os.path.join(p, 'premiumaddon' + ext)
p2 = os.path.join(p, 'cppcheck' + ext)
if os.path.isfile(p1) and os.path.isfile(p2):
return p1
return None

View File

@ -25,6 +25,7 @@ import argparse
import codecs
import string
import copy
import subprocess
try:
from itertools import izip as zip
@ -422,6 +423,28 @@ def get_type_conversion_to_from(token):
return None
def is_composite_expr(expr, composite_operator=False):
"""MISRA C 2012, section 8.10.3"""
if expr is None:
return False
if not composite_operator:
if (expr.str in ('+', '-', '*', '/', '%', '&', '|', '^', '>>', "<<", "?", ":", '~')):
return is_composite_expr(expr.astOperand1,True) or is_composite_expr(expr.astOperand2, True)
if expr.str == '?' and simpleMatch(expr.astOperand2, ':'):
colon = expr.astOperand2
return is_composite_expr(colon.astOperand1,True) or is_composite_expr(colon.astOperand2, True)
return False
# non constant expression?
if expr.isNumber:
return False
if expr.astOperand1 or expr.astOperand2:
return is_composite_expr(expr.astOperand1,True) or is_composite_expr(expr.astOperand2, True)
return True
def getEssentialTypeCategory(expr):
if not expr:
return None
@ -1009,16 +1032,14 @@ def isNoReturnScope(tok):
# Return the token which the value is assigned to
def getAssignedVariableToken(valueToken):
if not valueToken:
def getAssignedVariableToken(vartok):
if not vartok:
return None
if not valueToken.astParent:
return None
operator = valueToken.astParent
if operator.isAssignmentOp:
return operator.astOperand1
if operator.isArithmeticalOp:
return getAssignedVariableToken(operator)
parent = vartok.astParent
while parent and parent.isArithmeticalOp:
parent = parent.astParent
if parent and parent.isAssignmentOp:
return parent.astOperand1
return None
# If the value is used as a return value, return the function definition
@ -1297,6 +1318,8 @@ class MisraChecker:
self._ctu_summary_identifiers = False
self._ctu_summary_usage = False
self.path_premium_addon = None
def __repr__(self):
attrs = ["settings", "verify_expected", "verify_actual", "violations",
"ruleTexts", "suppressedRules", "filePrefix",
@ -1372,7 +1395,9 @@ class MisraChecker:
local_identifiers.append(identifier(var.nameToken))
elif var.isStatic:
names.append(var.nameToken.str)
internal_identifiers.append(identifier(var.nameToken))
i = identifier(var.nameToken)
i['inlinefunc'] = False
internal_identifiers.append(i)
else:
names.append(var.nameToken.str)
i = identifier(var.nameToken)
@ -1383,9 +1408,14 @@ class MisraChecker:
if func.tokenDef is None:
continue
if func.isStatic:
internal_identifiers.append(identifier(func.tokenDef))
else:
i = identifier(func.tokenDef)
i['inlinefunc'] = func.isInlineKeyword
internal_identifiers.append(i)
else:
if func.token is None:
i = identifier(func.tokenDef)
else:
i = identifier(func.token)
i['decl'] = func.token is None
external_identifiers.append(i)
@ -1404,12 +1434,12 @@ class MisraChecker:
continue
if token.function and token.scope.isExecutable:
if (not token.function.isStatic) and (token.str not in names):
names.append(token.str)
names.append({'name': token.str, 'file': token.file})
elif token.variable:
if token == token.variable.nameToken:
continue
if token.variable.access == 'Global' and (not token.variable.isStatic) and (token.str not in names):
names.append(token.str)
names.append({'name': token.str, 'file': token.file})
if len(names) > 0:
cppcheckdata.reportSummary(dumpfile, 'MisraUsage', names)
@ -1759,41 +1789,9 @@ class MisraChecker:
self.reportError(tok, 7, 1)
def misra_7_2(self, data):
# Large constant numbers that are assigned to a variable should have an
# u/U suffix if the variable type is unsigned.
def reportErrorIfMissingSuffix(variable, value):
if 'U' in value.str.upper():
return
if value and value.isNumber:
if variable and variable.valueType and variable.valueType.sign == 'unsigned':
if variable.valueType.type in ['char', 'short', 'int', 'long', 'long long']:
limit = 1 << (bitsOfEssentialType(variable.valueType.type) -1)
v = value.getKnownIntValue()
if v is not None and v >= limit:
self.reportError(value, 7, 2)
for token in data.tokenlist:
# Check normal variable assignment
if token.valueType and token.isNumber:
variable = getAssignedVariableToken(token)
reportErrorIfMissingSuffix(variable, token)
# Check use as function parameter
if isFunctionCall(token) and token.astOperand1 and token.astOperand1.function:
functionDeclaration = token.astOperand1.function
if functionDeclaration.tokenDef:
if functionDeclaration.tokenDef is token.astOperand1:
# Token is not a function call, but it is the definition of the function
continue
parametersUsed = getArguments(token)
for i in range(len(parametersUsed)):
usedParameter = parametersUsed[i]
if usedParameter.isNumber:
parameterDefinition = functionDeclaration.argument.get(i+1)
if parameterDefinition and parameterDefinition.nameToken:
reportErrorIfMissingSuffix(parameterDefinition.nameToken, usedParameter)
if token.isInt and ('U' not in token.str.upper()) and token.valueType and token.valueType.sign == 'unsigned':
self.reportError(token, 7, 2)
def misra_7_3(self, rawTokens):
compiled = re.compile(r'^[0-9.]+[Uu]*l+[Uu]*$')
@ -2277,8 +2275,7 @@ class MisraChecker:
for token in data.tokenlist:
if token.str != '=' or not token.astOperand1 or not token.astOperand2:
continue
if (token.astOperand2.str not in ('+', '-', '*', '/', '%', '&', '|', '^', '>>', "<<", "?", ":", '~') and
not isCast(token.astOperand2)):
if not is_composite_expr(token.astOperand2):
continue
vt1 = token.astOperand1.valueType
vt2 = token.astOperand2.valueType
@ -4058,7 +4055,10 @@ class MisraChecker:
misra_severity = self.ruleTexts[ruleNum].misra_severity
cppcheck_severity = self.ruleTexts[ruleNum].cppcheck_severity
elif len(self.ruleTexts) == 0:
errmsg = 'misra violation (use --rule-texts=<file> to get proper output)'
if self.path_premium_addon:
errmsg = subprocess.check_output([self.path_premium_addon, '--get-rule-text=' + errorId]).strip().decode('ascii')
else:
errmsg = 'misra violation (use --rule-texts=<file> to get proper output)'
else:
errmsg = 'misra violation %s with no text in the supplied rule-texts-file' % (ruleNum)
@ -4392,6 +4392,10 @@ class MisraChecker:
self.executeCheck(2209, self.misra_22_9, cfg)
self.executeCheck(2210, self.misra_22_10, cfg)
# Premium MISRA checking, deep analysis
if cfgNumber == 0 and self.path_premium_addon:
subprocess.call([self.path_premium_addon, '--misra', dumpfile])
def analyse_ctu_info(self, ctu_info_files):
all_typedef_info = []
all_tagname_info = []
@ -4400,7 +4404,7 @@ class MisraChecker:
all_external_identifiers_def = {}
all_internal_identifiers = {}
all_local_identifiers = {}
all_usage_count = {}
all_usage_files = {}
from cppcheckdata import Location
@ -4478,8 +4482,9 @@ class MisraChecker:
if summary_type == 'MisraInternalIdentifiers':
for s in summary_data:
if s['name'] in all_internal_identifiers:
self.reportError(Location(s), 5, 9)
self.reportError(Location(all_internal_identifiers[s['name']]), 5, 9)
if not s['inlinefunc'] or s['file'] != all_internal_identifiers[s['name']]['file']:
self.reportError(Location(s), 5, 9)
self.reportError(Location(all_internal_identifiers[s['name']]), 5, 9)
all_internal_identifiers[s['name']] = s
if summary_type == 'MisraLocalIdentifiers':
@ -4488,10 +4493,10 @@ class MisraChecker:
if summary_type == 'MisraUsage':
for s in summary_data:
if s in all_usage_count:
all_usage_count[s] += 1
if s['name'] in all_usage_files:
all_usage_files[s['name']].append(s['file'])
else:
all_usage_count[s] = 1
all_usage_files[s['name']] = [s['file']]
for ti in all_typedef_info:
if not ti['used']:
@ -4518,9 +4523,12 @@ class MisraChecker:
self.reportError(Location(local_identifier), 5, 8)
self.reportError(Location(external_identifier), 5, 8)
for name, count in all_usage_count.items():
for name, files in all_usage_files.items():
#print('%s:%i' % (name, count))
if count != 1:
count = len(files)
if count != 1 or name not in all_external_identifiers_def:
continue
if files[0] != Location(all_external_identifiers_def[name]).file:
continue
if name in all_external_identifiers:
self.reportError(Location(all_external_identifiers[name]), 8, 7)
@ -4584,6 +4592,8 @@ def main():
settings = MisraSettings(args)
checker = MisraChecker(settings)
checker.path_premium_addon = cppcheckdata.get_path_premium_addon()
if args.generate_table:
generateTable()
sys.exit(0)
@ -4645,6 +4655,13 @@ def main():
checker.analyse_ctu_info(ctu_info_files)
if args.file_list and checker.path_premium_addon:
premium_command = [checker.path_premium_addon, '--misra', '--file-list', args.file_list]
if args.cli:
premium_command.append('--cli')
for line in subprocess.check_output(premium_command).decode('ascii').split('\n'):
print(line.strip())
if settings.verify:
sys.exit(exitCode)

View File

@ -35,7 +35,7 @@ if (WIN32 AND NOT BORLAND)
endif()
endif()
if(tinyxml2_FOUND AND NOT USE_BUNDLED_TINYXML2)
target_link_libraries(cppcheck tinyxml2)
target_link_libraries(cppcheck ${tinyxml2_LIBRARIES})
endif()
add_dependencies(cppcheck copy_cfg)

View File

@ -46,6 +46,10 @@
#include <tinyxml2.h>
#endif
#ifdef __linux__
#include <unistd.h>
#endif
static void addFilesToList(const std::string& fileList, std::vector<std::string>& pathNames)
{
// To keep things initially simple, if the file can't be opened, just be silent and move on.
@ -122,6 +126,14 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
bool maxconfigs = false;
mSettings->exename = argv[0];
#ifdef __linux__
// Executing cppcheck in PATH. argv[0] does not contain the path.
if (mSettings->exename.find_first_of("/\\") == std::string::npos) {
char buf[PATH_MAX] = {0};
if (FileLister::fileExists("/proc/self/exe") && readlink("/proc/self/exe", buf, sizeof(buf)-1) > 0)
mSettings->exename = buf;
}
#endif
for (int i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
@ -882,6 +894,7 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
else if (std::strcmp(argv[i], "--version") == 0) {
mShowVersion = true;
mExitAfterPrint = true;
mSettings->loadCppcheckCfg();
return true;
}
@ -923,7 +936,7 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
}
}
mSettings->loadCppcheckCfg(argv[0]);
mSettings->loadCppcheckCfg();
// Default template format..
if (mSettings->templateFormat.empty()) {

View File

@ -109,12 +109,16 @@ bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* c
if (success) {
if (parser.getShowVersion() && !parser.getShowErrorMessages()) {
const char * const extraVersion = CppCheck::extraVersion();
if (*extraVersion != 0)
std::cout << "Cppcheck " << CppCheck::version() << " ("
<< extraVersion << ')' << std::endl;
else
std::cout << "Cppcheck " << CppCheck::version() << std::endl;
if (!settings.cppcheckCfgProductName.empty()) {
std::cout << settings.cppcheckCfgProductName << std::endl;
} else {
const char * const extraVersion = CppCheck::extraVersion();
if (*extraVersion != 0)
std::cout << "Cppcheck " << CppCheck::version() << " ("
<< extraVersion << ')' << std::endl;
else
std::cout << "Cppcheck " << CppCheck::version() << std::endl;
}
}
if (parser.getShowErrorMessages()) {
@ -243,9 +247,9 @@ int CppCheckExecutor::check(int argc, const char* const argv[])
int ret;
if (cppCheck.settings().exceptionHandling)
ret = check_wrapper(cppCheck, argc, argv);
ret = check_wrapper(cppCheck);
else
ret = check_internal(cppCheck, argc, argv);
ret = check_internal(cppCheck);
mSettings = nullptr;
return ret;
@ -821,12 +825,12 @@ namespace {
* TODO Check for multi-threading issues!
*
*/
int CppCheckExecutor::check_wrapper(CppCheck& cppcheck, int argc, const char* const argv[])
int CppCheckExecutor::check_wrapper(CppCheck& cppcheck)
{
#ifdef USE_WINDOWS_SEH
FILE *outputFile = stdout;
__try {
return check_internal(cppcheck, argc, argv);
return check_internal(cppcheck);
} __except (filterException(GetExceptionCode(), GetExceptionInformation())) {
// reporting to stdout may not be helpful within a GUI application...
fputs("Please report this to the cppcheck developers!\n", outputFile);
@ -854,23 +858,23 @@ int CppCheckExecutor::check_wrapper(CppCheck& cppcheck, int argc, const char* co
for (std::map<int, std::string>::const_iterator sig=listofsignals.begin(); sig!=listofsignals.end(); ++sig) {
sigaction(sig->first, &act, nullptr);
}
return check_internal(cppcheck, argc, argv);
return check_internal(cppcheck);
#else
return check_internal(cppcheck, argc, argv);
return check_internal(cppcheck);
#endif
}
/*
* That is a method which gets called from check_wrapper
* */
int CppCheckExecutor::check_internal(CppCheck& cppcheck, int /*argc*/, const char* const argv[])
int CppCheckExecutor::check_internal(CppCheck& cppcheck)
{
Settings& settings = cppcheck.settings();
mSettings = &settings;
const bool std = tryLoadLibrary(settings.library, argv[0], "std.cfg");
const bool std = tryLoadLibrary(settings.library, settings.exename, "std.cfg");
for (const std::string &lib : settings.libraries) {
if (!tryLoadLibrary(settings.library, argv[0], lib.c_str())) {
if (!tryLoadLibrary(settings.library, settings.exename, lib.c_str())) {
const std::string msg("Failed to load the library " + lib);
const std::list<ErrorMessage::FileLocation> callstack;
ErrorMessage errmsg(callstack, emptyString, Severity::information, msg, "failedToLoadCfg", Certainty::normal);
@ -879,22 +883,15 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck, int /*argc*/, const cha
}
}
bool posix = true;
if (settings.posix())
posix = tryLoadLibrary(settings.library, argv[0], "posix.cfg");
bool windows = true;
if (settings.isWindowsPlatform())
windows = tryLoadLibrary(settings.library, argv[0], "windows.cfg");
if (!std || !posix || !windows) {
if (!std) {
const std::list<ErrorMessage::FileLocation> callstack;
const std::string msg("Failed to load " + std::string(!std ? "std.cfg" : !posix ? "posix.cfg" : "windows.cfg") + ". Your Cppcheck installation is broken, please re-install.");
const std::string msg("Failed to load std.cfg. Your Cppcheck installation is broken, please re-install.");
#ifdef FILESDIR
const std::string details("The Cppcheck binary was compiled with FILESDIR set to \""
FILESDIR "\" and will therefore search for "
"std.cfg in " FILESDIR "/cfg.");
#else
const std::string cfgfolder(Path::fromNativeSeparators(Path::getPathFromFilename(argv[0])) + "cfg");
const std::string cfgfolder(Path::fromNativeSeparators(Path::getPathFromFilename(settings.exename)) + "cfg");
const std::string details("The Cppcheck binary was compiled without FILESDIR set. Either the "
"std.cfg should be available in " + cfgfolder + " or the FILESDIR "
"should be configured.");
@ -1143,9 +1140,9 @@ FILE* CppCheckExecutor::getExceptionOutput()
return mExceptionOutput;
}
bool CppCheckExecutor::tryLoadLibrary(Library& destination, const char* basepath, const char* filename)
bool CppCheckExecutor::tryLoadLibrary(Library& destination, const std::string& basepath, const char* filename)
{
const Library::Error err = destination.load(basepath, filename);
const Library::Error err = destination.load(basepath.c_str(), filename);
if (err.errorcode == Library::ErrorCode::UNKNOWN_ELEMENT)
std::cout << "cppcheck: Found unknown elements in configuration file '" << filename << "': " << err.reason << std::endl;

View File

@ -112,7 +112,7 @@ public:
* Tries to load a library and prints warning/error messages
* @return false, if an error occurred (except unknown XML elements)
*/
static bool tryLoadLibrary(Library& destination, const char* basepath, const char* filename);
static bool tryLoadLibrary(Library& destination, const std::string& basepath, const char* filename);
/**
* Execute a shell command and read the output from it. Returns true if command terminated successfully.
@ -151,24 +151,20 @@ private:
* - installs optional platform dependent signal handling
*
* @param cppcheck cppcheck instance
* @param argc from main()
* @param argv from main()
**/
int check_wrapper(CppCheck& cppcheck, int argc, const char* const argv[]);
int check_wrapper(CppCheck& cppcheck);
/**
* Starts the checking.
*
* @param cppcheck cppcheck instance
* @param argc from main()
* @param argv from main()
* @return EXIT_FAILURE if arguments are invalid or no input files
* were found.
* If errors are found and --error-exitcode is used,
* given value is returned instead of default 0.
* If no errors are found, 0 is returned.
*/
int check_internal(CppCheck& cppcheck, int argc, const char* const argv[]);
int check_internal(CppCheck& cppcheck);
/**
* Pointer to current settings; set while check() is running.

View File

@ -11,11 +11,11 @@ find_program(RUN_CLANG_TIDY NAMES run-clang-tidy run-clang-tidy-13 run-clang-tid
message(STATUS "RUN_CLANG_TIDY=${RUN_CLANG_TIDY}")
if (RUN_CLANG_TIDY)
# disable all compiler warnings since we are just interested in the tidy ones
add_custom_target(run-clang-tidy ${RUN_CLANG_TIDY} -p=${CMAKE_BINARY_DIR} -j ${NPROC} -extra-arg=-w -quiet)
add_custom_target(run-clang-tidy ${RUN_CLANG_TIDY} -checks=-performance-unnecessary-copy-initialization -p=${CMAKE_BINARY_DIR} -j ${NPROC} -extra-arg=-w -quiet)
if (BUILD_GUI)
add_dependencies(run-clang-tidy gui-build-deps)
if (BUILD_TESTS)
add_dependencies(run-clang-tidy triage-build-ui-deps)
endif()
endif()
endif()
endif()

View File

@ -48,12 +48,13 @@ endif()
if (NOT USE_BUNDLED_TINYXML2)
find_package(tinyxml2 QUIET)
if (NOT tinyxml2_FOUND)
find_library(tinyxml2_LIBRARY tinyxml2)
if (NOT tinyxml2_LIBRARY)
if (TARGET tinyxml2::tinyxml2)
set(tinyxml2_LIBRARIES "tinyxml2::tinyxml2")
else()
find_library(tinyxml2_LIBRARIES tinyxml2)
if (NOT tinyxml2_LIBRARIES)
message(FATAL_ERROR "tinyxml2 has not been found")
else()
message(STATUS "tinyxml2_LIBRARY: ${tinyxml2_LIBRARY}")
set(tinyxml2_FOUND 1)
endif()
endif()

View File

@ -52,7 +52,11 @@ if (USE_Z3)
message( STATUS "Z3_LIBRARIES = ${Z3_LIBRARIES}" )
message( STATUS "Z3_CXX_INCLUDE_DIRS = ${Z3_CXX_INCLUDE_DIRS}" )
endif()
message( STATUS )
message( STATUS "USE_BUNDLED_TINYXML2 = ${USE_BUNDLED_TINYXML2}" )
if (NOT USE_BUNDLED_TINYXML2)
message(STATUS "tinyxml2_LIBRARIES = ${tinyxml2_LIBRARIES}")
endif()
message( STATUS )
if(${ANALYZE_ADDRESS})

View File

@ -1,5 +1,5 @@
# Version for libraries CPP
SET(VERSION "2.7")
SET(VERSION "2.7.4")
STRING(REGEX MATCHALL "[0-9]" VERSION_PARTS "${VERSION}")
LIST(GET VERSION_PARTS 0 VERSION_MAJOR)
LIST(GET VERSION_PARTS 1 VERSION_MINOR)

View File

@ -36,7 +36,7 @@ if (BUILD_GUI)
target_link_libraries(cppcheck-gui ${Z3_LIBRARIES})
endif()
if(tinyxml2_FOUND AND NOT USE_BUNDLED_TINYXML2)
target_link_libraries(cppcheck-gui tinyxml2)
target_link_libraries(cppcheck-gui ${tinyxml2_LIBRARIES})
endif()
target_link_libraries(cppcheck-gui Qt5::Core Qt5::Gui Qt5::Widgets Qt5::PrintSupport Qt5::Help)
if(WITH_QCHART)

View File

@ -67,6 +67,13 @@ MainWindow::MainWindow(TranslationHandler* th, QSettings* settings) :
mExiting(false),
mIsLogfileLoaded(false)
{
{
Settings tempSettings;
tempSettings.loadCppcheckCfg();
mCppcheckCfgProductName = QString::fromStdString(tempSettings.cppcheckCfgProductName);
mCppcheckCfgAbout = QString::fromStdString(tempSettings.cppcheckCfgAbout);
}
mUI.setupUi(this);
mThread = new ThreadHandler(this);
mThread->setDataDir(getDataDir());
@ -507,8 +514,6 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrar
checkSettings.checkLibrary = checkLibrary;
checkSettings.checkConfiguration = checkConfiguration;
checkSettings.loadCppcheckCfg(QCoreApplication::applicationFilePath().toStdString());
if (mProjectFile)
qDebug() << "Checking project file" << mProjectFile->getFilename();
@ -854,15 +859,10 @@ Settings MainWindow::getCppcheckSettings()
result.exename = QCoreApplication::applicationFilePath().toStdString();
const bool std = tryLoadLibrary(&result.library, "std.cfg");
bool posix = true;
if (result.posix())
posix = tryLoadLibrary(&result.library, "posix.cfg");
bool windows = true;
if (result.isWindowsPlatform())
windows = tryLoadLibrary(&result.library, "windows.cfg");
if (!std)
QMessageBox::critical(this, tr("Error"), tr("Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured.").arg("std.cfg"));
if (!std || !posix || !windows)
QMessageBox::critical(this, tr("Error"), tr("Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured.").arg(!std ? "std.cfg" : !posix ? "posix.cfg" : "windows.cfg"));
result.loadCppcheckCfg();
// If project file loaded, read settings from it
if (mProjectFile) {
@ -1356,8 +1356,18 @@ void MainWindow::toggleAllChecked(bool checked)
void MainWindow::about()
{
AboutDialog *dlg = new AboutDialog(CppCheck::version(), CppCheck::extraVersion(), this);
dlg->exec();
if (!mCppcheckCfgAbout.isEmpty()) {
QMessageBox msg(QMessageBox::Information,
tr("About"),
mCppcheckCfgAbout,
QMessageBox::Ok,
this);
msg.exec();
}
else {
AboutDialog *dlg = new AboutDialog(CppCheck::version(), CppCheck::extraVersion(), this);
dlg->exec();
}
}
void MainWindow::showLicense()
@ -1445,6 +1455,9 @@ void MainWindow::formatAndSetTitle(const QString &text)
nameWithVersion += " (" + extraVersion + ")";
}
if (!mCppcheckCfgProductName.isEmpty())
nameWithVersion = mCppcheckCfgProductName;
QString title;
if (text.isEmpty())
title = nameWithVersion;

View File

@ -472,6 +472,9 @@ private:
* List of MRU menu actions. Needs also to store the separator.
*/
QAction *mRecentProjectActs[MaxRecentProjects + 1];
QString mCppcheckCfgAbout;
QString mCppcheckCfgProductName;
};
/// @}
#endif // MAINWINDOW_H

View File

@ -337,9 +337,6 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile)
if (!mUI.mAddonMisra->isEnabled()) {
mUI.mEditMisraFile->setEnabled(false);
mUI.mBtnBrowseMisraFile->setEnabled(false);
} else if (misraFile.isEmpty()) {
mUI.mAddonMisra->setEnabled(false);
mUI.mAddonMisra->setText(mUI.mAddonMisra->text() + ' ' + tr("(no rule texts file)"));
}
mUI.mToolClangAnalyzer->setChecked(projectFile->getClangAnalyzer());

View File

@ -1,11 +1,13 @@
qt5_wrap_cpp(test-benchmark-simple_SRC benchmarksimple.h)
add_custom_target(build-testbenchmark-simple-deps SOURCES ${test-benchmark-simple_SRC})
add_dependencies(gui-build-deps build-testbenchmark-simple-deps)
if(USE_BUNDLED_TINYXML2)
list(APPEND test-benchmark-simple_SRC $<TARGET_OBJECTS:tinyxml2_objs>)
endif()
add_executable(benchmark-simple
${test-benchmark-simple_SRC}
benchmarksimple.cpp
$<TARGET_OBJECTS:lib_objs>
$<TARGET_OBJECTS:tinyxml2_objs>
$<TARGET_OBJECTS:simplecpp_objs>
)
target_include_directories(benchmark-simple PRIVATE ${CMAKE_SOURCE_DIR}/lib)
@ -16,4 +18,7 @@ if (HAVE_RULES)
endif()
if (USE_Z3)
target_link_libraries(benchmark-simple ${Z3_LIBRARIES})
endif()
if(tinyxml2_FOUND AND NOT USE_BUNDLED_TINYXML2)
target_link_libraries(benchmark-simple ${tinyxml2_LIBRARIES})
endif()

View File

@ -22,4 +22,7 @@ if (HAVE_RULES)
endif()
if (USE_Z3)
target_link_libraries(test-xmlreportv2 ${Z3_LIBRARIES})
endif()
endif()
if(tinyxml2_FOUND AND NOT USE_BUNDLED_TINYXML2)
target_link_libraries(test-xmlreportv2 ${tinyxml2_LIBRARIES})
endif()

View File

@ -147,22 +147,21 @@ static bool simplifyPathWithVariables(std::string &s, std::map<std::string, std:
void ImportProject::FileSettings::setIncludePaths(const std::string &basepath, const std::list<std::string> &in, std::map<std::string, std::string, cppcheck::stricmp> &variables)
{
std::list<std::string> listInc;
// only parse each includePath once - so remove duplicates
std::list<std::string> uniqueIncludePaths = in;
uniqueIncludePaths.sort();
uniqueIncludePaths.unique();
for (const std::string &it : uniqueIncludePaths) {
if (it.empty())
std::set<std::string> found;
const std::list<std::string> copyIn(in);
includePaths.clear();
for (const std::string &ipath : copyIn) {
if (ipath.empty())
continue;
if (it.compare(0,2,"%(")==0)
if (ipath.compare(0,2,"%(")==0)
continue;
std::string s(Path::fromNativeSeparators(ipath));
if (!found.insert(s).second)
continue;
std::string s(Path::fromNativeSeparators(it));
if (s[0] == '/' || (s.size() > 1U && s.compare(1,2,":/") == 0)) {
if (!endsWith(s,'/'))
s += '/';
listInc.push_back(s);
includePaths.push_back(s);
continue;
}
@ -177,9 +176,8 @@ void ImportProject::FileSettings::setIncludePaths(const std::string &basepath, c
}
if (s.empty())
continue;
listInc.push_back(s + '/');
includePaths.push_back(s + '/');
}
includePaths.swap(listInc);
}
ImportProject::Type ImportProject::import(const std::string &filename, Settings *settings)
@ -409,28 +407,38 @@ bool ImportProject::importCompileCommands(std::istream &istr)
const std::string directory = dirpath;
std::ostringstream comm;
if (obj.find("arguments") != obj.end()) {
std::string command;
if (obj.count("arguments")) {
if (obj["arguments"].is<picojson::array>()) {
for (const picojson::value& arg : obj["arguments"].get<picojson::array>()) {
if (arg.is<std::string>()) {
comm << arg.get<std::string>() << " ";
std::string str = arg.get<std::string>();
if (str.find(" ") != std::string::npos && str.find("=\"") > str.find(" "))
str = "\"" + str + "\"";
command += str + " ";
}
}
} else {
printError("'arguments' field in compilation database entry is not a JSON array");
return false;
}
} else if (obj.find("command") != obj.end()) {
} else if (obj.count("command")) {
if (obj["command"].is<std::string>()) {
comm << obj["command"].get<std::string>();
command = obj["command"].get<std::string>();
} else {
printError("'command' field in compilation database entry is not a string");
return false;
}
} else {
printError("no 'arguments' or 'command' field found in compilation database entry");
return false;
}
const std::string command = comm.str();
if (!obj.count("file") || !obj["file"].is<std::string>()) {
printError("skip compilation database entry because it does not have a proper 'file' field");
continue;
}
const std::string file = Path::fromNativeSeparators(obj["file"].get<std::string>());
// Accept file?
@ -466,15 +474,17 @@ bool ImportProject::importSln(std::istream &istr, const std::string &path, const
{
std::string line;
// skip magic word
if (!std::getline(istr,line)) {
printError("Visual Studio solution file is empty");
return false;
}
if (!std::getline(istr, line) || line.find("Microsoft Visual Studio Solution File") != 0) {
printError("Visual Studio solution file header not found");
return false;
if (line.find("Microsoft Visual Studio Solution File") != 0) {
// Skip BOM
if (!std::getline(istr, line) || line.find("Microsoft Visual Studio Solution File") != 0) {
printError("Visual Studio solution file header not found");
return false;
}
}
std::map<std::string,std::string,cppcheck::stricmp> variables;

View File

@ -76,9 +76,9 @@ Settings::Settings()
certainty.setEnabled(Certainty::normal, true);
}
void Settings::loadCppcheckCfg(const std::string &executable)
void Settings::loadCppcheckCfg()
{
std::string fileName = Path::getPathFromFilename(executable) + "cppcheck.cfg";
std::string fileName = Path::getPathFromFilename(exename) + "cppcheck.cfg";
#ifdef FILESDIR
if (Path::fileExists(FILESDIR "/cppcheck.cfg"))
fileName = FILESDIR "/cppcheck.cfg";
@ -92,6 +92,10 @@ void Settings::loadCppcheckCfg(const std::string &executable)
if (!picojson::get_last_error().empty())
return;
picojson::object obj = json.get<picojson::object>();
if (obj.count("productName") && obj["productName"].is<std::string>())
cppcheckCfgProductName = obj["productName"].get<std::string>();
if (obj.count("about") && obj["about"].is<std::string>())
cppcheckCfgAbout = obj["about"].get<std::string>();
if (obj.count("addons") && obj["addons"].is<picojson::array>()) {
for (const picojson::value &v : obj["addons"].get<picojson::array>()) {
const std::string &s = v.get<std::string>();

View File

@ -97,7 +97,7 @@ private:
public:
Settings();
void loadCppcheckCfg(const std::string &executable);
void loadCppcheckCfg();
/** @brief addons, either filename of python/json file or json data */
std::list<std::string> addons;
@ -156,6 +156,12 @@ public:
/** @brief include paths excluded from checking the configuration */
std::set<std::string> configExcludePaths;
/** cppcheck.cfg: Custom product name */
std::string cppcheckCfgProductName;
/** cppcheck.cfg: About text */
std::string cppcheckCfgAbout;
/** @brief Are we running from DACA script? */
bool daca;

View File

@ -4945,6 +4945,8 @@ static void valueFlowForwardAssign(Token* const tok,
// Skip RHS
const Token * nextExpression = tok->astParent() ? nextAfterAstRightmostLeaf(tok->astParent()) : tok->next();
if (!nextExpression)
return;
for (ValueFlow::Value& value : values) {
if (value.isSymbolicValue())

View File

@ -8,8 +8,8 @@
#define STRINGIFY(x) STRING(x)
#define STRING(VER) #VER
#if CPPCHECK_MINOR == CPPCHECK_DEVMINOR
#define CPPCHECK_VERSION_STRING STRINGIFY(CPPCHECK_MAJOR) "." STRINGIFY(CPPCHECK_DEVMINOR)
#define CPPCHECK_VERSION CPPCHECK_MAJOR,CPPCHECK_MINOR,0,0
#define CPPCHECK_VERSION_STRING STRINGIFY(CPPCHECK_MAJOR) "." STRINGIFY(CPPCHECK_DEVMINOR) ".4"
#define CPPCHECK_VERSION CPPCHECK_MAJOR,CPPCHECK_MINOR,4,0
#else
#define CPPCHECK_VERSION_STRING STRINGIFY(CPPCHECK_MAJOR) "." STRINGIFY(CPPCHECK_DEVMINOR) " dev"
#define CPPCHECK_VERSION CPPCHECK_MAJOR,CPPCHECK_MINOR,99,0

View File

@ -1,11 +1,19 @@
if (ENABLE_OSS_FUZZ AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_executable(fuzz-client EXCLUDE_FROM_ALL
set(fuzz-client_SRC
main.cpp
type2.cpp
)
if(USE_BUNDLED_TINYXML2)
list(APPEND fuzz-client_SRC $<TARGET_OBJECTS:tinyxml2_objs>)
endif()
add_executable(fuzz-client EXCLUDE_FROM_ALL
${fuzz-client_SRC}
$<TARGET_OBJECTS:simplecpp_objs>
$<TARGET_OBJECTS:tinyxml2_objs>
$<TARGET_OBJECTS:lib_objs>)
target_include_directories(fuzz-client PRIVATE ${CMAKE_SOURCE_DIR}/lib ${CMAKE_SOURCE_DIR}/externals/simplecpp ${CMAKE_SOURCE_DIR}/externals/tinyxml2 ${CMAKE_SOURCE_DIR}/externals)
target_include_directories(fuzz-client PRIVATE ${CMAKE_SOURCE_DIR}/lib ${CMAKE_SOURCE_DIR}/externals/simplecpp ${CMAKE_SOURCE_DIR}/externals)
if(USE_BUNDLED_TINYXML2)
target_include_directories(fuzz-client PRIVATE ${CMAKE_SOURCE_DIR}/externals/tinyxml2/)
endif()
target_compile_options(fuzz-client PRIVATE -fsanitize=fuzzer)
# TODO: target_link_options() requires CMake >= 3.13
#target_link_options(fuzz-client PRIVATE -fsanitize=fuzzer)
@ -16,6 +24,9 @@ if (ENABLE_OSS_FUZZ AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
if (USE_Z3)
target_link_libraries(fuzz-client PRIVATE ${Z3_LIBRARIES})
endif()
if(tinyxml2_FOUND AND NOT USE_BUNDLED_TINYXML2)
target_link_libraries(fuzz-client PRIVATE ${tinyxml2_LIBRARIES})
endif()
add_executable(translate EXCLUDE_FROM_ALL
translate.cpp

View File

@ -26,7 +26,7 @@ if (BUILD_TESTS)
endif()
endif()
if(tinyxml2_FOUND AND NOT USE_BUNDLED_TINYXML2)
target_link_libraries(testrunner tinyxml2)
target_link_libraries(testrunner ${tinyxml2_LIBRARIES})
endif()
if (NOT CMAKE_DISABLE_PRECOMPILE_HEADERS)

View File

@ -70,9 +70,9 @@ ${CPPCHECK} ${CPPCHECK_OPT} --inconclusive ${DIR}std.cpp
# windows.cpp
# Syntax check via g++ does not work because it can not find a valid windows.h
#${CXX} ${CXX_OPT} ${DIR}windows.cpp
${CPPCHECK} ${CPPCHECK_OPT} --inconclusive --platform=win32A ${DIR}windows.cpp
${CPPCHECK} ${CPPCHECK_OPT} --inconclusive --platform=win32W ${DIR}windows.cpp
${CPPCHECK} ${CPPCHECK_OPT} --inconclusive --platform=win64 ${DIR}windows.cpp
${CPPCHECK} ${CPPCHECK_OPT} --inconclusive --platform=win32A --library=windows ${DIR}windows.cpp
${CPPCHECK} ${CPPCHECK_OPT} --inconclusive --platform=win32W --library=windows ${DIR}windows.cpp
${CPPCHECK} ${CPPCHECK_OPT} --inconclusive --platform=win64 --library=windows ${DIR}windows.cpp
# wxwidgets.cpp
set +e

View File

@ -58,6 +58,10 @@ private:
TEST_CASE(importCompileCommands6); // Windows/CMake/Ninja generated comile_commands.json with spaces
TEST_CASE(importCompileCommands7); // linux: "/home/danielm/cppcheck 2"
TEST_CASE(importCompileCommands8); // Windows: "C:\Users\danielm\cppcheck"
TEST_CASE(importCompileCommands9);
TEST_CASE(importCompileCommands10); // #10887: include path with space
TEST_CASE(importCompileCommands11); // include path order
TEST_CASE(importCompileCommands12); // defines
TEST_CASE(importCompileCommandsArgumentsSection); // Handle arguments section
TEST_CASE(importCompileCommandsNoCommandSection); // gracefully handles malformed json
TEST_CASE(importCppcheckGuiProject);
@ -209,7 +213,8 @@ private:
TestImporter importer;
importer.importCompileCommands(istr);
ASSERT_EQUALS(2, importer.fileSettings.size());
ASSERT_EQUALS("C:/Users/dan/git/test-cppcheck/mylib/second src/", importer.fileSettings.begin()->includePaths.front());
ASSERT_EQUALS("C:/Users/dan/git/test-cppcheck/mylib/src/", importer.fileSettings.begin()->includePaths.front());
ASSERT_EQUALS("C:/Users/dan/git/test-cppcheck/mylib/second src/", importer.fileSettings.begin()->includePaths.back());
}
@ -243,12 +248,85 @@ private:
}])";
std::istringstream istr(json);
TestImporter importer;
importer.importCompileCommands(istr); // Do not crash
}
void importCompileCommands9() const {
// IAR output (https://sourceforge.net/p/cppcheck/discussion/general/thread/608af51e0a/)
const char json[] =
R"([{
"arguments" : [
"powershell.exe -WindowStyle Hidden -NoProfile -ExecutionPolicy Bypass -File d:\\Projekte\\xyz\\firmware\\app\\xyz-lib\\build.ps1 -IAR -COMPILER_PATH \"c:\\Program Files (x86)\\IAR Systems\\Embedded Workbench 9.0\" -CONTROLLER CC1310F128 -LIB LIB_PERMANENT -COMPILER_DEFINES \"CC1310_HFXO_FREQ=24000000 DEBUG\""
],
"directory" : "d:\\Projekte\\xyz\\firmware\\app",
"type" : "PRE",
"file": "1.c"
}])";
std::istringstream istr(json);
TestImporter importer;
importer.importCompileCommands(istr);
}
void importCompileCommands10() const { // #10887
const char json[] =
R"([{
"file": "/home/danielm/cppcheck/1/test folder/1.c" ,
"directory": "",
"arguments": [
"iccavr.exe",
"-I",
"/home/danielm/cppcheck/test folder"
]
}])";
std::istringstream istr(json);
TestImporter importer;
ASSERT_EQUALS(true, importer.importCompileCommands(istr));
ASSERT_EQUALS(1, importer.fileSettings.size());
ASSERT_EQUALS("FILESDIR=\"C:\\Program Files\\Cppcheck\"", importer.fileSettings.begin()->defines);
ASSERT_EQUALS(2, importer.fileSettings.begin()->includePaths.size());
ASSERT_EQUALS("C:/Users/danielm/cppcheck/build/lib/", importer.fileSettings.begin()->includePaths.front());
ASSERT_EQUALS("C:/Users/danielm/cppcheck/lib/", importer.fileSettings.begin()->includePaths.back());
const ImportProject::FileSettings &fs = importer.fileSettings.front();
ASSERT_EQUALS("/home/danielm/cppcheck/test folder/", fs.includePaths.front());
}
void importCompileCommands11() const { // include path order
const char json[] =
R"([{
"file": "1.c" ,
"directory": "/x",
"arguments": [
"cc",
"-I",
"def",
"-I",
"abc"
]
}])";
std::istringstream istr(json);
TestImporter importer;
ASSERT_EQUALS(true, importer.importCompileCommands(istr));
ASSERT_EQUALS(1, importer.fileSettings.size());
const ImportProject::FileSettings &fs = importer.fileSettings.front();
ASSERT_EQUALS("/x/def/", fs.includePaths.front());
ASSERT_EQUALS("/x/abc/", fs.includePaths.back());
}
void importCompileCommands12() const { // define
const char json[] =
R"([{
"file": "1.c" ,
"directory": "/x",
"arguments": [
"cc",
"-D",
"X=1",
"-D",
"__VERSION__=\"IAR C/C++ Compiler V6.40.2.748 for Atmel AVR\""
]
}])";
std::istringstream istr(json);
TestImporter importer;
ASSERT_EQUALS(true, importer.importCompileCommands(istr));
ASSERT_EQUALS(1, importer.fileSettings.size());
const ImportProject::FileSettings &fs = importer.fileSettings.front();
ASSERT_EQUALS("X=1;__VERSION__=IAR C/C++ Compiler V6.40.2.748 for Atmel AVR", fs.defines);
}
void importCompileCommandsArgumentsSection() const {

View File

@ -6259,6 +6259,13 @@ private:
" }\n"
"};\n";
valueOfTok(code, "f.c");
code = "int f(int value) { return 0; }\n"
"std::shared_ptr<Manager> g() {\n"
" static const std::shared_ptr<Manager> x{ new M{} };\n"
" return x;\n"
"}\n";
valueOfTok(code, "x");
}
void valueFlowHang() {

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Include>
<?define ProductName = "Cppcheck $(var.Platform) 2.7" ?>
<?define ProductName = "Cppcheck $(var.Platform) 2.7.4" ?>
<?define ProductNameShort = "Cppcheck" ?>
<?define ProductVersion = "2.7" ?>
<?define ProductVersion = "2.7.4" ?>
<?define ProductManufacturer = "The Cppcheck team" ?>
<?define ProductDescription = "Cppcheck is a tool for static analysis of C/C++ code" ?>