Compare commits
18 Commits
Author | SHA1 | Date |
---|---|---|
Daniel Marjamäki | 392741715b | |
Daniel Marjamäki | ef8a499c8d | |
Wolfgang Stöggl | 1cc234ac2c | |
Daniel Marjamäki | 9ef14d179d | |
Daniel Marjamäki | 41872f9a6d | |
Daniel Marjamäki | 635059603a | |
Daniel Marjamäki | 4c650289ad | |
Daniel Marjamäki | 760436c56e | |
Daniel Marjamäki | 355866f0cf | |
Daniel Marjamäki | 97bf53515b | |
Daniel Marjamäki | a06898dc8e | |
Daniel Marjamäki | a045149181 | |
Daniel Marjamäki | 54d079387e | |
Georgi D. Sotirov | 199fe343c3 | |
Oliver Stöneberg | d922a3b0bc | |
Daniel Marjamäki | f0150069c8 | |
Daniel Marjamäki | 6ef6b02153 | |
Daniel Marjamäki | c5b3fafe84 |
|
@ -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: |
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
135
addons/misra.py
135
addons/misra.py
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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()
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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" ?>
|
||||
|
|
Loading…
Reference in New Issue