예제 #1
0
    def examine_fortran(self, subject: FortranSource) -> List[Issue]:
        issues = []

        scope_units = subject.path('Program_Unit')
        scope_units.extend(
            subject.path([
                'Main_Program', 'Internal_Subprogram_Part',
                'Internal_Subprogram'
            ]))
        scope_units.extend(
            subject.path(
                ['Module', 'Module_Subprogram_Part', 'Module_Subprogram']))
        for scope in scope_units:
            scope_statement = subject.get_first_statement(root=scope)

            implication = subject.path(
                ['Specification_Part', 'Implicit_Part', 'Implicit_Stmt'],
                root=scope.content[1:])
            if not implication:
                nature = MissingImplicit._NATURE_MAP[scope_statement.__class__]
                name = scope_statement.items[1]
                description = "{thing} '{name}' is missing " \
                              + "an implicit statement"
                description = description.format(thing=nature, name=name)
                issues.append(
                    Issue(description, line=scope_statement.item.span[0]))
        return issues
 def test_path_string(self, path_case: Tuple[str, List[str], List[str]]) \
         -> None:
     """
     Checks that matching a path to the source works.
     """
     reader = SourceStringReader(path_case[0])
     unit_under_test = FortranSource(reader)
     result = unit_under_test.path('/'.join(path_case[1]))
     assert [obj.__class__.__name__ for obj in result] == path_case[2]
예제 #3
0
 def test_path_string(self, path_case):
     '''
     Checks that matching a path to the source works.
     '''
     # pylint: disable=no-self-use
     reader = SourceStringReader(path_case[0])
     unit_under_test = FortranSource(reader)
     result = unit_under_test.path('/'.join(path_case[1]))
     assert [obj.__class__.__name__ for obj in result] == path_case[2]
예제 #4
0
    def examine_fortran(self, subject: FortranSource) -> List[Issue]:
        issues: List[Issue] = []
        scope_units: List[Fortran2003.Block] = []

        # get all subprograms (functions and subroutines) within programs
        scope_units.extend(
            subject.path([
                'Main_Program', 'Internal_Subprogram_Part',
                'Internal_Subprogram'
            ]))

        # get all subprograms within modules
        scope_units.extend(
            subject.path(
                ['Module', 'Module_Subprogram_Part', 'Module_Subprogram']))

        # get all naked subprograms
        scope_units.extend(subject.path(['Function_Subprogram']))
        scope_units.extend(subject.path(['Subroutine_Subprogram']))

        for scope in scope_units:
            # get initialisation statement and piece containing all type
            # declarations

            specs = None
            for part in scope.children:
                if type(part) in (Fortran2003.Function_Stmt,
                                  Fortran2003.Subroutine_Stmt):
                    stmt = part
                if type(part) == Fortran2003.Specification_Part:
                    specs = part
                    # we don't need to check the rest of the children
                    break

            # covert tree node into a python list
            dummy_arg_list = stmt.children[2]

            # initialise set in case empty
            dummy_args: List[str] = []
            if dummy_arg_list is not None:
                dummy_args = [
                    arg.string.lower() for arg in dummy_arg_list.children
                ]

            if specs is not None:
                for spec in specs.children:
                    if spec.__class__ == Fortran2008.Type_Declaration_Stmt:

                        # check if type declaration has an intent
                        attributes = spec.children[1]
                        if attributes is not None:
                            for attribute in spec.children[1].children:
                                if attribute.__class__ == \
                                        Fortran2003.Intent_Attr_Spec:

                                    # if so, remove argument names from
                                    # dummy_args
                                    for arg in spec.children[2].children:
                                        arg_name = arg.children[
                                            0].string.lower()
                                        if arg_name in dummy_args:
                                            dummy_args.remove(arg_name)

            # get the type of block
            if type(scope) == Fortran2003.Subroutine_Subprogram:
                unit_type = 'subroutine'
            elif type(scope) == Fortran2003.Function_Subprogram:
                unit_type = 'function'

            # any remaining dummy arguments lack intent
            for arg in dummy_args:
                description = f'Dummy argument "{arg}" of {unit_type} "' \
                              f'{stmt.children[1].string}" is missing an ' \
                              f'"intent" statement'
                issues.append(Issue(description, line=stmt.item.span[0]))

        return issues