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

        candidates: List[Fortran2003.StmtBase] = []
        # Component variables
        candidates.extend(subject.find_all(
            Fortran2003.Data_Component_Def_Stmt))
        # Variable declaration
        candidates.extend(subject.find_all(Fortran2003.Type_Declaration_Stmt))

        for candidate in candidates:

            problem = 'Use of dimension attribute for {name}.'

            attributes = candidate.items[1]
            if attributes is None:
                continue
            cannon_attr = list(
                str(item).lower().replace(' ', '')
                for item in attributes.items)
            argument_def = 'intent(in)' in cannon_attr \
                           or 'intent(out)' in cannon_attr \
                           or 'intent(inout)' in cannon_attr
            if any(x.startswith('dimension') for x in cannon_attr):
                for variable in candidate.items[2].items:
                    name = str(variable.items[0])
                    message = problem.format(name=name)
                    line_number = candidate.item.span[0]
                    issues.append(Issue(message, line=line_number))

        issues.sort(key=lambda x: (x.filename, x.line, x.description))
        return issues
예제 #2
0
    def examine_fortran(self, subject: FortranSource) -> List[Issue]:
        issues = []

        for exit in subject.find_all(Fortran2003.Exit_Stmt):
            if exit.items[1] is None:
                issues.append(
                    Issue(
                        'Usage of "exit" without label indicating '
                        'which "do" construct is being exited '
                        'from.',
                        line=exit.item.span[0]))

        # Above doesn't catch exits in inline if statements
        for statement in subject.find_all(Fortran2003.If_Stmt):
            action = statement.items[1]
            if type(action
                    ) == Fortran2003.Exit_Stmt and action.items[1] is None:
                issues.append(
                    Issue(
                        'Usage of "exit" without label indicating '
                        'which "do" construct is being exited '
                        'from.',
                        line=statement.item.span[0]))

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

        for statement in subject.find_all(Fortran2003.Use_Stmt):
            print ("statement = ", statement)
        for statement in subject.find_all(Fortran2003.Data_Component_Def_Stmt):
            print ("statement = ", statement)
        for statement in subject.find_all(Fortran2003.Proc_Component_Def_Stmt):
            print ("statement = ", statement)
        for statement in subject.find_all(Fortran2003.Procedure_Declaration_Stmt):
            print ("statement = ", statement)
        for statement in subject.find_all(Fortran2003.Type_Declaration_Stmt):
            print ("statement = ", statement)
        print ("text = ", subject.get_text())
        return issues
 def test_find_all(self) -> None:
     """
     Checks that finding all occurrences of a source part works.
     """
     reader = SourceStringReader(self._MULTI_PROC_MODULE)
     unit_under_test = FortranSource(reader)
     wanted = fparser.two.Fortran2003.Module_Subprogram
     result = unit_under_test.find_all(wanted)
     assert str(next(result).content[0].items[1]) == 'one'
     assert str(next(result).content[0].items[1]) == 'two'
     with pytest.raises(StopIteration):
         next(result)
예제 #5
0
    def examine_fortran(self, subject: FortranSource) -> List[Issue]:
        issues: List[Issue] = []

        candidates: List[Fortran2003.Base] = []
        # Component variables
        candidates.extend(subject.find_all(
            Fortran2003.Data_Component_Def_Stmt))
        # Component Procedure
        candidates.extend(subject.find_all(
            Fortran2003.Proc_Component_Def_Stmt))
        # Procedure declaration
        candidates.extend(
            subject.find_all(Fortran2003.Procedure_Declaration_Stmt))
        # Variable declaration
        candidates.extend(subject.find_all(Fortran2003.Type_Declaration_Stmt))

        for candidate in candidates:
            if isinstance(
                    candidate,  # Is variable
                (Fortran2003.Data_Component_Def_Stmt,
                 Fortran2003.Type_Declaration_Stmt)):
                type_spec: Fortran2003.Intrinsic_Type_Spec = candidate.items[0]
                kind_selector: Fortran2003.Kind_Selector = type_spec.items[1]

                if isinstance(kind_selector, Fortran2003.Kind_Selector):
                    data_type: str = type_spec.items[0].lower()
                    kind: str = kind_selector.string.strip('()')
                    match = self._patterns[data_type].match(kind)
                    if match is None:
                        entity_declaration = candidate.items[2]
                        message = self._ISSUE_TEMPLATE.format(
                            type=data_type,
                            kind=kind,
                            name=entity_declaration,
                            pattern=self._patterns[data_type].pattern)
                        issues.append(
                            Issue(message, line=candidate.item.span[0]))

        issues.sort(key=lambda x: (x.filename, x.line, x.description))
        return issues
예제 #6
0
    def examine_fortran(self, subject: FortranSource) -> List[Issue]:
        issues = []

        for statement in subject.find_all(Fortran2003.Use_Stmt):
            module = statement.items[2]
            onlies = statement.items[4]
            if str(module).lower() not in self._ignore:
                if onlies is None:
                    description = 'Usage of "{module}" without "only" clause.'
                    issues.append(Issue(description.format(module=module),
                                        line=statement.item.span[0]))

        return issues
