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")
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
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]
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")
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"]
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__)))
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__)
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
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__)
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
def worst_offender_count(worst_offenders): for metric in worst_offenders: return len(worst_offenders[metric]) raise ICE("cannot determine length of wo table")
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)
def register_file(self): raise ICE("somhow called root class method")
def get_content(self): raise ICE("somhow called root class method")
def write_modified(self, content): raise ICE("logic error - must not be called for SL File WP")
def write_modified(self, content): raise ICE("somhow called root class method")