mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-15 02:43:41 +00:00
lib/clippy: assert() for non-optional args
This is mostly to help static analysis; since we know from the command string which args are optional and which aren't, we can add assert() statements on them. Fixes: #3270 Signed-off-by: David Lamparter <equinox@diac24.net>
This commit is contained in:
parent
3779776a39
commit
4381a59be0
@ -37,6 +37,7 @@ class RenderHandler(object):
|
|||||||
deref = ''
|
deref = ''
|
||||||
drop_str = False
|
drop_str = False
|
||||||
canfail = True
|
canfail = True
|
||||||
|
canassert = False
|
||||||
|
|
||||||
class StringHandler(RenderHandler):
|
class StringHandler(RenderHandler):
|
||||||
argtype = 'const char *'
|
argtype = 'const char *'
|
||||||
@ -44,6 +45,7 @@ class StringHandler(RenderHandler):
|
|||||||
code = Template('$varname = (argv[_i]->type == WORD_TKN) ? argv[_i]->text : argv[_i]->arg;')
|
code = Template('$varname = (argv[_i]->type == WORD_TKN) ? argv[_i]->text : argv[_i]->arg;')
|
||||||
drop_str = True
|
drop_str = True
|
||||||
canfail = False
|
canfail = False
|
||||||
|
canassert = True
|
||||||
|
|
||||||
class LongHandler(RenderHandler):
|
class LongHandler(RenderHandler):
|
||||||
argtype = 'long'
|
argtype = 'long'
|
||||||
@ -111,6 +113,7 @@ if (argv[_i]->text[0] == 'X') {
|
|||||||
_fail = !inet_aton(argv[_i]->arg, &s__$varname.sin.sin_addr);
|
_fail = !inet_aton(argv[_i]->arg, &s__$varname.sin.sin_addr);
|
||||||
$varname = &s__$varname;
|
$varname = &s__$varname;
|
||||||
}''')
|
}''')
|
||||||
|
canassert = True
|
||||||
|
|
||||||
def mix_handlers(handlers):
|
def mix_handlers(handlers):
|
||||||
def combine(a, b):
|
def combine(a, b):
|
||||||
@ -171,6 +174,7 @@ $argblocks
|
|||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
$argassert
|
||||||
return ${fnname}_magic(self, vty, argc, argv$arglist);
|
return ${fnname}_magic(self, vty, argc, argv$arglist);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,6 +186,21 @@ argblock = Template('''
|
|||||||
$code
|
$code
|
||||||
}''')
|
}''')
|
||||||
|
|
||||||
|
def get_always_args(token, always_args, args = [], stack = []):
|
||||||
|
if token in stack:
|
||||||
|
return
|
||||||
|
if token.type == 'END_TKN':
|
||||||
|
for arg in list(always_args):
|
||||||
|
if arg not in args:
|
||||||
|
always_args.remove(arg)
|
||||||
|
return
|
||||||
|
|
||||||
|
stack = stack + [token]
|
||||||
|
if token.type in handlers and token.varname is not None:
|
||||||
|
args = args + [token.varname]
|
||||||
|
for nexttkn in token.next():
|
||||||
|
get_always_args(nexttkn, always_args, args, stack)
|
||||||
|
|
||||||
def process_file(fn, ofd, dumpfd, all_defun):
|
def process_file(fn, ofd, dumpfd, all_defun):
|
||||||
errors = 0
|
errors = 0
|
||||||
filedata = clippy.parse(fn)
|
filedata = clippy.parse(fn)
|
||||||
@ -206,6 +225,7 @@ def process_file(fn, ofd, dumpfd, all_defun):
|
|||||||
|
|
||||||
graph = clippy.Graph(cmddef)
|
graph = clippy.Graph(cmddef)
|
||||||
args = OrderedDict()
|
args = OrderedDict()
|
||||||
|
always_args = set()
|
||||||
for token, depth in clippy.graph_iterate(graph):
|
for token, depth in clippy.graph_iterate(graph):
|
||||||
if token.type not in handlers:
|
if token.type not in handlers:
|
||||||
continue
|
continue
|
||||||
@ -213,6 +233,9 @@ def process_file(fn, ofd, dumpfd, all_defun):
|
|||||||
continue
|
continue
|
||||||
arg = args.setdefault(token.varname, [])
|
arg = args.setdefault(token.varname, [])
|
||||||
arg.append(handlers[token.type](token))
|
arg.append(handlers[token.type](token))
|
||||||
|
always_args.add(token.varname)
|
||||||
|
|
||||||
|
get_always_args(graph.first(), always_args)
|
||||||
|
|
||||||
#print('-' * 76)
|
#print('-' * 76)
|
||||||
#pprint(entry)
|
#pprint(entry)
|
||||||
@ -224,30 +247,36 @@ def process_file(fn, ofd, dumpfd, all_defun):
|
|||||||
argdecls = []
|
argdecls = []
|
||||||
arglist = []
|
arglist = []
|
||||||
argblocks = []
|
argblocks = []
|
||||||
|
argassert = []
|
||||||
doc = []
|
doc = []
|
||||||
canfail = 0
|
canfail = 0
|
||||||
|
|
||||||
def do_add(handler, varname, attr = ''):
|
def do_add(handler, basename, varname, attr = ''):
|
||||||
argdefs.append(',\\\n\t%s %s%s' % (handler.argtype, varname, attr))
|
argdefs.append(',\\\n\t%s %s%s' % (handler.argtype, varname, attr))
|
||||||
argdecls.append('\t%s\n' % (handler.decl.substitute({'varname': varname}).replace('\n', '\n\t')))
|
argdecls.append('\t%s\n' % (handler.decl.substitute({'varname': varname}).replace('\n', '\n\t')))
|
||||||
arglist.append(', %s%s' % (handler.deref, varname))
|
arglist.append(', %s%s' % (handler.deref, varname))
|
||||||
|
if basename in always_args and handler.canassert:
|
||||||
|
argassert.append('''\tif (!%s) {
|
||||||
|
\t\tvty_out(vty, "Internal CLI error [%%s]\\n", "%s");
|
||||||
|
\t\treturn CMD_WARNING;
|
||||||
|
\t}\n''' % (varname, varname))
|
||||||
if attr == '':
|
if attr == '':
|
||||||
at = handler.argtype
|
at = handler.argtype
|
||||||
if not at.startswith('const '):
|
if not at.startswith('const '):
|
||||||
at = '. . . ' + at
|
at = '. . . ' + at
|
||||||
doc.append('\t%-26s %s' % (at, varname))
|
doc.append('\t%-26s %s %s' % (at, 'alw' if basename in always_args else 'opt', varname))
|
||||||
|
|
||||||
for varname in args.keys():
|
for varname in args.keys():
|
||||||
handler = mix_handlers(args[varname])
|
handler = mix_handlers(args[varname])
|
||||||
#print(varname, handler)
|
#print(varname, handler)
|
||||||
if handler is None: continue
|
if handler is None: continue
|
||||||
do_add(handler, varname)
|
do_add(handler, varname, varname)
|
||||||
code = handler.code.substitute({'varname': varname}).replace('\n', '\n\t\t\t')
|
code = handler.code.substitute({'varname': varname}).replace('\n', '\n\t\t\t')
|
||||||
if handler.canfail:
|
if handler.canfail:
|
||||||
canfail = 1
|
canfail = 1
|
||||||
strblock = ''
|
strblock = ''
|
||||||
if not handler.drop_str:
|
if not handler.drop_str:
|
||||||
do_add(StringHandler(None), '%s_str' % (varname), ' __attribute__ ((unused))')
|
do_add(StringHandler(None), varname, '%s_str' % (varname), ' __attribute__ ((unused))')
|
||||||
strblock = '\n\t\t\t%s_str = argv[_i]->arg;' % (varname)
|
strblock = '\n\t\t\t%s_str = argv[_i]->arg;' % (varname)
|
||||||
argblocks.append(argblock.substitute({'varname': varname, 'strblock': strblock, 'code': code}))
|
argblocks.append(argblock.substitute({'varname': varname, 'strblock': strblock, 'code': code}))
|
||||||
|
|
||||||
@ -263,6 +292,7 @@ def process_file(fn, ofd, dumpfd, all_defun):
|
|||||||
params['argblocks'] = ''.join(argblocks)
|
params['argblocks'] = ''.join(argblocks)
|
||||||
params['canfail'] = canfail
|
params['canfail'] = canfail
|
||||||
params['nonempty'] = len(argblocks)
|
params['nonempty'] = len(argblocks)
|
||||||
|
params['argassert'] = ''.join(argassert)
|
||||||
ofd.write(templ.substitute(params))
|
ofd.write(templ.substitute(params))
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
Loading…
Reference in New Issue
Block a user