예제 #7
0
    def examine_fortran(self, subject: FortranSource) -> List[Issue]:
        issues = []
        for statement in subject.find_all(Fortran2003.Use_Stmt):
            module = statement.items[2]
            if str(module).lower() in self._INTRINSICS:
                nature = statement.items[0]
                if nature is None or nature.string.lower() != 'intrinsic':
                    description = 'Usage of intrinsic module "{module}" ' \
                                  'without "intrinsic" clause.'
                    issues.append(
                        Issue(description.format(module=module),
                              line=statement.item.span[0]))

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

        # Collect all variable declarations
        declarations: List[Fortran2003.Type_Declaration_Stmt] = list(
            subject.find_all(Fortran2003.Type_Declaration_Stmt))

        # keep only the ones in subroutines
        declarations = [
            declaration for declaration in declarations if isinstance(
                declaration.parent.parent, Fortran2003.Subroutine_Subprogram)
        ]

        for declaration in declarations:
            type_spec = declaration.items[0]
            # If not a character, no concern
            if not type_spec.items[0] == "CHARACTER":
                continue
            param_value = type_spec.items[1]
            # This might be a length selector, if so get the param value
            if isinstance(param_value, Fortran2003.Length_Selector):
                param_value = param_value.items[1]
            # If not an auto length, no concern
            if not param_value.string == "*":
                continue
            attr_spec_list = declaration.items[1]
            # If no attributes specified, no concern
            if attr_spec_list is None:
                continue
            # Get intent attr and not other attributes
            intent_attr = None
            for item in attr_spec_list.items:
                if isinstance(item, Fortran2003.Intent_Attr_Spec):
                    intent_attr = item
                    break
            # If no intent, no conecern
            # Ensuring arguments specify intent should be enforced elsewhere
            if intent_attr is None:
                continue
            # Intent in, no conern
            if intent_attr.items[1].string == "IN":
                continue
            issues.append(
                Issue(self._message(declaration.items[2].string,
                                    intent_attr.items[1]),
                      line=declaration.item.span[0]))

        return issues
예제 #9
0
    def examine_fortran(self, subject: FortranSource):
        issues: List[Issue] = []

        candidates: List[Fortran2003.StmtBase] = []
        # Component variables
        candidates.extend(subject.find_all(
            Fortran2003.Data_Component_Def_Stmt))
        # Component Procedure
        candidates.extend(subject.find_all(
            Fortran2003.Proc_Component_Def_Stmt))
        # Procedure declaration
        candidates.extend(
            subject.find_all(Fortran2003.Procedure_Declaration_Stmt))
        # Variable declaration
        candidates.extend(subject.find_all(Fortran2003.Type_Declaration_Stmt))

        return_variable = ''
        for candidate in candidates:
            if isinstance(
                    candidate,  # Is variable
                (Fortran2003.Data_Component_Def_Stmt,
                 Fortran2003.Type_Declaration_Stmt)):
                if isinstance(candidate.parent.parent,
                              Fortran2003.Function_Subprogram):
                    # Is contained in a function
                    function_block: Fortran2003.Function_Subprogram \
                        = candidate.parent.parent
                    statement = None
                    for thing in function_block.children:
                        if isinstance(thing, Fortran2003.Function_Stmt):
                            statement = thing
                            break
                    if statement is None:
                        message = "Malformed parse tree: Function subprogram" \
                                  " without Function statement"
                        raise Exception(message)
                    suffix = statement.items[3]
                    if isinstance(suffix, Fortran2003.Suffix):
                        if isinstance(suffix.items[0], Fortran2003.Name):
                            # Is return variable
                            return_variable = str(suffix.items[0])

            problem = 'Declaration of pointer "{name}" without initialisation.'

            attributes = candidate.items[1]
            if attributes is None:
                continue
            cannon_attr = list(
                str(item).lower().replace(' ', '')
                for item in attributes.items)
            argument_def = 'intent(in)' in cannon_attr \
                           or 'intent(out)' in cannon_attr \
                           or 'intent(inout)' in cannon_attr
            if 'pointer' in cannon_attr and not argument_def:
                for variable in candidate.items[2].items:
                    if isinstance(
                            candidate,  # Is variable
                        (Fortran2003.Data_Component_Def_Stmt,
                         Fortran2003.Type_Declaration_Stmt)):
                        name = str(variable.items[0])
                        if name == return_variable:
                            continue  # Return variables cannot be initialised.
                        init = variable.items[3]
                        if init is None:
                            message = problem.format(name=name)
                            line_number = candidate.item.span[0]
                            issues.append(Issue(message, line=line_number))
                    elif isinstance(
                            candidate,  # Is procedure
                        (Fortran2003.Proc_Component_Def_Stmt,
                         Fortran2003.Procedure_Declaration_Stmt)):
                        name = str(variable)
                        if isinstance(variable, Fortran2003.Name):
                            line_number = candidate.item.span[0]
                            message = problem.format(name=name)
                            issues.append(Issue(message, line=line_number))
                    else:
                        message \
                            = f"Unexpected source element: {repr(candidate)}"
                        raise Exception(message)

        issues.sort(key=lambda x: (x.filename, x.line, x.description))
        return issues