Fix: handle relatedLocations without physicalLocations (files)

Problem:
    The
        artifact = get(related_location, 'physicalLocation', 'artifactLocation')
    requested by
        message, artifact, region = S.get_relatedlocation_message_info(location)
    is incomplete:
        ipdb> p related_location
        {'message': {'text': 'request'}}

Fix:
    Introduce the NoFile class to propagate this and handle it where needed.

Now simply report <NoFile> as appropriate.
    For plain text output:

        RESULT: src/optionsparser/ ..
        FLOW STEP 0: <NoFile>: request
        FLOW STEP 1: <NoFile>: request_mp
        FLOW STEP 2: src/....

    For csv output:

        "result","src/optionsparser/...","116","26","116","34","`& ...` used as ..."
        "flow_step","0","<NoFile>","-1","-1","-1","-1","request"
        "flow_step","1","<NoFile>","-1","-1","-1","-1","request_mp"
        "flow_step","2","src/foo.cpp","119","97","119","104","request"
This commit is contained in:
Michael Hohn
2021-12-06 12:37:35 -08:00
committed by =Michael Hohn
parent 2c3ca3c0eb
commit 120e673424
2 changed files with 54 additions and 29 deletions

View File

@@ -57,19 +57,25 @@ for runi in S.indices(sarif_struct, 'runs'):
# Linking is explicit in output, so no need to get id(s) from message string.
for relo in relatedLocations:
message, artifact, region = S.get_relatedlocation_message_info(relo)
l1, c1, l2, c2 = S.lineinfo(region)
filepath = "%s:%d:%d:%d:%d" % (artifact['uri'], l1, c1, l2, c2)
if args.csv:
S.write_csv(cw, "result", artifact['uri'], l1, c1, l2, c2, message)
else:
S.msg("REFERENCE: %s: %s\n\n" % (filepath, message))
if args.list_source:
lines = S.load_lines(args.list_source, artifact['uri'], l1, l2)
if artifact == S.NoFile:
if args.csv:
pass
S.write_csv(cw, "result", "", -1, -1, -1, -1, message)
else:
for line, line_num in zip(lines, range(l1, l2+1)):
S.display_underlined(l1, c1, l2, c2, line, line_num)
S.msg("REFERENCE: %s: %s\n\n" % ("<NoFile>", message))
else:
l1, c1, l2, c2 = S.lineinfo(region)
filepath = "%s:%d:%d:%d:%d" % (artifact['uri'], l1, c1, l2, c2)
if args.csv:
S.write_csv(cw, "result", artifact['uri'], l1, c1, l2, c2, message)
else:
S.msg("REFERENCE: %s: %s\n\n" % (filepath, message))
if args.list_source:
lines = S.load_lines(args.list_source, artifact['uri'], l1, l2)
if args.csv:
pass
else:
for line, line_num in zip(lines, range(l1, l2+1)):
S.display_underlined(l1, c1, l2, c2, line, line_num)
if 'codeFlows' in result:
# Path problems
for codeFlow in S.get(result, 'codeFlows'):
@@ -77,19 +83,25 @@ for runi in S.indices(sarif_struct, 'runs'):
for loci in S.indices(threadFlow, 'locations'):
location = S.get(threadFlow, 'locations', loci, 'location')
message, artifact, region = S.get_relatedlocation_message_info(location)
l1, c1, l2, c2 = S.lineinfo(region)
filepath = "%s:%d:%d:%d:%d" % (artifact['uri'], l1, c1, l2, c2)
if args.csv:
S.write_csv(cw, "flow_step", loci, artifact['uri'], l1, c1, l2, c2, message)
else:
S.msg("FLOW STEP %d: %s: %s\n\n" % (loci, filepath, message))
if args.list_source:
lines = S.load_lines(args.list_source, artifact['uri'], l1, l2)
if artifact == S.NoFile:
if args.csv:
pass
S.write_csv(cw, "flow_step", loci, "<NoFile>", -1, -1, -1, -1, message)
else:
for line, line_num in zip(lines, range(l1, l2+1)):
S.display_underlined(l1, c1, l2, c2, line, line_num)
S.msg("FLOW STEP %d: %s: %s\n\n" % (loci, "<NoFile>", message))
else:
l1, c1, l2, c2 = S.lineinfo(region)
filepath = "%s:%d:%d:%d:%d" % (artifact['uri'], l1, c1, l2, c2)
if args.csv:
S.write_csv(cw, "flow_step", loci, artifact['uri'], l1, c1, l2, c2, message)
else:
S.msg("FLOW STEP %d: %s: %s\n\n" % (loci, filepath, message))
if args.list_source:
lines = S.load_lines(args.list_source, artifact['uri'], l1, l2)
if args.csv:
pass
else:
for line, line_num in zip(lines, range(l1, l2+1)):
S.display_underlined(l1, c1, l2, c2, line, line_num)
if args.csv:
pass
else:

View File

@@ -8,6 +8,16 @@ MIN_PYTHON = (3, 7)
if sys.version_info < MIN_PYTHON:
sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON)
class WholeFile:
""" Special case handling: use this class for non-existent regions where the
whole file is to be used.
"""
class NoFile:
""" Special case handling: use this class for non-existent regions where the
whole file is to be used.
"""
def get_csv_writer():
""" Set up and return the default csv writer on stdout.
"""
@@ -23,19 +33,22 @@ def get_relatedlocation_message_info(related_location):
The relatedLocation typically starts from
get(sarif_struct, 'runs', [int], 'results', [int], 'relatedLocations', [int])
For a threadFlow, extract message information for a location contained in it.
When used for a threadFlow, extract message information for a location contained in it.
The location typically starts from
In this case, the location typically starts from
get(sarif_struct, 'runs', _i, 'results', _i, 'codeFlows', _i, 'threadFlows', _i, 'locations', _i)
Returns: (message, artifact, region) by default
For an empty 'physicalLocation' key, returns (message, sarif_cli.NoFile, sarif_cli.NoFile)
"""
message = get(related_location, 'message', 'text')
artifact = get(related_location, 'physicalLocation', 'artifactLocation')
region = get(related_location, 'physicalLocation', 'region')
if 'physicalLocation' in related_location:
artifact = get(related_location, 'physicalLocation', 'artifactLocation')
region = get(related_location, 'physicalLocation', 'region')
else:
artifact, region = NoFile, NoFile
return message, artifact, region
class WholeFile:
pass
def get_location_message_info(result):
""" Given one of the results, extract message information.