Opinionated OCaml linter with Merlin integration for code quality, naming conventions, and style checks
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

merlint: e325/e331 exempt stdlib-aligned find_* aliases

Stop flagging stdlib-idiomatic names like [find_all], [find_map],
[find_many], [find_index], [find_last], [find_first]:

- E325 ("find_ should return option"): [find_all] and [find_many] are
collection aggregators ([List.find_all], [Hashtbl.find_all]); their
non-option return type is the convention, not a warning.
- E331 ("find_ prefix is redundant"): the bare suffix for these names
([all], [map], [many], [index], [last], [first]) is too generic to
stand alone. The full [find_*] name is what users expect from stdlib.

The exemption is a semantic rule keyed on the name shape (these are the
specific stdlib precedents); other [find_X] names continue to trigger
both rules.

+24 -2
+13 -1
lib/rules/e325.ml
··· 21 21 let returns_option return_type = 22 22 String.ends_with ~suffix:"option" (String.trim return_type) 23 23 24 + (** Stdlib-aligned [find_*] names whose return shape is a collection (not an 25 + option): [List.find_all], [Hashtbl.find_all], etc. The name-shape is a 26 + stable signal (the stdlib enshrines the convention); do not flag these 27 + for returning a non-option. *) 28 + let is_stdlib_find_collection_name name = 29 + name = "find_all" || name = "find_many" 30 + 24 31 (** Check if a type is a type variable (e.g. ['a], ['b]) meaning merlin could 25 32 not resolve the concrete type. *) 26 33 let is_type_variable s = ··· 54 61 "find_" ^ suffix); 55 62 }) 56 63 else if 57 - (String.starts_with ~prefix:"find_" n || n = "find") && not is_option 64 + (String.starts_with ~prefix:"find_" n || n = "find") 65 + && (not is_option) 66 + (* [find_all] / [find_many] are the stdlib collection aggregators 67 + ([List.find_all], etc.); their non-option return shape is the 68 + convention, not a warning. *) 69 + && not (is_stdlib_find_collection_name n) 58 70 then 59 71 Some 60 72 (Issue.v ~loc
+11 -1
lib/rules/e331.ml
··· 1 1 (** E331: Redundant Function Prefixes *) 2 2 3 + (** Stdlib-aligned [find_*] names where stripping the [find_] prefix would 4 + lose information: [List.find_all], [Hashtbl.find_all], [List.find_map], 5 + etc. The bare suffix ([all], [map]) alone isn't descriptive enough, and 6 + the stdlib precedent establishes the full name as the natural form. *) 7 + let is_stdlib_find_alias name = 8 + name = "find_all" || name = "find_map" || name = "find_many" 9 + || name = "find_index" || name = "find_last" || name = "find_first" 10 + 3 11 type prefix_type = Create | Make | Get | Find 4 12 5 13 type payload = { ··· 66 74 let location = Outline.location filename item in 67 75 68 76 match (item.kind, location) with 69 - | Outline.Value, Some loc when not (List.mem name allowed) -> ( 77 + | Outline.Value, Some loc 78 + when (not (List.mem name allowed)) && not (is_stdlib_find_alias name) 79 + -> ( 70 80 (* Check for regular function prefix patterns *) 71 81 match check_function_prefix name with 72 82 | Some (prefix_type, suggested) ->