Пример #1
0
    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)])
Пример #2
0
    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)])
Пример #3
0
    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
Пример #4
0
    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)])
Пример #5
0
    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
Пример #6
0
    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
Пример #7
0
    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
Пример #8
0
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)
Пример #9
0
    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
Пример #10
0
    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