Beispiel #1
0
    def parse_metric_entry(self, cfg):
        self.match("IDENTIFIER", "metric")

        self.match("STRING")
        metric_name = self.ct.value

        if metric_name in config.METRICS:
            metric_info = config.METRICS[metric_name]
        else:
            self.mh.error(self.ct.location,
                          "unknown metric '%s'" % metric_name)

        self.match("COLON")

        self.match("IDENTIFIER")
        if self.ct.value == "limit":
            self.match("NUMBER")
            if metric_info["type"] != "int":
                raise ICE("logic error: metric that is not an int")

            try:
                value = int(self.ct.value)
            except ValueError:
                self.mh.error(self.ct.location, "expected positive integer")
            if value < 0:
                self.mh.error(self.ct.location, "expected positive integer")

            cfg["metrics"][metric_name] = {"max": value}

        elif self.ct.value == "report":
            if metric_name in cfg["metrics"]:
                del cfg["metrics"][metric_name]

        else:
            self.mh.error(self.ct.location, "expected report or limit")
Beispiel #2
0
def function_length(node):
    assert isinstance(node, (Function_Definition, Script_File))

    if isinstance(node, Script_File):
        return None

    elif node.t_end:
        return node.t_end.location.line - node.t_fun.location.line + 1

    else:
        # If a function does not have an end, its length is from this
        # function up to and including the next function or the end of
        # the file
        n_cu = node.n_parent
        if not isinstance(n_cu, Function_File):
            raise ICE("unterminated function must be a child of a "
                      "function file")

        this_function_idx = n_cu.l_functions.index(node)
        next_function_idx = this_function_idx + 1

        if next_function_idx < len(n_cu.l_functions):
            # We have a function following this one
            return (n_cu.l_functions[next_function_idx].t_fun.location.line -
                    node.t_fun.location.line)

        else:
            # This is the last function in the file
            return n_cu.file_length - node.t_fun.location.line + 1
Beispiel #3
0
    def get_named_vertex(self, name):
        assert isinstance(name, str)

        if name not in self.names:
            raise ICE("attempted to get named vertex %s that"
                      " does not exists" % name)

        return self.names[name]
Beispiel #4
0
    def parse_metric_entry(self, cfg):
        self.match("IDENTIFIER", "metric")

        if self.peek("OPERATOR", "*"):
            self.match("OPERATOR", "*")
            metric_name = None
        else:
            self.match("STRING")
            metric_name = self.ct.value

            if metric_name in config.METRICS:
                metric_info = config.METRICS[metric_name]
            else:
                self.mh.error(self.ct.location,
                              "unknown metric '%s'" % metric_name)

        self.match("COLON")

        self.match("IDENTIFIER")
        if self.ct.value == "limit":
            if metric_name is None:
                self.mh.error(self.ct.location,
                              "cannot specify limit for all metrics"
                              " simultaneously")

            self.match("NUMBER")
            if metric_info["type"] != "int":
                raise ICE("logic error: metric that is not an int")

            try:
                value = int(self.ct.value)
            except ValueError:
                self.mh.error(self.ct.location,
                              "expected positive integer")
            if value < 0:
                self.mh.error(self.ct.location,
                              "expected positive integer")

            cfg["metrics"][metric_name] = {"max" : value}

        elif self.ct.value == "disable":
            if metric_name is None:
                cfg["metrics"] = {m: {"disable": True}
                                  for m in config.METRICS}
            else:
                cfg["metrics"][metric_name] = {"disable": True}

        elif self.ct.value == "report":
            if metric_name is None:
                cfg["metrics"] = {}
            else:
                if metric_name in cfg["metrics"]:
                    del cfg["metrics"][metric_name]

        else:
            self.mh.error(self.ct.location,
                          "expected report or limit")
