Skip to content

Commit

Permalink
addons/namingng.py: Fix use with --cli.
Browse files Browse the repository at this point in the history
Commandline use of namingng led to an error complaining about the use of
--cli. This flag is supported by the generic cppcheckdata.ArgumentParser(),
which is not used by namingng.py. Replacing argparse.ArgumentParser() by the
pre-configured cppcheckdata variant, solves this.

Furthermore this patch changes namingng.py to use the generic reporting
provided by cppcheckdata.reportError().

A local function reportNamingError() is implemented to call through to
cppcheckdata.reportError(), while collecting all errors.

If --cli is given, the exit status is now 0, even if errors are reported, as a
non-zero exit status is interpreted as an internal error by cppcheck. Also, all
output other than reported errors is suppressed.

The --verify option now verifies correct working both in --cli and non --cli
mode.
  • Loading branch information
mvds00 committed Dec 23, 2023
1 parent 63f93a1 commit fcb7cb5
Showing 1 changed file with 52 additions and 56 deletions.
108 changes: 52 additions & 56 deletions addons/namingng.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,78 +28,70 @@
import argparse
import json

errors = []

# Auxiliary class
class DataStruct:
def __init__(self, file, linenr, string):
self.file = file
self.linenr = linenr
self.str = string
self.column = 0


def reportError(filename, linenr, severity, msg):
message = "[{filename}:{linenr}] ( {severity} ) naming.py: {msg}\n".format(
filename=filename,
linenr=linenr,
severity=severity,
msg=msg
)
sys.stderr.write(message)
return message

def reportNamingError(location,message,errorId='namingConvention',severity='style',extra=''):
line = cppcheckdata.reportError(location,severity,message,'namingng',errorId,extra)
errors.append(line)

def loadConfig(configfile):
with open(configfile) as fh:
data = json.load(fh)
return data


def checkTrueRegex(data, expr, msg, errors):
def checkTrueRegex(data, expr, msg):
res = re.match(expr, data.str)
if res:
errors.append(reportError(data.file, data.linenr, 'style', msg))
reportNamingError(data,msg)


def checkFalseRegex(data, expr, msg, errors):
def checkFalseRegex(data, expr, msg):
res = re.match(expr, data.str)
if not res:
errors.append(reportError(data.file, data.linenr, 'style', msg))
reportNamingError(data,msg)


def evalExpr(conf, exp, mockToken, msgType, errors):
def evalExpr(conf, exp, mockToken, msgType):
if isinstance(conf, dict):
if conf[exp][0]:
msg = msgType + ' ' + mockToken.str + ' violates naming convention : ' + conf[exp][1]
checkTrueRegex(mockToken, exp, msg, errors)
checkTrueRegex(mockToken, exp, msg)
elif ~conf[exp][0]:
msg = msgType + ' ' + mockToken.str + ' violates naming convention : ' + conf[exp][1]
checkFalseRegex(mockToken, exp, msg, errors)
checkFalseRegex(mockToken, exp, msg)
else:
msg = msgType + ' ' + mockToken.str + ' violates naming convention : ' + conf[exp][0]
checkFalseRegex(mockToken, exp, msg, errors)
checkFalseRegex(mockToken, exp, msg)
else:
msg = msgType + ' ' + mockToken.str + ' violates naming convention'
checkFalseRegex(mockToken, exp, msg, errors)
checkFalseRegex(mockToken, exp, msg)


def process(dumpfiles, configfile, debugprint=False):

errors = []

conf = loadConfig(configfile)

for afile in dumpfiles:
if not afile[-5:] == '.dump':
continue
print('Checking ' + afile + '...')
if not args.cli:
print('Checking ' + afile + '...')
data = cppcheckdata.CppcheckData(afile)

# Check File naming
if "RE_FILE" in conf and conf["RE_FILE"]:
mockToken = DataStruct(afile[:-5], "0", afile[afile.rfind('/') + 1:-5])
msgType = 'File name'
for exp in conf["RE_FILE"]:
evalExpr(conf["RE_FILE"], exp, mockToken, msgType, errors)
evalExpr(conf["RE_FILE"], exp, mockToken, msgType)

