4
4
5
5
from lark import Token , Tree
6
6
7
+ from ..common .ast import AbstractSyntaxTree , Class , Statement , Annotation
7
8
from ..common .utils import find_name_token_among_children
8
9
9
10
from .problem import Problem
@@ -17,15 +18,22 @@ def lint(parse_tree: Tree, config: MappingProxyType) -> List[Problem]:
17
18
"private-method-call" ,
18
19
_private_method_call_check ,
19
20
),
21
+ ] # type: List[Tuple[str, Callable]]
22
+ problem_clusters = (
23
+ x [1 ](parse_tree ) if x [0 ] not in disable else [] for x in checks_to_run_w_tree
24
+ )
25
+ problems = [problem for cluster in problem_clusters for problem in cluster ]
26
+ checks_to_run_w_ast = [
20
27
(
21
28
"class-definitions-order" ,
22
29
partial (_class_definitions_order_check , config ["class-definitions-order" ]),
23
30
),
24
- ] # type: List[Tuple[str, Callable]]
31
+ ]
32
+ ast = AbstractSyntaxTree (parse_tree )
25
33
problem_clusters = (
26
- x [1 ](parse_tree ) if x [0 ] not in disable else [] for x in checks_to_run_w_tree
34
+ x [1 ](ast ) if x [0 ] not in disable else [] for x in checks_to_run_w_ast
27
35
)
28
- problems = [problem for cluster in problem_clusters for problem in cluster ]
36
+ problems + = [problem for cluster in problem_clusters for problem in cluster ]
29
37
return problems
30
38
31
39
@@ -55,71 +63,89 @@ def _private_method_call_check(parse_tree: Tree) -> List[Problem]:
55
63
return problems
56
64
57
65
66
+ # TODO: drop
58
67
def _is_method_private (method_name : str ) -> bool :
59
68
return method_name .startswith ("_" ) # TODO: consider making configurable
60
69
61
70
62
- def _class_definitions_order_check (order , parse_tree : Tree ) -> List [Problem ]:
63
- problems = _class_definitions_order_check_for_class (
64
- "global scope" , parse_tree .children , order
65
- )
66
- for class_def in parse_tree .find_data ("class_def" ):
67
- class_name = class_def .children [0 ].value
68
- problems += _class_definitions_order_check_for_class (
69
- "class {}" .format (class_name ), class_def .children , order
70
- )
71
- return problems
71
+ def _class_definitions_order_check (
72
+ order : List [str ], ast : AbstractSyntaxTree
73
+ ) -> List [Problem ]:
74
+ return [
75
+ problem
76
+ for a_class in ast .all_classes
77
+ for problem in _class_definitions_order_check_for_class (a_class , order )
78
+ ]
72
79
73
80
74
81
def _class_definitions_order_check_for_class (
75
- class_name : str , class_children , order
82
+ a_class : Class , order : List [ str ]
76
83
) -> List [Problem ]:
77
- stmt_to_section_mapping = {
78
- "tool_stmt" : "tools" ,
79
- "signal_stmt" : "signals" ,
80
- "extends_stmt" : "extends" ,
81
- "classname_stmt" : "classnames" ,
82
- "const_stmt" : "consts" ,
83
- "export_stmt" : "exports" ,
84
- "enum_def" : "enums" ,
85
- }
86
- visibility_dependent_stmt_to_section_mapping = {
87
- "class_var_stmt" : {"pub" : "pubvars" , "prv" : "prvvars" },
88
- "onready_stmt" : {"pub" : "onreadypubvars" , "prv" : "onreadyprvvars" },
89
- }
90
84
problems = []
91
85
current_section = order [0 ]
92
- for class_child in class_children :
93
- if not isinstance (class_child , Tree ):
94
- continue
95
- if class_child .data in ["annotation" ]:
86
+ for statement in a_class .statements :
87
+ if _is_statement_irrelevant (statement ):
96
88
continue
97
- stmt = class_child .data
98
- if stmt == "class_var_stmt" :
99
- visibility = _class_var_stmt_visibility (class_child )
100
- section = visibility_dependent_stmt_to_section_mapping [stmt ][visibility ]
101
- elif stmt == "onready_stmt" :
102
- class_var_stmt = class_child .children [0 ]
103
- visibility = _class_var_stmt_visibility (class_var_stmt )
104
- section = visibility_dependent_stmt_to_section_mapping [stmt ][visibility ]
105
- else :
106
- section = stmt_to_section_mapping .get (stmt , "others" )
107
- section_rank = order .index (section )
108
- if section_rank >= order .index (current_section ):
109
- current_section = section
89
+ current_section_rank = order .index (current_section )
90
+ statement_section = _map_statement_to_section (statement )
91
+ section_rank = order .index (statement_section )
92
+ if section_rank >= current_section_rank :
93
+ current_section = statement_section
110
94
else :
111
95
problems .append (
112
96
Problem (
113
97
name = "class-definitions-order" ,
114
- description = "Definition out of order in {}" .format (class_name ),
115
- line = class_child .line ,
116
- column = class_child .column ,
98
+ description = "Definition out of order in {}" .format (a_class . name ),
99
+ line = statement . lark_node .line ,
100
+ column = statement . lark_node .column ,
117
101
)
118
102
)
119
103
return problems
120
104
121
105
122
- def _class_var_stmt_visibility (class_var_stmt ) -> str :
106
+ def _is_statement_irrelevant (statement : Statement ) -> bool :
107
+ if statement .kind == "pass_stmt" :
108
+ return True
109
+ if statement .kind == "annotation" :
110
+ return Annotation (statement .lark_node ).name != "tool"
111
+ return False
112
+
113
+
114
+ # pylint: disable-next=too-many-return-statements
115
+ def _map_statement_to_section (statement : Statement ) -> str :
116
+ if statement .kind == "class_var_stmt" :
117
+ if any (
118
+ annotation .name .startswith ("export" ) for annotation in statement .annotations
119
+ ):
120
+ return "exports"
121
+ if any (annotation .name == "onready" for annotation in statement .annotations ):
122
+ return "onready{}vars" .format (
123
+ _class_var_stmt_visibility (statement .lark_node )
124
+ )
125
+ return "{}vars" .format (_class_var_stmt_visibility (statement .lark_node ))
126
+ if statement .kind == "signal_stmt" :
127
+ return "signals"
128
+ if statement .kind == "extends_stmt" :
129
+ return "extends"
130
+ if statement .kind == "enum_stmt" :
131
+ return "enums"
132
+ if statement .kind == "classname_stmt" :
133
+ return "classnames"
134
+ if statement .kind == "const_stmt" :
135
+ return "consts"
136
+ if (
137
+ statement .kind == "annotation"
138
+ and Annotation (statement .lark_node ).name == "tool"
139
+ ):
140
+ return "tools"
141
+ if statement .kind == "class_def" :
142
+ return "others"
143
+ if statement .kind == "func_def" :
144
+ return "others"
145
+ raise NotImplementedError
146
+
147
+
148
+ def _class_var_stmt_visibility (class_var_stmt : Tree ) -> str :
123
149
some_var_stmt = class_var_stmt .children [0 ]
124
150
name_token = find_name_token_among_children (some_var_stmt )
125
151
return "pub" if is_function_public (name_token .value ) else "prv" # type: ignore
0 commit comments