Beispiel #5
0
def get_config(filename):
    dirname = os.path.dirname(os.path.abspath(filename))

    if dirname not in CONFIG_TREE:
        if not os.path.isdir(dirname):
            hint = " (note: this is not a directory)"
        else:
            hint = ""
        raise ICE("%s: expected %s to be in configuration tree%s" %
                  (filename, dirname, hint))

    return CONFIG_TREE[dirname]["config"]
Beispiel #6
0
    def rec(root):
        is_leaf = True
        for subclass in root.__subclasses__():
            rec(subclass)
            is_leaf = False

        if is_leaf:
            if issubclass(root, Style_Rule_File):
                rules["on_file"].append(root)
            elif issubclass(root, Style_Rule_Line):
                rules["on_line"].append(root)
            else:
                raise ICE(
                    "Unable to categorize %s with base %s" %
                    (root.__name__, " and ".join(b.__name__
                                                 for b in root.__bases__)))
Beispiel #7
0
def npath(node):
    assert isinstance(node, (Sequence_Of_Statements, Statement, Pragma,
                             Function_Definition, Script_File))

    if isinstance(node, Function_Definition):
        return npath(node.n_body)

    elif isinstance(node, Script_File):
        return npath(node.n_statements)

    elif isinstance(node, Sequence_Of_Statements):
        paths = 1
        for n_statement in node.l_statements:
            if isinstance(n_statement,
                          (If_Statement, For_Loop_Statement, Switch_Statement,
                           Try_Statement, While_Statement)):
                paths *= npath(n_statement)
        return paths

    elif isinstance(node, If_Statement):
        paths = 0
        for n_action in node.l_actions:
            paths += npath(n_action.n_body)
        if not node.has_else:
            paths += 1

        return paths

    elif isinstance(node, Switch_Statement):
        paths = 0
        for n_action in node.l_actions:
            paths += npath(n_action.n_body)
        if not node.has_otherwise:
            paths += 1

        return paths

    elif isinstance(node, (For_Loop_Statement, While_Statement)):
        return 1 + npath(node.n_body)

    elif isinstance(node, Try_Statement):
        return npath(node.n_body) * 2

    else:
        raise ICE("unexpected node %s" % node.__class__.__name__)
Beispiel #8
0
    def __init__(self, graph, name=None):
        assert isinstance(graph, Graph)
        assert name is None or isinstance(name, str)

        self.graph = graph
        self.out_edges = set()
        self.in_edges = set()
        self.name = name

        # Register vertex with host graph
        self.graph.vertices.add(self)

        # Register named vertex
        if name:
            if name in graph.names:
                raise ICE("attempted to create named vertex %s that"
                          " already exists" % name)
            self.graph.names[name] = self
Beispiel #9
0
def cnest(node):
    assert isinstance(node, (Sequence_Of_Statements, Statement, Pragma,
                             Function_Definition, Script_File))

    if isinstance(node, Function_Definition):
        return cnest(node.n_body)

    elif isinstance(node, Script_File):
        return cnest(node.n_statements)

    elif isinstance(node, Sequence_Of_Statements):
        return max(map(cnest, node.l_statements), default=0)

    elif isinstance(node, (Simple_Statement, Pragma)):
        return 0

    elif isinstance(node, SPMD_Statement):
        return cnest(node.n_body)

    elif isinstance(node, If_Statement):
        return 1 + max((cnest(a.n_body) for a in node.l_actions), default=0)

    elif isinstance(node, Switch_Statement):
        return 1 + max((cnest(a.n_body) for a in node.l_actions), default=0)

    elif isinstance(node, (For_Loop_Statement, While_Statement)):
        return 1 + cnest(node.n_body)

    elif isinstance(node, Try_Statement):
        if node.n_handler:
            return 1 + max(cnest(node.n_body), cnest(node.n_handler))
        else:
            return 1 + cnest(node.n_body)

    else:
        raise ICE("unexpected node %s" % node.__class__.__name__)