# Check Namespace naming
if "RE_NAMESPACE" in conf and conf["RE_NAMESPACE"]:
Expand All @@ -108,10 +100,11 @@ def process(dumpfiles, configfile, debugprint=False):
mockToken = DataStruct(tk.next.file, tk.next.linenr, tk.next.str)
msgType = 'Namespace'
for exp in conf["RE_NAMESPACE"]:
evalExpr(conf["RE_NAMESPACE"], exp, mockToken, msgType, errors)
evalExpr(conf["RE_NAMESPACE"], exp, mockToken, msgType)

for cfg in data.configurations:
print('Checking %s, config %s...' % (afile, cfg.name))
if not args.cli:
print('Checking %s, config %s...' % (afile, cfg.name))
if "RE_VARNAME" in conf and conf["RE_VARNAME"]:
for var in cfg.variables:
if var.nameToken and var.access != 'Global' and var.access != 'Public' and var.access != 'Private':
Expand All @@ -134,18 +127,15 @@ def process(dumpfiles, configfile, debugprint=False):
continue
if varType in conf["var_prefixes"]:
if not var.nameToken.str.startswith(conf["var_prefixes"][varType]):
errors.append(reportError(
var.typeStartToken.file,
var.typeStartToken.linenr,
'style',
reportNamingError(var.typeStartToken,
'Variable ' +
var.nameToken.str +
' violates naming convention'))
' violates naming convention')

mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str)
msgType = 'Variable'
for exp in conf["RE_VARNAME"]:
evalExpr(conf["RE_VARNAME"], exp, mockToken, msgType, errors)
evalExpr(conf["RE_VARNAME"], exp, mockToken, msgType)

# Check Private Variable naming
if "RE_PRIVATE_MEMBER_VARIABLE" in conf and conf["RE_PRIVATE_MEMBER_VARIABLE"]:
Expand All @@ -156,7 +146,7 @@ def process(dumpfiles, configfile, debugprint=False):
mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str)
msgType = 'Private member variable'
for exp in conf["RE_PRIVATE_MEMBER_VARIABLE"]:
evalExpr(conf["RE_PRIVATE_MEMBER_VARIABLE"], exp, mockToken, msgType, errors)
evalExpr(conf["RE_PRIVATE_MEMBER_VARIABLE"], exp, mockToken, msgType)

# Check Public Member Variable naming
if "RE_PUBLIC_MEMBER_VARIABLE" in conf and conf["RE_PUBLIC_MEMBER_VARIABLE"]:
Expand All @@ -166,7 +156,7 @@ def process(dumpfiles, configfile, debugprint=False):
mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str)
msgType = 'Public member variable'
for exp in conf["RE_PUBLIC_MEMBER_VARIABLE"]:
evalExpr(conf["RE_PUBLIC_MEMBER_VARIABLE"], exp, mockToken, msgType, errors)
evalExpr(conf["RE_PUBLIC_MEMBER_VARIABLE"], exp, mockToken, msgType)

# Check Global Variable naming
if "RE_GLOBAL_VARNAME" in conf and conf["RE_GLOBAL_VARNAME"]:
Expand All @@ -176,7 +166,7 @@ def process(dumpfiles, configfile, debugprint=False):
mockToken = DataStruct(var.typeStartToken.file, var.typeStartToken.linenr, var.nameToken.str)
msgType = 'Public member variable'
for exp in conf["RE_GLOBAL_VARNAME"]:
evalExpr(conf["RE_GLOBAL_VARNAME"], exp, mockToken, msgType, errors)
evalExpr(conf["RE_GLOBAL_VARNAME"], exp, mockToken, msgType)

# Check Functions naming
if "RE_FUNCTIONNAME" in conf and conf["RE_FUNCTIONNAME"]:
Expand All @@ -194,12 +184,11 @@ def process(dumpfiles, configfile, debugprint=False):

if retval and retval in conf["function_prefixes"]:
if not token.function.name.startswith(conf["function_prefixes"][retval]):
errors.append(reportError(
token.file, token.linenr, 'style', 'Function ' + token.function.name + ' violates naming convention'))
reportNamingError(token, 'Function ' + token.function.name + ' violates naming convention')
mockToken = DataStruct(token.file, token.linenr, token.function.name)
msgType = 'Function'
for exp in conf["RE_FUNCTIONNAME"]:
evalExpr(conf["RE_FUNCTIONNAME"], exp, mockToken, msgType, errors)
evalExpr(conf["RE_FUNCTIONNAME"], exp, mockToken, msgType)

