Skip to content

Commit c5b2882

Browse files
committed
POC linter for missing kind specifiers on real literals and 'fixer' via automatically generated git patch (file)
1 parent 7930491 commit c5b2882

File tree

1 file changed

+73
-3
lines changed

1 file changed

+73
-3
lines changed

lint_rules/lint_rules/ifs_arpege_coding_standards.py

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from collections import defaultdict
1616
import re
17+
import difflib
1718

1819
try:
1920
from fparser.two.Fortran2003 import Intrinsic_Name
@@ -22,16 +23,85 @@
2223
_intrinsic_fortran_names = ()
2324

2425
from loki import (
25-
FindInlineCalls, FindNodes, GenericRule, Module, RuleType
26+
FindInlineCalls, FindNodes, GenericRule, Module, RuleType,
27+
ExpressionFinder, ExpressionRetriever, FloatLiteral,
28+
SubstituteExpressions
2629
)
27-
from loki import ir
28-
30+
from loki import ir, fgen
31+
from loki.frontend.util import read_file
2932

3033
__all__ = [
3134
'MissingImplicitNoneRule', 'OnlyParameterGlobalVarRule', 'MissingIntfbRule',
35+
'MissingKindSpecifierRealLiterals'
3236
]
3337

3438

39+
class FindFloatLiterals(ExpressionFinder):
40+
"""
41+
A visitor to collects :any:`FloatLiteral` used in an IR tree.
42+
43+
See :class:`ExpressionFinder`
44+
"""
45+
retriever = ExpressionRetriever(lambda e: isinstance(e, (FloatLiteral,)))
46+
47+
class MissingKindSpecifierRealLiterals(GenericRule):
48+
"""
49+
...
50+
"""
51+
52+
type = RuleType.SERIOUS
53+
fixable = True
54+
55+
docs = {
56+
'id': 'L0',
57+
'title': (
58+
'Real Literals must have a kind specifier. '
59+
),
60+
}
61+
62+
63+
@classmethod
64+
def check_subroutine(cls, subroutine, rule_report, config, **kwargs):
65+
"""
66+
...
67+
"""
68+
literal_nodes = FindFloatLiterals(with_ir_node=True).visit(subroutine.body)
69+
for node, literals in literal_nodes:
70+
for literal in literals:
71+
if literal.kind is None:
72+
rule_report.add(f'Real/Float literal without kind specifier "{literal}"', node)
73+
74+
@classmethod
75+
def fix_subroutine(cls, subroutine, rule_report, config, sourcefile=None):
76+
"""
77+
...
78+
"""
79+
original_content = read_file(str(sourcefile.path))
80+
content = original_content
81+
literal_nodes = FindFloatLiterals(with_ir_node=True).visit(subroutine.body)
82+
for node, literals in literal_nodes:
83+
literal_map = {}
84+
for literal in literals:
85+
if literal.kind is None:
86+
literal_map[literal] = FloatLiteral(value=literal.value, kind='JPRB')
87+
if literal_map:
88+
fixed_node = SubstituteExpressions(literal_map).visit(node)
89+
indent = int((len(node.source.string) - len(node.source.string.lstrip(' ')))/2)
90+
fixed_node_str = fgen(fixed_node, depth=indent)
91+
content_new = re.sub(rf'{re.escape(node.source.string)}',
92+
fixed_node_str, content, flags = re.S)
93+
content = content_new
94+
diff = difflib.unified_diff(original_content.splitlines(), content_new.splitlines(),
95+
f'a/{sourcefile.path}', f'b/{sourcefile.path}', lineterm='')
96+
diff_str = '\n'.join(list(diff))
97+
# print(f"---{sourcefile.path}------")
98+
# print(diff_str)
99+
# print(f"--------------------------")
100+
with open (f'loki_lint_{subroutine.name}.patch', 'w') as f:
101+
f.write(diff_str)
102+
f.write('\n')
103+
104+
35105
class MissingImplicitNoneRule(GenericRule):
36106
"""
37107
``IMPLICIT NONE`` must be present in all scoping units but may be omitted

0 commit comments

Comments
 (0)