Beispiel #10
0
def build_cfg_statement(graph, n_statement):
    assert isinstance(graph, Graph)
    assert isinstance(n_statement, (Statement, Metric_Justification_Pragma))

    ctx = CFG_Context(Vertex(graph, n_statement))

    if isinstance(
            n_statement,
        (Compound_Assignment_Statement, Global_Statement, Import_Statement,
         Naked_Expression_Statement, Persistent_Statement,
         Simple_Assignment_Statement, Metric_Justification_Pragma)):
        # All of these are simple statements. One entry, one obvious
        # exit.
        ctx.l_exits.append(ctx.v_entry)

    elif isinstance(n_statement, If_Statement):
        # If statements chain together the actions.
        current_link = ctx.v_entry
        for n_action in n_statement.l_actions:
            v_action = Vertex(graph, n_action)
            graph.add_edge(current_link, v_action)
            current_link = v_action

            action_ctx = build_cfg_sos(graph, n_action.n_body)
            ctx.merge_loops(action_ctx)
            ctx.merge_exits(action_ctx)
            if action_ctx.v_entry:
                graph.add_edge(v_action, action_ctx.v_entry)

        if not n_statement.has_else:
            # Add an implicit path for else, if not present
            ctx.l_exits.append(current_link)

    elif isinstance(n_statement, Switch_Statement):
        # Case statements in MATLAB are chained, because there is no
        # semantic check that the options do not overlap; hence they
        # must be evaluated in sequence. This is the same as above. In
        # the future, for the MISS_HIT subset, we could make sure
        # there is no overlap.

        current_link = ctx.v_entry
        for n_action in n_statement.l_actions:
            v_action = Vertex(graph, n_action)
            graph.add_edge(current_link, v_action)
            current_link = v_action

            action_ctx = build_cfg_sos(graph, n_action.n_body)
            ctx.merge_loops(action_ctx)
            ctx.merge_exits(action_ctx)
            if action_ctx.v_entry:
                graph.add_edge(v_action, action_ctx.v_entry)

        if not n_statement.has_otherwise:
            # Add an implicit path for otherwise, if not present
            ctx.l_exits.append(current_link)

    elif isinstance(n_statement, (For_Loop_Statement, While_Statement)):
        # Loops add a loop back to the loop statement. There are two
        # paths out of the loop statement: one into the loop and one
        # to the next statement.
        #
        # Any break statements found in the body are processed here.
        body_ctx = build_cfg_sos(graph, n_statement.n_body)

        if body_ctx.v_entry:
            graph.add_edge(ctx.v_entry, body_ctx.v_entry)

        for src in body_ctx.l_exits:
            graph.add_edge(src, ctx.v_entry)
        for src in body_ctx.l_loop_continues:
            graph.add_edge(src, ctx.v_entry)

        ctx.l_exits = [ctx.v_entry] + ctx.l_loop_breaks

    elif isinstance(n_statement, Break_Statement):
        ctx.l_loop_breaks.append(ctx.v_entry)

    elif isinstance(n_statement, Continue_Statement):
        ctx.l_loop_continues.append(ctx.v_entry)

    elif isinstance(n_statement, Return_Statement):
        graph.add_edge(ctx.v_entry, graph.get_named_vertex("end"))

    elif isinstance(n_statement, SPMD_Statement):
        spmd_ctx = build_cfg_sos(graph, n_statement.n_body)
        ctx.merge_loops(spmd_ctx)
        ctx.merge_exits(spmd_ctx)

        if spmd_ctx.v_entry:
            graph.add_edge(ctx.v_entry, spmd_ctx.v_entry)

    elif isinstance(n_statement, Try_Statement):
        try_ctx = build_cfg_sos(graph, n_statement.n_body)
        ctx.merge_loops(try_ctx)
        ctx.merge_exits(try_ctx)

        if n_statement.n_handler:
            handler_ctx = build_cfg_sos(graph, n_statement.n_handler)
            ctx.merge_loops(handler_ctx)
            ctx.merge_exits(handler_ctx)
            if handler_ctx.v_entry:
                graph.add_edge(ctx.v_entry, handler_ctx.v_entry)
        else:
            ctx.l_exits.append(ctx.v_entry)

        if try_ctx.v_entry:
            graph.add_edge(ctx.v_entry, try_ctx.v_entry)

    else:
        raise ICE("unknown statement kind %s" % n_statement.__class__.__name__)

    return ctx
