Beispiel #1
0
    def process_wp(cls, wp):
        # Create lexer
        lexer = MATLAB_Lexer(wp.mh,
                             wp.get_content(),
                             wp.filename,
                             wp.blockname)
        if wp.cfg.octave:
            lexer.set_octave_mode()
        if not wp.cfg.pragmas:
            lexer.process_pragmas = False
        if len(lexer.text.strip()) == 0:
            return MH_Trace_Result(wp)

        # Create parse tree
        try:
            parser = MATLAB_Parser(wp.mh, lexer, wp.cfg)
            n_cu = parser.parse_file()
            n_ep = get_enclosing_ep(wp.filename)
        except Error:
            return MH_Trace_Result(wp)

        visitor = Function_Visitor(wp.in_test_dir, wp.mh, n_cu, n_ep)
        n_cu.visit(None, visitor, "Root")

        # Return results
        return MH_Trace_Result(wp, visitor.tracing)
Beispiel #2
0
    def process_wp(cls, wp):
        # Create lexer
        lexer = MATLAB_Lexer(wp.mh,
                             wp.get_content(),
                             wp.filename,
                             wp.blockname)
        if wp.cfg.octave:
            lexer.set_octave_mode()
        if not wp.cfg.pragmas:
            lexer.process_pragmas = False
        if len(lexer.text.strip()) == 0:
            return MH_BMC_Result(wp)

        # Create parse tree and translate
        try:
            parser = MATLAB_Parser(wp.mh, lexer, wp.cfg)
            n_tree = parser.parse_file()
            gst = compile_file(wp.mh, n_tree)
        except Error:
            return MH_BMC_Result(wp)

        new_filename = wp.filename.replace(".m", ".json_symtab")
        with open(new_filename, "w") as fd:
            json.dump(gst.to_json(), fd, indent=2)
        # wp.mh.info(n_tree.loc(),
        #            "wrote goto symbol table to %s" % new_filename)

        analyze(wp.mh, new_filename, lexer, n_tree)

        if not wp.options.keep:
            os.unlink(new_filename)

        return MH_BMC_Result(wp)
Beispiel #3
0
    def process_wp(cls, wp):
        # Create lexer
        lexer = MATLAB_Lexer(wp.mh, wp.get_content(), wp.filename,
                             wp.blockname)
        if wp.cfg.octave:
            lexer.set_octave_mode()
        if not wp.cfg.pragmas:
            lexer.process_pragmas = False
        if len(lexer.text.strip()) == 0:
            return MH_Lint_Result(wp)

        # Create parse tree
        try:
            parser = MATLAB_Parser(wp.mh, lexer, wp.cfg)
            parser.parse_file()
        except Error:
            return MH_Lint_Result(wp)

        return MH_Lint_Result(wp)
Beispiel #4
0
    def process_wp(cls, wp):
        # Create lexer
        lexer = MATLAB_Lexer(wp.mh, wp.get_content(), wp.filename,
                             wp.blockname)
        if wp.cfg.octave:
            lexer.set_octave_mode()
        if not wp.cfg.pragmas:
            lexer.process_pragmas = False
        if len(lexer.text.strip()) == 0:
            return MH_Lint_Result(wp)

        # Create parse tree
        try:
            parser = MATLAB_Parser(wp.mh, lexer, wp.cfg)
            n_cu = parser.parse_file()
        except Error:
            return MH_Lint_Result(wp)

        # Check compilation units for shadowing a built-in
        base_name = os.path.splitext(n_cu.name)[0]
        dir_name = os.path.basename(
            os.path.dirname(pathutil.abspath(wp.filename)))
        if wp.cfg.active("builtin_shadow") and \
           base_name in BUILTIN_FUNCTIONS and \
           not (dir_name.startswith("+") or dir_name.startswith("@")):
            wp.mh.check(
                n_cu.loc(),
                "this file shadows built-in %s which is very naughty" %
                base_name, "high")

        # Initial checks
        n_cu.visit(None, Stage_1_Linting(wp.mh), "Root")

        # First pass of semantic analysis
        entrypoint = cfg_tree.get_entry_point(wp.options.entry_point)
        sem = sem_pass_1(wp.mh, entrypoint, n_cu)

        return MH_Lint_Result(wp, sem)
