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]
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]
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