@@ -52,7 +52,63 @@ defmodule Credo.Check.Readability.PredicateFunctionNames do
52
52
def run ( % SourceFile { } = source_file , params ) do
53
53
issue_meta = IssueMeta . for ( source_file , params )
54
54
55
- Credo.Code . prewalk ( source_file , & traverse ( & 1 , & 2 , issue_meta ) )
55
+ issue_candidates = Credo.Code . prewalk ( source_file , & traverse ( & 1 , & 2 , issue_meta ) )
56
+
57
+ if issue_candidates == [ ] do
58
+ [ ]
59
+ else
60
+ impl_list = Credo.Code . prewalk ( source_file , & find_impls ( & 1 , & 2 ) )
61
+
62
+ issue_candidates
63
+ |> Enum . reject ( fn { _ , signature } -> signature in impl_list end )
64
+ |> Enum . map ( fn { issue , _ } -> issue end )
65
+ end
66
+ end
67
+
68
+ defp find_impls ( { :__block__ , _meta , args } = ast , impls ) do
69
+ block_impls = find_impls_in_block ( args )
70
+ { ast , block_impls ++ impls }
71
+ end
72
+
73
+ defp find_impls ( ast , impls ) do
74
+ { ast , impls }
75
+ end
76
+
77
+ defp find_impls_in_block ( block_args ) when is_list ( block_args ) do
78
+ block_args
79
+ |> Enum . reduce ( [ ] , & do_find_impls_in_block / 2 )
80
+ end
81
+
82
+ defp do_find_impls_in_block ( { :@ , _ , [ { :impl , _ , [ impl ] } ] } , acc ) when impl != false do
83
+ [ :record_next_definition | acc ]
84
+ end
85
+
86
+ # def when
87
+ defp do_find_impls_in_block ( { keyword , meta , [ { :when , _ , def_ast } | _ ] } , [
88
+ :record_next_definition | impls
89
+ ] )
90
+ when keyword in @ def_ops do
91
+ do_find_impls_in_block ( { keyword , meta , def_ast } , [ :record_next_definition | impls ] )
92
+ end
93
+
94
+ # def 0 arity
95
+ defp do_find_impls_in_block ( { keyword , _meta , [ { name , _ , nil } | _ ] } , [
96
+ :record_next_definition | impls
97
+ ] )
98
+ when keyword in @ def_ops do
99
+ [ { to_string ( name ) , 0 } | impls ]
100
+ end
101
+
102
+ # def n arity
103
+ defp do_find_impls_in_block ( { keyword , _meta , [ { name , _ , args } | _ ] } , [
104
+ :record_next_definition | impls
105
+ ] )
106
+ when keyword in @ def_ops do
107
+ [ { to_string ( name ) , length ( args ) } | impls ]
108
+ end
109
+
110
+ defp do_find_impls_in_block ( _ , acc ) do
111
+ acc
56
112
end
57
113
58
114
for op <- @ def_ops do
@@ -66,56 +122,62 @@ defmodule Credo.Check.Readability.PredicateFunctionNames do
66
122
issues ,
67
123
issue_meta
68
124
) do
69
- { ast , issues_for_definition ( op , arguments , issues , issue_meta ) }
125
+ { ast , issues_candidate_for_definition ( op , arguments , issues , issue_meta ) }
70
126
end
71
127
end
72
128
73
129
defp traverse ( ast , issues , _issue_meta ) do
74
130
{ ast , issues }
75
131
end
76
132
77
- defp issues_for_definition ( op , body , issues , issue_meta ) do
78
- case Enum . at ( body , 0 ) do
79
- { name , meta , nil } ->
80
- issues_for_name ( op , name , meta , issues , issue_meta )
133
+ defp issues_candidate_for_definition ( op , [ { name , meta , nil } | _ ] , issues , issue_meta ) do
134
+ issues_candidate_for_definition ( op , [ { name , meta , [ ] } ] , issues , issue_meta )
135
+ end
81
136
82
- { name , meta , [ _ | _ ] } ->
83
- issues_for_name ( op , name , meta , issues , issue_meta )
137
+ defp issues_candidate_for_definition ( op , [ { name , meta , args } | _ ] , issues , issue_meta ) do
138
+ issues_candidate_for_name ( op , name , meta , issues , issue_meta , args )
139
+ end
84
140
85
- _ ->
86
- issues
87
- end
141
+ defp issues_candidate_for_definition ( _op , _ , issues , _issue_meta ) do
142
+ issues
88
143
end
89
144
90
- defp issues_for_name ( _op , { :unquote , _ , [ _ | _ ] } = _name , _meta , issues , _issue_meta ) do
145
+ defp issues_candidate_for_name (
146
+ _op ,
147
+ { :unquote , _ , [ _ | _ ] } = _name ,
148
+ _meta ,
149
+ issues ,
150
+ _issue_meta ,
151
+ _args
152
+ ) do
91
153
issues
92
154
end
93
155
94
- defp issues_for_name ( op , name , meta , issues , issue_meta ) do
156
+ defp issues_candidate_for_name ( op , name , meta , issues , issue_meta , args ) do
95
157
name = to_string ( name )
96
158
97
159
cond do
98
160
String . starts_with? ( name , "is_" ) && String . ends_with? ( name , "?" ) ->
99
161
[
100
- issue_for ( issue_meta , meta [ :line ] , name , :predicate_and_question_mark )
162
+ issue_candidate_for ( issue_meta , meta [ :line ] , name , args , :predicate_and_question_mark )
101
163
| issues
102
164
]
103
165
104
166
String . starts_with? ( name , "is_" ) && op != :defmacro ->
105
- [ issue_for ( issue_meta , meta [ :line ] , name , :only_predicate ) | issues ]
167
+ [ issue_candidate_for ( issue_meta , meta [ :line ] , name , args , :only_predicate ) | issues ]
106
168
107
169
true ->
108
170
issues
109
171
end
110
172
end
111
173
112
- defp issue_for ( issue_meta , line_no , trigger , _ ) do
113
- format_issue (
114
- issue_meta ,
115
- message:
116
- "Predicate function names should not start with 'is', and should end in a question mark." ,
117
- trigger: trigger ,
118
- line_no: line_no
119
- )
174
+ defp issue_candidate_for ( issue_meta , line_no , trigger , args , _ ) do
175
+ { format_issue (
176
+ issue_meta ,
177
+ message:
178
+ "Predicate function names should not start with 'is', and should end in a question mark." ,
179
+ trigger: trigger ,
180
+ line_no: line_no
181
+ ) , { trigger , length ( args ) } }
120
182
end
121
183
end
0 commit comments