Beispiel #5
0
    def process_wp(cls, wp):
        if wp.blockname is None:
            full_name = wp.filename
        else:
            full_name = wp.filename + "/" + wp.blockname

        metrics = {
            full_name: {
                "errors"    : False,
                "metrics"   : {},
                "functions" : {},
                "disabled"  : set(m for m in config.METRICS
                                  if not wp.cfg.metric_enabled(m))
            }
        }
        justifications = {}

        # Create lexer

        lexer = MATLAB_Lexer(wp.mh, wp.get_content(),
                             wp.filename, wp.blockname)
        if wp.cfg.octave:
            lexer.set_octave_mode()
        if not wp.cfg.pragmas:
            lexer.process_pragmas = False

        # We're dealing with an empty file here. Lets just not do anything

        if len(lexer.text.strip()) == 0:
            return MH_Metric_Result(wp, metrics)

        # Create parse tree

        try:
            parser = MATLAB_Parser(wp.mh, lexer, wp.cfg)
            parse_tree = parser.parse_file()
        except Error:
            metrics[wp.filename]["errors"] = True
            return MH_Metric_Result(wp, metrics)

        # Collect file metrics

        if wp.cfg.metric_enabled("file_length"):
            metrics[full_name]["metrics"]["file_length"] = {
                "measure" : lexer.line_count(),
                "limit"   : None,
                "reason"  : None,
                "tickets" : set(),
            }

        # Check+justify file metrics

        justifications = {full_name : get_file_justifications(wp.mh,
                                                              parse_tree)}
        for file_metric in config.FILE_METRICS:
            check_metric(wp.mh, wp.cfg, lexer.get_file_loc(), file_metric,
                         metrics[full_name]["metrics"],
                         justifications[full_name])

        # Collect, check, and justify function metrics

        metrics[full_name]["functions"] = get_function_metrics(wp.mh,
                                                               wp.cfg,
                                                               parse_tree)

        # Complain about unused justifications

        warn_unused_justifications(wp.mh, parse_tree)

        return MH_Metric_Result(wp, metrics)