# Check Class naming
if "RE_CLASS_NAME" in conf and conf["RE_CLASS_NAME"]:
Expand All @@ -209,14 +198,10 @@ def process(dumpfiles, configfile, debugprint=False):
mockToken = DataStruct(fnc.tokenDef.file, fnc.tokenDef.linenr, fnc.name)
msgType = 'Class ' + fnc.type
for exp in conf["RE_CLASS_NAME"]:
evalExpr(conf["RE_CLASS_NAME"], exp, mockToken, msgType, errors)
return errors

evalExpr(conf["RE_CLASS_NAME"], exp, mockToken, msgType)

if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Naming verification')
parser.add_argument('dumpfiles', type=str, nargs='+',
help='A set of dumpfiles to process')
parser = cppcheckdata.ArgumentParser()
parser.add_argument("--debugprint", action="store_true", default=False,
help="Add debug prints")
parser.add_argument("--configfile", type=str, default="naming.json",
Expand All @@ -225,28 +210,39 @@ def process(dumpfiles, configfile, debugprint=False):
help="verify this script. Must be executed in test folder !")

args = parser.parse_args()
errors = process(args.dumpfiles, args.configfile, args.debugprint)
process(args.dumpfile, args.configfile, args.debugprint)

if args.verify:
print(errors)
if len(errors) < 6:
print("Not enough errors found")
sys.exit(1)
target = [
'[namingng_test.c:8] ( style ) naming.py: Variable badui32 violates naming convention\n',
'[namingng_test.c:11] ( style ) naming.py: Variable a violates naming convention\n',
'[namingng_test.c:29] ( style ) naming.py: Variable badui32 violates naming convention\n',
'[namingng_test.c:20] ( style ) naming.py: Function ui16bad_underscore violates naming convention\n',
'[namingng_test.c:25] ( style ) naming.py: Function u32Bad violates naming convention\n',
'[namingng_test.c:37] ( style ) naming.py: Function Badui16 violates naming convention\n']
if args.cli:
target = [
'{"file": "namingng_test.c", "linenr": 8, "column": 5, "severity": "style", "message": "Variable badui32 violates naming convention", "addon": "namingng", "errorId": "namingConvention", "extra": ""}\n',
'{"file": "namingng_test.c", "linenr": 11, "column": 5, "severity": "style", "message": "Variable a violates naming convention", "addon": "namingng", "errorId": "namingConvention", "extra": ""}\n',
'{"file": "namingng_test.c", "linenr": 29, "column": 5, "severity": "style", "message": "Variable badui32 violates naming convention", "addon": "namingng", "errorId": "namingConvention", "extra": ""}\n',
'{"file": "namingng_test.c", "linenr": 20, "column": 0, "severity": "style", "message": "Function ui16bad_underscore violates naming convention", "addon": "namingng", "errorId": "namingConvention", "extra": ""}\n',
'{"file": "namingng_test.c", "linenr": 25, "column": 10, "severity": "style", "message": "Function u32Bad violates naming convention", "addon": "namingng", "errorId": "namingConvention", "extra": ""}\n',
'{"file": "namingng_test.c", "linenr": 37, "column": 10, "severity": "style", "message": "Function Badui16 violates naming convention", "addon": "namingng", "errorId": "namingConvention", "extra": ""}\n',
]
else:
target = [
'[namingng_test.c:8] (style) Variable badui32 violates naming convention [namingng-namingConvention]\n',
'[namingng_test.c:11] (style) Variable a violates naming convention [namingng-namingConvention]\n',
'[namingng_test.c:29] (style) Variable badui32 violates naming convention [namingng-namingConvention]\n',
'[namingng_test.c:20] (style) Function ui16bad_underscore violates naming convention [namingng-namingConvention]\n',
'[namingng_test.c:25] (style) Function u32Bad violates naming convention [namingng-namingConvention]\n',
'[namingng_test.c:37] (style) Function Badui16 violates naming convention [namingng-namingConvention]\n',
]
diff = set(errors) - set(target)
if len(diff):
print("Not the right errors found {}".format(str(diff)))
sys.exit(1)
print("Verification done\n")
if not args.cli:
print("Verification done\n")
sys.exit(0)

if len(errors):
if len(errors) and not args.cli:
print('Found errors: {}'.format(len(errors)))
sys.exit(1)

Expand Down

0 comments on commit fcb7cb5

Please sign in to comment.