Beispiel #11
0
def worst_offender_count(worst_offenders):
    for metric in worst_offenders:
        return len(worst_offenders[metric])
    raise ICE("cannot determine length of wo table")
Beispiel #12
0
def build_config_tree(mh, cmdline_options):
    # Construct basic default options
    root_config = deepcopy(config.BASE_CONFIG)

    # Find root of config tree
    roots = [d for d in CONFIG_TREE if CONFIG_TREE[d]["root"]]
    if len(roots) == 0:
        raise ICE("could not find any project or filesystem root")
    elif len(roots) == 1:
        project_root = roots[0]
    elif len(roots) > 1:
        raise ICE("found multiple roots: %s" % ", ".join(roots))

    parse_config = not cmdline_options.ignore_config

    def merge_command_line(cfg):
        # Thse options exist for all tools
        if cmdline_options.octave:
            cfg["octave"] = cmdline_options.octave
        if cmdline_options.ignore_pragmas:
            cfg["ignore_pragmas"] = cmdline_options.ignore_pragmas

        # Overwrite some options from the command-line for style
        # checking
        if "line_length" in cmdline_options and \
           cmdline_options.line_length:
            cfg["line_length"] = cmdline_options.line_length
        if "file_length" in cmdline_options and \
           cmdline_options.file_length:
            cfg["file_length"] = cmdline_options.file_length
        if "tab_width" in cmdline_options and \
           cmdline_options.tab_width:
            cfg["tab_width"] = cmdline_options.tab_width
        if "copyright_entity" in cmdline_options and \
           cmdline_options.copyright_entity:
            cfg["copyright_entity"] = set(cmdline_options.copyright_entity)

    def build(node, exclude=False):
        if CONFIG_TREE[node]["root"]:
            # First we set up basic config. For roots this is a copy
            # of the default config.
            CONFIG_TREE[node]["config"] = deepcopy(root_config)
            merge_command_line(CONFIG_TREE[node]["config"])
        else:
            # For non-roots we copy the parent config.
            parent_node = CONFIG_TREE[node]["parent"]
            parent_config = CONFIG_TREE[parent_node]["config"]
            CONFIG_TREE[node]["config"] = deepcopy(parent_config)

            # We reset the exclude_dir field as it makes no sense to
            # propagate it.
            CONFIG_TREE[node]["config"]["exclude_dir"] = set()

        # We now have basic configuration for this node. If we're in
        # exclude mode we just set enable to false for this node.
        if exclude:
            CONFIG_TREE[node]["config"]["enable"] = False

        # Otherwise we process any config file
        elif CONFIG_TREE[node]["has_config"] and parse_config:
            load_config(mh,
                        os.path.join(node, CONFIG_TREE[node]["has_config"]),
                        CONFIG_TREE[node]["config"])
            merge_command_line(CONFIG_TREE[node]["config"])

        # Finally, loop over all children to continue building the
        # tree.
        for child in CONFIG_TREE[node]["children"]:
            to_exclude = (exclude or
                          os.path.basename(child) in
                          CONFIG_TREE[node]["config"]["exclude_dir"])
            build(child, exclude=to_exclude)

    build(project_root, exclude=False)
Beispiel #13
0
 def register_file(self):
     raise ICE("somhow called root class method")
Beispiel #14
0
 def get_content(self):
     raise ICE("somhow called root class method")
Beispiel #15
0
 def write_modified(self, content):
     raise ICE("logic error - must not be called for SL File WP")
Beispiel #16
0
 def write_modified(self, content):
     raise ICE("somhow called root class method")