def __add_message(self, src, line, column, rule_id, msg, tag=None): """Add GNATcheck message to current session database. :param str src: Message source file. :param str line: Message line number. :param str column: Message column number. :param str rule_id: Message's rule identifier. :param str msg: Description of the message. """ # Cache the rules if rule_id in self.rules: rule = self.rules[rule_id] else: rule = GNAThub.Rule(rule_id, rule_id, GNAThub.RULE_KIND, self.tool) self.rules[rule_id] = rule # Set predefined unspecified ranking for all GNATcheck messages ranking = GNAThub.RANKING_UNSPECIFIED # Cache the messages if (rule, msg, ranking) in self.messages: message = self.messages[(rule, msg, ranking)] else: if tag: message = GNAThub.Message(rule, msg, ranking, 0, tag) else: message = GNAThub.Message(rule, msg, ranking) self.messages[(rule, msg, ranking)] = message # Add the message to the given resource self.bulk_data[src].append( [message, int(line), int(column), int(column)])
def __add_message(self, src, line, column, rule_id, msg, category): """Add GNATprove message to current session database. :param str src: message source file :param str line: message line number :param str column: message column number :param str rule_id: message rule identifier :param str msg: description of the message :param str category: the category of the message """ # Get message ranking value ranking = self.__get_ranking(category) # Cache the rules if rule_id in self.rules: rule = self.rules[rule_id] else: rule = GNAThub.Rule(rule_id, rule_id, GNAThub.RULE_KIND, self.tool) self.rules[rule_id] = rule # Cache messages if (rule, msg, ranking) in self.messages: message = self.messages[(rule, msg, ranking)] else: message = GNAThub.Message(rule, msg, ranking) self.messages[(rule, msg, ranking)] = message # Add the message to the given resource self.bulk_data[src].append( [message, int(line), int(column), int(column)])
def parse_metrics(self, node, entity=False): """Parse the xml *node* returns a list of metrics""" message_data = [] for metric in node.findall('./metric'): name = metric.attrib.get('name') if name in self.rules: rule = self.rules[name] else: rule = GNAThub.Rule(name, name, GNAThub.METRIC_KIND, self.tool) self.rules[name] = rule if (rule, metric.text, GNATmetric.RANKING) in self.messages: msg = self.messages[(rule, metric.text, GNATmetric.RANKING)] else: msg = GNAThub.Message(rule, metric.text, GNATmetric.RANKING) self.messages[(rule, metric.text, GNATmetric.RANKING)] = msg message_data.append([msg, 0, 1, 1]) return message_data
def __add_message(self, src, line, column, rule_id, msg, category, tool_msg_id, properties): """Add CodePeer message to current session database. :param str src: message source file :param str line: message line number :param str column: message column number :param str rule_id: message rule identifier :param str msg: description of the message :param str category: the category of the message :param str tool_msg_id: the original id of the message :param properties: the message properties :type properties: collections.Iterable[GNAThub.Property] or None """ # Get message ranking value ranking = self.__get_ranking(category) # Cache the rules if rule_id in self.rules: rule = self.rules[rule_id] else: rule = GNAThub.Rule(rule_id, rule_id, GNAThub.RULE_KIND, self.tool) self.rules[rule_id] = rule # Get message id from string msg_id = 0 if tool_msg_id and tool_msg_id.strip().isdigit(): msg_id = int(tool_msg_id) # Cache the messages if (rule, msg, ranking, msg_id) in self.messages: message = self.messages[(rule, msg, ranking, msg_id)] else: message = GNAThub.Message(rule, msg, ranking, msg_id, properties) self.messages[(rule, msg, ranking, msg_id)] = message # Add the message to the given resource self.bulk_data[src].append( [message, int(line), int(column), int(column)])
def parse_config(self, tree): """Parse the config block to create the GNAThub rules, if any""" config_node = tree.find('./config') if config_node is None: return self.info('retrieving metrics configuration') for metric in config_node.findall('./metric'): name = metric.attrib.get('name') display_name = metric.attrib.get('display_name') if not display_name: display_name = name if name in self.rules: rule = self.rules[name] else: rule = GNAThub.Rule(display_name, name, GNAThub.METRIC_KIND, self.tool) self.rules[name] = rule
def report(self): """Parse GNATstack output file report. Returns according to the success of the analysis: * ``GNAThub.EXEC_SUCCESS``: on successful execution and analysis * ``GNAThub.EXEC_FAILURE``: on any error """ # Clear existing references only if not incremental run if not GNAThub.incremental(): self.log.info('clear existing results if any') GNAThub.Tool.clear_references(self.name) self.info('analyse report') self.tool = GNAThub.Tool(self.name) if not os.path.exists(self.output): self.error('no report found') return GNAThub.EXEC_FAILURE self.log.debug('parse XML report: %s', self.output) # List of resource messages suitable for tool level bulk insertion resources_messages = [] # Map of list of messages by entities entities_messages_map = {} # List of entity messages suitable for tool level bulk insertion entities_messages = [] # List of indirect call location indirect_loc_list = [] try: tree = ElementTree.parse(self.output) global_node = tree.find('./global') # Retrieve the metrics and the map of subprogram by id subprograms = tree.find('./subprogramset').findall('./subprogram') if subprograms: unknown_global = GNAThub.Rule("Unknown Global Stack Usage", "Unknown Global Stack Usage", GNAThub.METRIC_KIND, self.tool) static_global = GNAThub.Rule("Static Global Stack Usage", "Static Global Stack Usage", GNAThub.METRIC_KIND, self.tool) unknown_local = GNAThub.Rule("Unknown Local Stack Usage", "Unknown Local Stack Usage", GNAThub.METRIC_KIND, self.tool) static_local = GNAThub.Rule("Static Local Stack Usage", "Static Local Stack Usage", GNAThub.METRIC_KIND, self.tool) for node in subprograms: subprogram_id = node.attrib.get('id') locations = node.find('./locationset').findall('./location') global_usage = node.find('./globalstackusage') local_usage = node.find('./localstackusage') name = node.attrib.get('prefixname') if name == "indirect call": # The columns are only defined here so save them for later line = locations[0].attrib.get('line') column = locations[0].attrib.get('column') indirect_loc_list.append([line, column]) continue else: name = self.pp_name(name) if not locations: if subprogram_id not in self.subprograms_without_location: self.subprograms_without_location[subprogram_id] = name for loc in locations: file = loc.attrib.get('file') line = loc.attrib.get('line') column = loc.attrib.get('column') if file in self.resources: resource = self.resources[file] else: resource = GNAThub.Resource(file, GNAThub.FILE_KIND) self.resources[file] = resource # entities default value for kind is set to "procedure" entity = GNAThub.Entity(name, "action", int(line), int(column), int(column), resource) # Only link the id to the first location of the entity if subprogram_id not in self.subprograms: self.subprograms[subprogram_id] = entity else: continue size = global_usage.attrib.get('size') if global_usage.attrib.get('qualifier') == "UNKNOWN": metric = unknown_global else: metric = static_global global_metric = GNAThub.Message(metric, size, ranking=GNATstack.RANKING) size = local_usage.attrib.get('size') if local_usage.attrib.get('qualifier') == "UNKNOWN": metric = unknown_local else: metric = static_local local_metric = GNAThub.Message(metric, size, ranking=GNATstack.RANKING) entities_messages_map[subprogram_id] = ([[ global_metric, 0, 1, 1 ], [local_metric, 0, 1, 1]]) # Analyse the indirect calls indirects = global_node.find('./indirectset').findall('./indirect') if indirects: indirect_rule = GNAThub.Rule("Indirect Call", "Indirect Call", GNAThub.RULE_KIND, self.tool) for node in indirects: indirect_id = node.attrib.get('id') if indirect_id not in self.subprograms: continue set = node.find('./indirectcallset').findall('./indirectcall') for call in set: line = call.find('./line').find('./value').text # Go through the list of saved locations and use the # line to retrieve a corresponding column column = 1 pos = -1 for ix in range(len(indirect_loc_list)): if indirect_loc_list[ix][0] == line: pos = ix column = indirect_loc_list[pos][1] continue if pos != -1: indirect_loc_list.pop(pos) message = GNAThub.Message(indirect_rule, self.pp_msg( indirect_id, "indirect call"), ranking=GNATstack.RANKING) entities_messages_map[indirect_id].append( [message, int(line), int(column), int(column)]) # Analyse the external calls externals = global_node.find('./externalset').findall('./external') if externals: external_rule = GNAThub.Rule("External Call", "External Call", GNAThub.RULE_KIND, self.tool) for node in externals: subprogram_id = node.attrib.get('id') if subprogram_id not in self.subprograms: continue message = GNAThub.Message(external_rule, self.pp_msg(subprogram_id, "external call"), ranking=GNATstack.RANKING) entities_messages_map[subprogram_id].append([message, 0, 1, 1]) # Analyse the potential cycle cycles = global_node.find('./cycleset').findall('./cycle') if cycles: cycle_rule = GNAThub.Rule("Potential Cycle", "Potential Cycle", GNAThub.RULE_KIND, self.tool) for node in cycles: cycle_subprograms = node.findall('./subprogram') cycle_list = [] for sub in cycle_subprograms: subprogram_id = sub.attrib.get('id') cycle_list.append(self.subprograms[subprogram_id].name) subprogram_id = cycle_subprograms[0].attrib.get('id') cycle_list.append(self.subprograms[subprogram_id].name) message = GNAThub.Message(cycle_rule, "potential cycle detected:\n\t\t" + "\n\t\t".join(cycle_list), ranking=GNATstack.RANKING) entities_messages_map[subprogram_id].append([message, 0, 1, 1]) # Analyse the unbounded frames unboundeds = ( global_node.find('./unboundedset').findall('./unbounded')) if unboundeds: unbounded_rule = GNAThub.Rule("Unbounded Frame", "Unbounded Frame", GNAThub.RULE_KIND, self.tool) for node in unboundeds: subprogram_id = node.attrib.get('id') if subprogram_id in self.subprograms: message = GNAThub.Message(unbounded_rule, self.pp_msg( subprogram_id, "unbounded frame"), ranking=GNATstack.RANKING) entities_messages_map[subprogram_id].append( [message, 0, 1, 1]) # Analyse the entry points entries = tree.find('./entryset').findall('./entry') # There is always an entry, so create the rule anyway entry_rule = GNAThub.Rule("Entry point", "Entry point", GNAThub.RULE_KIND, self.tool) for node in entries: subprogram_id = node.attrib.get('id') if subprogram_id not in self.subprograms: continue entity = self.subprograms[subprogram_id] local_stack = node.find('./localstackusage') size = local_stack.attrib.get('size') qualifier = local_stack.attrib.get('qualifier') if qualifier == "UNKNOWN": text = "The estimated" else: text = "The" text += (' call stack size for the entry point "%s" is %s' % (entity.name, str(size))) callchain_list = [] for sub in node.find('./callchain').findall('./subprogram'): chain_id = sub.attrib.get('id') if chain_id in self.subprograms: callchain_list.append(self.subprograms[chain_id].name) elif chain_id in self.subprograms_without_location: callchain_list.append( self.subprograms_without_location[chain_id]) else: continue text += (" and the callchain is:\n\t\t%s" % "\n\t\t".join(callchain_list)) message = GNAThub.Message(entry_rule, text, ranking=GNATstack.RANKING) entities_messages_map[subprogram_id].append([message, 0, 1, 1]) # Project message explaining the accuracy of the metrics accurate = global_node.find('./accurate') if accurate.find('./value').text == "FALSE": project = GNAThub.Resource(GNAThub.Project.name(), GNAThub.PROJECT_KIND) rule = GNAThub.Rule("Accuracy", "Accuracy", GNAThub.RULE_KIND, self.tool) text = ("worst case may not be accurate because of: " + ("indirect calls/" if indirects else "") + ("cycles/" if cycles else "") + ("unbounded frames/" if unboundeds else "") + ("external calls" if externals else "")) text = text[:-1] if text[-1] == '/' else text message = GNAThub.Message(rule, text, ranking=GNATstack.RANKING) resources_messages.append([project, [[message, 0, 1, 1]]]) # Insert the messages and the metrics for key, value in entities_messages_map.items(): entities_messages.append([self.subprograms[key], value]) self.tool.add_messages(resources_messages, entities_messages) except ParseError as why: self.log.exception('failed to parse XML report') self.error('%s (%s:%s)' % (why, why.filename, why.lineno)) return GNAThub.EXEC_FAILURE else: return GNAThub.EXEC_SUCCESS
def report(self): """Analyse the report files generated by :program:`Gcov`. Finds all .gcov files in the object directory and parses them. Sets the exec_status property according to the success of the analysis: * ``GNAThub.EXEC_SUCCESS``: on successful execution and analysis * ``GNAThub.EXEC_FAILURE``: on any error """ self.log.info('clear existing results if any') GNAThub.Tool.clear_references(self.name) self.info('parse coverage reports (%s)' % self.GCOV_EXT) # Handle multiple object directories if GNAThub.Project.object_dirs(): # If there are object directories defined in the project tree, look # for .gcov files there. files = [] for obj_dir in GNAThub.Project.object_dirs(): # Fetch all files in project object directories and retrieve # only .gcov files, absolute path for filename in os.listdir(obj_dir): if filename.endswith(self.GCOV_EXT): files.append(os.path.join(obj_dir, filename)) else: # If any object directory is defined in .gpr, fetch all files in # default project object directory and retrieve only .gcov files, # absolute path files = [ os.path.join(GNAThub.Project.object_dir(), filename) for filename in os.listdir(GNAThub.Project.object_dir()) if filename.endswith(self.GCOV_EXT) ] # If no .gcov file found, plugin returns on failure if not files: self.error('no %s file in object directory' % self.GCOV_EXT) return GNAThub.EXEC_FAILURE self.tool = GNAThub.Tool(self.name) self.rule = GNAThub.Rule('coverage', 'coverage', GNAThub.METRIC_KIND, self.tool) total = len(files) # List of resource messages suitable for tool level bulk insertion resources_messages = [] try: for index, filename in enumerate(files, start=1): # Retrieve source fullname (`filename` is the *.gcov report # file). base, _ = os.path.splitext(os.path.basename(filename)) src = GNAThub.Project.source_file(base) resource = GNAThub.Resource.get(src) if resource: self.__process_file(resource, filename, resources_messages) Console.progress(index, total, new_line=(index == total)) # Tool level insert for resources messages self.tool.add_messages(resources_messages, []) except IOError as why: self.log.exception('failed to parse reports') self.error(str(why)) return GNAThub.EXEC_FAILURE else: return GNAThub.EXEC_SUCCESS
import os import sys import GNAThub from support.asserts import ( assertEmpty, assertEqual, assertIsNotNone, assertNotEmpty, assertRaises ) base = GNAThub.Project.source_file('simple.adb') resource = GNAThub.Resource.get(base) assertIsNotNone(resource) tool = GNAThub.Tool('test-tool') assertIsNotNone(tool) rule = GNAThub.Rule('test-rule', 'test-rule-name', GNAThub.RULE_KIND, tool) assertIsNotNone(rule) prop0 = GNAThub.Property('test-prop-0', 'test-prop-name-0') assertIsNotNone(prop0) prop1 = GNAThub.Property('test-prop-1', 'test-prop-name-1') assertIsNotNone(prop1) msg0 = GNAThub.Message(rule, 'test message', properties=None) assertIsNotNone(msg0) assertEmpty(msg0.get_properties()) msg1 = GNAThub.Message(rule, 'test message', properties=[prop0, prop1]) assertIsNotNone(msg1) for msg in msg0, msg1: resource.add_message(msg)
def report(self): """Analyse the report files generated by :program:`GNATcoverage`. Finds all .xcov files in the object directory and parses them. Sets the exec_status property according to the success of the analysis: * ``GNAThub.EXEC_SUCCESS``: on successful execution and analysis * ``GNAThub.EXEC_FAILURE``: on any error """ # Clear existing references only if not incremental run if not GNAThub.incremental(): self.log.info('clear existing results if any') GNAThub.Tool.clear_references(self.name) # Check if gnatcoverage output folder exist if not os.path.exists(self.GNATCOVERAGE_OUTPUT): self.log.info('No gnatcoverage folder in object directory') return GNAThub.EXEC_FAILURE self.info('parse coverage reports (%s)' % self.XML_EXT) # Fetch all files in project object directory and retrieve only # .xml files, absolute path file_path = os.path.join(self.GNATCOVERAGE_OUTPUT, 'index.xml') if not os.path.exists(file_path): self.error('no index.xml file in object directory') return GNAThub.EXEC_FAILURE index_xml = minidom.parse(file_path) if not index_xml: self.error('no %s file in object directory' % self.XML_EXT) return GNAThub.EXEC_FAILURE files = index_xml.getElementsByTagName('file') self.tool = GNAThub.Tool(self.name) for cov_level in ('statement', 'decision', 'condition', 'coverage'): self.issue_rules[cov_level] = GNAThub.Rule(cov_level, cov_level, GNAThub.RULE_KIND, self.tool) total = files.length # List of resource messages suitable for tool level bulk insertion resources_messages = [] try: for index, file in enumerate(files, start=1): # Retrieve source fullname filename = file.attributes['name'].value src = GNAThub.Project.source_file(filename) resource = GNAThub.Resource.get(src) if resource: self.__process_file(resource, filename, resources_messages) Console.progress(index, total, new_line=(index == total)) # Tool level insert for resources messages self.tool.add_messages(resources_messages, []) except (IOError, ValueError) as why: self.log.exception('failed to parse reports') self.error(str(why)) return GNAThub.EXEC_FAILURE else: return GNAThub.EXEC_SUCCESS
def report(self): """Analyse the report files generated by :program:`GNATcoverage`. Finds all .xcov files in the object directory and parses them. Sets the exec_status property according to the success of the analysis: * ``GNAThub.EXEC_SUCCESS``: on successful execution and analysis * ``GNAThub.EXEC_FAILURE``: on any error """ self.log.info('clear tool references in the database') GNAThub.Tool.clear_references(self.name) self.info('parse coverage reports (%s)' % self.GNATCOV_EXT) # Fetch all files in project object directory and retrieve only # .xcov files, absolute path files = [os.path.join(GNAThub.Project.object_dir(), filename) for filename in os.listdir(GNAThub.Project.object_dir()) if filename.endswith(self.GNATCOV_EXT)] # If no .xcov file found, plugin returns on failure if not files: self.error('no %s file in object directory' % self.GNATCOV_EXT) return GNAThub.EXEC_FAILURE self.tool = GNAThub.Tool(self.name) for cov_level in ('stmt', 'decision', 'mcdc'): self.issue_rules[cov_level] = GNAThub.Rule( cov_level, cov_level, GNAThub.RULE_KIND, self.tool) total = len(files) # List of resource messages suitable for tool level bulk insertion resources_messages = [] try: for index, filename in enumerate(files, start=1): # Retrieve source fullname (`filename` is the *.xcov report # file). base, _ = os.path.splitext(os.path.basename(filename)) src = GNAThub.Project.source_file(base) resource = GNAThub.Resource.get(src) if resource: self.__process_file(resource, filename, resources_messages) Console.progress(index, total, new_line=(index == total)) # Tool level insert for resources messages self.tool.add_messages(resources_messages, []) except (IOError, ValueError) as why: self.log.exception('failed to parse reports') self.error(str(why)) return GNAThub.EXEC_FAILURE else: return GNAThub.EXEC_SUCCESS