mirror of
https://github.com/hohn/sarif-cli.git
synced 2025-12-16 17:23:03 +01:00
sarif-to-dot: move signature functions into their own module
This commit is contained in:
committed by
=Michael Hohn
parent
0444a87076
commit
edfe1f3363
152
bin/sarif-to-dot
152
bin/sarif-to-dot
@@ -4,7 +4,7 @@
|
||||
import argparse
|
||||
from dataclasses import dataclass
|
||||
import json
|
||||
import sarif_cli.traverse as S
|
||||
import sarif_cli.signature as S
|
||||
import sys
|
||||
from pprint import pprint
|
||||
|
||||
@@ -13,150 +13,6 @@ class Context:
|
||||
sig_to_typedef: dict # signature to typedef name map
|
||||
sig_count: int # simple struct counter for Struct%03d names
|
||||
|
||||
def _signature_dict(args, elem, context):
|
||||
""" Assemble and return the signature for a dictionary.
|
||||
"""
|
||||
# Collect signatures
|
||||
sig = {}
|
||||
for key, val in elem.items():
|
||||
sig[key] = _signature(args, val, context)
|
||||
# Sort signature
|
||||
keys = list(elem.keys())
|
||||
keys.sort()
|
||||
# Form and return (struct (key sig) ...)
|
||||
signature = ("struct", ) + tuple([(key, sig[key]) for key in keys])
|
||||
if args.typedef_signatures:
|
||||
# Give every unique struct a name and use a reference to it as value.
|
||||
if signature not in context.sig_to_typedef:
|
||||
context.sig_to_typedef[signature] = "Struct%03d" % context.sig_count
|
||||
context.sig_count += 1
|
||||
signature = context.sig_to_typedef[signature]
|
||||
return signature
|
||||
|
||||
def _signature_list(args, elem, context):
|
||||
""" Assemble and return the signature for a Python list.
|
||||
"""
|
||||
if args.unique_array_signatures:
|
||||
# Collect all unique signatures
|
||||
sig = set()
|
||||
for el in elem:
|
||||
sig.add(_signature(args, el, context))
|
||||
sig = list(sig)
|
||||
sig.sort()
|
||||
signature = ("array", ) + tuple([(i, s) for (i, s) in enumerate(sig)])
|
||||
else:
|
||||
# Collect all signatures
|
||||
sig = []
|
||||
for el in elem:
|
||||
sig.append(_signature(args, el, context))
|
||||
signature = ("array", ) + tuple([(i, s) for (i, s) in enumerate(sig)])
|
||||
if args.typedef_signatures:
|
||||
# Give every unique array a name and use a reference to it as value.
|
||||
if signature not in context.sig_to_typedef:
|
||||
context.sig_to_typedef[signature] = "Array%03d" % context.sig_count
|
||||
context.sig_count += 1
|
||||
signature = context.sig_to_typedef[signature]
|
||||
return signature
|
||||
|
||||
def _signature(args, elem, context):
|
||||
""" Assemble and return the signature for a list/dict/value structure.
|
||||
"""
|
||||
t = type(elem)
|
||||
if t == dict:
|
||||
return _signature_dict(args, elem, context)
|
||||
elif t == list:
|
||||
return _signature_list(args, elem, context)
|
||||
elif t == str:
|
||||
if args.typedef_signatures:
|
||||
return context.sig_to_typedef["string"]
|
||||
return ("string")
|
||||
elif t == int:
|
||||
if args.typedef_signatures:
|
||||
return context.sig_to_typedef["int"]
|
||||
return ("int")
|
||||
elif t == bool:
|
||||
if args.typedef_signatures:
|
||||
return context.sig_to_typedef["bool"]
|
||||
return ("bool")
|
||||
else:
|
||||
return ("unknown", elem)
|
||||
|
||||
def write_header(fp):
|
||||
fp.write("""digraph sarif_types {
|
||||
node [shape=box,fontname="Charter"];
|
||||
graph [rankdir = "LR"];
|
||||
edge [];
|
||||
""")
|
||||
# Alternative font choices:
|
||||
# node [shape=box,fontname="Avenir"];
|
||||
# node [shape=box,fontname="Enriqueta Regular"];
|
||||
|
||||
|
||||
def write_footer(fp):
|
||||
fp.write("}")
|
||||
|
||||
#
|
||||
# These are internal node format samples, as (typedef, sig) tuples:
|
||||
#
|
||||
# ('String', 'string'),
|
||||
# ('Int', 'int'),
|
||||
# ('Bool', 'bool'),
|
||||
# ('Struct000', ('struct', ('text', 'String'))),
|
||||
# ('Struct001', ('struct', ('enabled', 'Bool'), ('level', 'String'))),
|
||||
# ( 'Struct002',
|
||||
# ( 'struct',
|
||||
# ('kind', 'String'),
|
||||
# ('precision', 'String'),
|
||||
# ('severity', 'String'),
|
||||
# ('tags', ('array', 'String')))),
|
||||
#
|
||||
def write_node(fp, typedef, sig):
|
||||
""" Write nodes in dot format.
|
||||
"""
|
||||
if sig in ["string", "int", "bool"]:
|
||||
label = sig
|
||||
elif sig[0] == "array":
|
||||
label = "\l|".join([ "<%s>%s" % (field[0],field[0]) for field in sig[1:]])
|
||||
elif sig[0] == "struct":
|
||||
label = "\l|".join([ "<%s>%s" % (field[0],field[0]) for field in sig[1:]])
|
||||
else:
|
||||
raise Exception("unknown signature: " + str(sig))
|
||||
node = """ "{name}" [
|
||||
label = "{head}\l|{body}\l"
|
||||
shape = "record"
|
||||
];
|
||||
""".format(name=typedef, head=typedef, body=label)
|
||||
fp.write(node)
|
||||
|
||||
# See format samples above write_node
|
||||
def write_edges(fp, typedef, sig):
|
||||
""" Write edges in dot format.
|
||||
"""
|
||||
if sig in ["string", "int", "bool"]:
|
||||
pass
|
||||
elif sig[0] in ("struct", "array"):
|
||||
# Sample struct:
|
||||
# ( struct
|
||||
# (semmle.formatSpecifier string)
|
||||
# (semmle.sourceLanguage string))
|
||||
#
|
||||
# Sample array:
|
||||
# ( array
|
||||
# ( 0
|
||||
# ( struct
|
||||
# (repositoryUri string)
|
||||
# (revisionId string))))
|
||||
for field in sig[1:]:
|
||||
field_name, field_type = field
|
||||
label = ""
|
||||
dest = str(field_type)
|
||||
edge = """ {src_node}:"{src_port}" -> {dest} [label="{label}"];
|
||||
""".format(src_node=typedef, src_port=field_name, dest=field_type,
|
||||
label=label)
|
||||
fp.write(edge)
|
||||
else:
|
||||
raise Exception("unknown signature: " + str(sig))
|
||||
|
||||
#
|
||||
# Start processing
|
||||
#
|
||||
@@ -185,7 +41,7 @@ with open(args.file, 'r') if args.file != '-' else sys.stdin as fp:
|
||||
sarif_struct = json.load(fp)
|
||||
|
||||
if args.dot_output:
|
||||
_signature(args, sarif_struct, context)
|
||||
S._signature(args, sarif_struct, context)
|
||||
struct_graph = [(typedef, sig) for sig, typedef in context.sig_to_typedef.items()]
|
||||
write_header(sys.stdout)
|
||||
for typedef, sig in struct_graph:
|
||||
@@ -195,8 +51,8 @@ if args.dot_output:
|
||||
write_footer(sys.stdout)
|
||||
|
||||
elif args.typedef_signatures:
|
||||
_signature(args, sarif_struct, context)
|
||||
S._signature(args, sarif_struct, context)
|
||||
struct_graph = [(typedef, sig) for sig,typedef in context.sig_to_typedef.items()]
|
||||
pprint(struct_graph, sys.stdout, indent=2)
|
||||
else:
|
||||
pprint(_signature(args, sarif_struct, context), sys.stdout, indent=2)
|
||||
pprint(S._signature(args, sarif_struct, context), sys.stdout, indent=2)
|
||||
|
||||
Reference in New Issue
Block a user