Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/CI-unixish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,6 @@ jobs:
python3 ../naming.py --var='[a-z].*' --function='[a-z].*' naming_test.c.dump
../../cppcheck --dump naming_test.cpp
python3 ../naming.py --var='[a-z].*' --function='[a-z].*' naming_test.cpp.dump
../../cppcheck --dump namingng_test.c
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should at least keep a basic test to make sure it still works in standalone mode.

python3 ../namingng.py --configfile ../naming.json --verify namingng_test.c.dump

- name: Build democlient
if: matrix.os == 'ubuntu-22.04'
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/CI-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,4 @@ jobs:
rem python3 ..\naming.py --var='[a-z].*' --function='[a-z].*' naming_test.c.dump || exit /b !errorlevel!
..\..\cppcheck --dump naming_test.cpp || exit /b !errorlevel!
python3 ..\naming.py --var='[a-z].*' --function='[a-z].*' naming_test.cpp.dump || exit /b !errorlevel!
..\..\cppcheck --dump namingng_test.c || exit /b !errorlevel!
python3 ..\namingng.py --configfile ..\naming.json --verify namingng_test.c.dump || exit /b !errorlevel!

4 changes: 3 additions & 1 deletion addons/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ Addons are scripts that analyses Cppcheck dump files to check compatibility with
Helper class for reading Cppcheck dump files within an addon.
- misra_9.py
Implementation of the MISRA 9.x rules used by `misra` addon.
- naming.json
- namingng.config.json
Example configuration for `namingng` addon.
- namingng.json
Example JSON file that can be used using --addon=namingng.json, referring to namingng.py and namingng.config.json
- ROS_naming.json
Example configuration for the `namingng` addon enforcing the [ROS naming convention for C++ ](http://wiki.ros.org/CppStyleGuide#Files).
- runaddon.py
Expand Down
File renamed without changes.
6 changes: 6 additions & 0 deletions addons/namingng.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"script":"namingng.py",
"args":[
"--configfile=namingng.config.json"
]
}
104 changes: 31 additions & 73 deletions addons/namingng.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,70 +29,59 @@
import argparse
import json


# 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=''):
cppcheckdata.reportError(location,severity,message,'namingng',errorId,extra)

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 = []
Comment thread
danmar marked this conversation as resolved.

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
Expand All @@ -104,7 +93,8 @@ def process(dumpfiles, configfile, debugprint=False):
good |= bool(re.match(exp, source_file))
good |= bool(re.match(exp, basename))
if not good:
errors.append(reportError(source_file, 0, 'style', 'File name ' + source_file + ' violates naming convention'))
mockToken = DataStruct(source_file, 0, basename)
reportNamingError(mockToken, 'File name ' + basename + ' violates naming convention')

# Check Namespace naming
if "RE_NAMESPACE" in conf and conf["RE_NAMESPACE"]:
Expand All @@ -113,10 +103,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 @@ -139,18 +130,15 @@ def process(dumpfiles, configfile, debugprint=False):
continue
if varType in conf.get("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 @@ -161,7 +149,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 @@ -171,7 +159,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 @@ -181,7 +169,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 @@ -199,12 +187,11 @@ def process(dumpfiles, configfile, debugprint=False):

if retval and retval in conf.get("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 @@ -214,45 +201,16 @@ 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",
parser.add_argument("--configfile", type=str, default="namingng.config.json",
help="Naming check config file")
parser.add_argument("--verify", action="store_true", default=False,
help="verify this script. Must be executed in test folder !")

args = parser.parse_args()
errors = process(args.dumpfiles, 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']
diff = set(errors) - set(target)
if len(diff):
print("Not the right errors found {}".format(str(diff)))
sys.exit(1)
print("Verification done\n")
sys.exit(0)

if len(errors):
print('Found errors: {}'.format(len(errors)))
sys.exit(1)
process(args.dumpfile, args.configfile, args.debugprint)

sys.exit(0)
50 changes: 0 additions & 50 deletions addons/test/namingng_test.c

This file was deleted.

Loading