Beispiel #6
0
    def process_wp(cls, wp):
        rule_set = wp.extra_options["rule_set"]
        autofix = wp.options.fix
        fd_tree = wp.extra_options["fd_tree"]
        debug_validate_links = wp.options.debug_validate_links

        # Build rule library

        rule_lib = build_library(wp.cfg, rule_set)

        # Load file content

        content = wp.get_content()

        # Create lexer

        lexer = MATLAB_Lexer(wp.mh, content, wp.filename, wp.blockname)
        if wp.cfg.octave:
            lexer.set_octave_mode()
        if not wp.cfg.pragmas:
            lexer.process_pragmas = False

        # We're dealing with an empty file here. Lets just not do anything

        if len(lexer.text.strip()) == 0:
            return MH_Style_Result(wp)

        # Stage 1 - rules around the file itself

        for rule in rule_lib["on_file"]:
            rule.apply(wp.mh, wp.cfg, lexer.filename, lexer.text,
                       lexer.context_line)

        # Stage 2 - rules around raw text lines

        for line_no, line in enumerate(lexer.context_line, 1):
            for rule in rule_lib["on_line"]:
                rule.apply(wp.mh, wp.cfg, lexer.filename, line_no, line)

        # Tabs are just super annoying, and they require special
        # treatment. There is a known but obscure bug here, in that tabs
        # in strings are replaced as if they were part of normal
        # text. This is probably not intentional. For example:
        #
        # "a<tab>b"
        #    "a<tab>b"
        #
        # Will right now come out as
        #
        # "a   b"
        # "  a b"
        #
        # This is probably not correct. Fixing this is will require a very
        # different kind of lexing (which I am not in the mood for, I have
        # suffered enough to deal with ') or a 2-pass solution (which is
        # slow): first we lex and then fix up tabs inside tokens; and then
        # we do the global replacement and lex again before we proceed.

        if autofix:
            lexer.correct_tabs(wp.cfg.style_config["tab_width"])

        # Create tokenbuffer

        try:
            tbuf = Token_Buffer(lexer, wp.cfg)
        except Error:
            # If there are lex errors, we can stop here
            return MH_Style_Result(wp)

        # Create parse tree

        try:
            parser = MATLAB_Parser(wp.mh, tbuf, wp.cfg)
            parse_tree = parser.parse_file()

            # Check naming (we do this after parsing, not during,
            # since we may need to re-write functions without end).
            parse_tree.sty_check_naming(wp.mh, wp.cfg)

            if debug_validate_links:
                tbuf.debug_validate_links()

            if fd_tree:
                fd_tree.write("-- Parse tree for %s\n" % wp.filename)
                parse_tree.pp_node(fd_tree)
                fd_tree.write("\n\n")

        except Error:
            parse_tree = None

        # Stage 3 - rules around individual tokens

        stage_3_analysis(mh=wp.mh,
                         cfg=wp.cfg,
                         tbuf=tbuf,
                         is_embedded=isinstance(
                             wp, work_package.Embedded_MATLAB_WP),
                         fixed=parse_tree is not None)

        # Stage 4 - rules involving the parse tree

        # TODO

        # Possibly re-write the file, with issues fixed

        if autofix:
            if not parse_tree:
                wp.mh.error(lexer.get_file_loc(),
                            "file is not auto-fixed because it contains"
                            " parse errors",
                            fatal=False)
            else:
                # TODO: call modify()
                wp.write_modified(tbuf.replay())

        # Return results

        return MH_Style_Result(wp)
    def process_wp(cls, wp):
        # Load file content
        content = wp.get_content()

        # Create lexer
        lexer = MATLAB_Lexer(wp.mh, content, wp.filename, wp.blockname)
        if wp.cfg.octave:
            lexer.set_octave_mode()
        if not wp.cfg.pragmas:  # pragma: no cover
            lexer.process_pragmas = False

        # Deal with command-line options, setting up three variables:
        # * action - what to do
        # * primary_entity - main entity
        # * templates - how to write copyright notices
        templates = {
            "single": wp.options.template,
            "range": wp.options.template_range
        }
        primary_entity = get_primary_entity(wp.options, wp.cfg)
        if not primary_entity:
            wp.mh.warning(
                lexer.get_file_loc(),
                "unable to determine primary copyright entity,"
                " skipping this file")
            return MH_Copyright_Result(wp, False)
        if wp.options.update_year:
            action = "update_year"
        elif wp.options.merge:
            action = "merge"
        elif wp.options.change_entity is not None:
            action = "change_entity"
        elif wp.options.add_notice:
            action = "add_notice"
        else:
            raise ICE("none of the action are set")

        allowed_entities = (wp.cfg.style_config["copyright_entity"]
                            | set([primary_entity]))

        # We're dealing with an empty file here. Lets just not do anything
        if len(lexer.text.strip()) == 0:
            return MH_Copyright_Result(wp, False)

        # Parse
        try:
            tbuf = Token_Buffer(lexer, wp.cfg)
            parser = MATLAB_Parser(wp.mh, tbuf, wp.cfg)
            parse_tree = parser.parse_file()
            parse_docstrings(wp.mh, wp.cfg, parse_tree, tbuf)
        except Error:  # pragma: no cover
            return MH_Copyright_Result(wp, False)

        # Determine the docstring of the primary entity. We use the
        # script/class docstring, if it exists and contains copyright
        # info. Otherwise we use the compilation unit's docstring
        # (i.e. file header). The style checker worries about the case
        # where we have copyright in more than one location.
        n_docstring = None
        if isinstance(parse_tree, Class_File):
            n_docstring = parse_tree.n_classdef.n_docstring
        elif isinstance(parse_tree, Function_File):
            n_docstring = parse_tree.l_functions[0].n_docstring
        if n_docstring is None or not n_docstring.copyright_info:
            n_docstring = parse_tree.n_docstring
        # Note that n_docstring could be None at this point, so we do
        # need to deal with that correctly.

        # Set up line -> Copyright_Info map
        cinfos = {}
        if n_docstring:
            for cinfo in n_docstring.copyright_info:
                if cinfo.t_comment.location.line in cinfos:
                    raise ICE("docstring with duplicate line (%u)" %
                              cinfo.t_comment.location.line)
                else:
                    cinfos[cinfo.t_comment.location.line] = cinfo

            # The merge action requires the copyright notice to be
            # grouped. Enforce this now.
            if action == "merge" and \
               not (n_docstring.all_copyright_in_one_block(allowed_entities) or
                    n_docstring.all_copyright_in_one_block()):
                wp.mh.error(n_docstring.loc(),
                            "cannot merge entries in this docstring as they"
                            " are not all next to each other",
                            fatal=False)
                return MH_Copyright_Result(wp, False)

        # Perform actions
        action_taken = False
        lines = copy(lexer.context_line)
        try:
            if action == "update_year":
                new_year = wp.options.year
                for line_no, cinfo in cinfos.items():
                    ystart, yend = cinfo.get_range()
                    if cinfo.get_org() != primary_entity:
                        continue

                    if yend <= new_year:
                        new_range = (ystart, new_year)
                        replace_line(lines, line_no,
                                     cinfo.is_block_comment(), templates,
                                     cinfo.get_copy_notice(), primary_entity,
                                     new_range)

                        action_taken = True
                    else:
                        wp.mh.error(cinfo.loc_yend(),
                                    "end year is later than %s" % new_year)

            elif action == "merge":
                merged_line = None
                merged_line_is_block = None
                killed_lines = []
                new_range = None
                for line_no in sorted(cinfos):
                    cinfo = cinfos[line_no]
                    ystart, yend = cinfo.get_range()

                    if cinfo.get_org() not in allowed_entities:
                        continue
                    if cinfo.get_org() != primary_entity or ystart == yend:
                        action_taken = True

                    if ystart > yend:
                        wp.mh.error(cinfo.loc_ystart(),
                                    "initial year is later than end year")

                    if new_range is None:
                        merged_line = line_no
                        merged_line_is_block = cinfo.is_block_comment()
                        merged_line_copy_notice = cinfo.get_copy_notice()
                        new_range = cinfo.get_range()
                    else:
                        new_range = (min(ystart, new_range[0]),
                                     max(yend, new_range[1]))
                        killed_lines.append(line_no)
                        action_taken = True

                if action_taken:
                    replace_line(lines, merged_line, merged_line_is_block,
                                 templates, merged_line_copy_notice,
                                 primary_entity, new_range)
                    for line_no in reversed(killed_lines):
                        del lines[line_no - 1]

            elif action == "change_entity":
                for line_no, cinfo in cinfos.items():
                    if cinfo.get_org() == wp.options.change_entity:
                        replace_line(lines, line_no,
                                     cinfo.is_block_comment(), templates,
                                     cinfo.get_copy_notice(), primary_entity,
                                     cinfo.get_range())
                        action_taken = True

            elif action == "add_notice":
                # Only add copyright notices to files without any
                # notice.
                if len(cinfos) == 0:
                    # Find the right place to add the notice. Right
                    # now we only do this for the file header; so we
                    # need to find it and append at the end; or create
                    # a new one.
                    action_taken = True

                    if parse_tree.n_docstring:
                        is_block, line_no = parse_tree.n_docstring.final_line()
                        off = parse_tree.n_docstring.guess_docstring_offset()

                        # Duplicate the last line
                        lines = \
                            lines[:line_no] + \
                            [lines[line_no - 1]] + \
                            lines[line_no:]
                    else:
                        is_block = False
                        line_no = 0
                        off = 1
                        lines = ["% POTATO", ""] + lines

                    if wp.options.style == "c_first" or \
                       (wp.options.style == "dynamic" and
                        not wp.cfg.octave):
                        copy_notice = "(c) Copyright"
                    else:
                        copy_notice = "Copyright (c)"

                    # Then overwrite it
                    replace_line(lines,
                                 line_no + 1,
                                 is_block,
                                 templates,
                                 copy_notice,
                                 primary_entity,
                                 (wp.options.year, wp.options.year),
                                 offset=off)

            else:
                raise ICE("Unexpected action '%s'" % action)
        except Error:
            return MH_Copyright_Result(wp, False)

        if action_taken:
            wp.write_modified("\n".join(lines) + "\n")

        return MH_Copyright_Result(wp, True)