1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! Elixir: keyword `Call` identity (`def`, `defmodule`, `quote`, …),
//! and applied versus named operators.
use crateElixir;
use crate;
/// Reads the text of the `target` field of an Elixir `Call` node.
///
/// Most of Elixir's control-flow constructs (`if`, `unless`, `for`,
/// `while`, `case`, `cond`, `with`, `try`) and method-defining macros
/// (`def`, `defp`, `defmacro`, …) parse as `Call` nodes whose `target`
/// is an `Identifier` whose source text spells the keyword. The
/// `Cyclomatic` and `Exit` impls already follow this pattern; this
/// helper centralises the byte-text lookup so `Cognitive` and `Abc`
/// can share it.
///
/// Returns `None` for Calls whose target is not a simple identifier
/// (e.g. `Module.func(…)` parses as `RemoteCallWithParentheses` with
/// the dotted name as target) or when the bytes are not valid UTF-8.
/// Method-defining macros (`def`, `defp`, `defmacro`, `defmacrop`). The set
/// is duplicated across checker, getter, and several metric impls
/// because each consults it from a different trait surface; centralising
/// the literal here keeps future additions (e.g. `defguard`) consistent.
/// Class-defining macro (`defmodule`). Paired with [`elixir_is_method_macro`]
/// where a caller needs both ("any space-opening declaration").
/// Returns true when `node` is lexically nested inside the `do_block` of a
/// `quote do … end` Call (Elixir's metaprogramming template). A `def` /
/// `defp` / `defmacro` / `defmacrop` inside `quote` does not define a
/// method of any enclosing module — the syntax tree is a code template
/// emitted later, when the surrounding macro is invoked. Treating those
/// quoted Calls as methods inflates `Wmc` and disagrees with `Npm`'s
/// direct-children classification (#310).
///
/// Walks the ancestor chain looking for a `quote` Call ancestor. Stops at
/// the first match (true) or at the root (false). Each step is a single
/// `child_by_field_name("target")` + identifier byte compare, so the cost
/// is O(steps) when `ancestors` is known — with `Ancestors::unknown` each
/// step additionally pays `Node::parent`'s O(depth) (#1084).
/// Iterates the direct-child `Call` nodes inside the `do_block` of an
/// Elixir Call (typically a `defmodule`). Used by `Npm` / `Npa` to scan
/// a module body for method-defining macros / `defstruct` without
/// descending into nested modules. Yields no items when the Call has
/// no `do_block`.
+ 'a
/// The `binary_operator` that applies `op`, an operator token, or `None`
/// when the token is not applied there.
///
/// An operator token also *names* the operator: `&==/2`, `&and/2` and
/// `Kernel.||(a, b)` hold it inside an `operator_identifier`, and the
/// single-token `atom` / `keyword` spell it too. None of those is a
/// `binary_operator` with operands to compare or chain, and under error
/// recovery the parent can be an `ERROR` with no operands, so every
/// decision metric keys on this parent rather than on the token (#1531,
/// #1534). A remote call that names the operator still *applies* it,
/// though; see [`elixir_remote_call_applies`].
///
/// Matched by rule name rather than by `kind_id`: the grammar aliases
/// `binary_operator` to three ids (`Elixir::BinaryOperator` through
/// `BinaryOperator3`), and a name comparison stays correct when a bump
/// adds a fourth (grammar-dispatch §1).
/// Whether `op`, an operator token, is the name of a remote call on
/// `Kernel` with arguments: `Kernel.||(a, b)`, or `x |> Kernel.||(y)`,
/// which the pipe rewrites to it. Such a call expands the `Kernel` macro
/// exactly as `a || b` does, so it short-circuits and decides as the
/// operator does, where a capture (`&Kernel.||/2`, a call with no
/// arguments) only names it. It has no `binary_operator`, so it carries no
/// `left` / `right` operands either.
///
/// The receiver must spell `Kernel` (or `Elixir.Kernel`): a user module
/// may define `||/2` as an ordinary function, and `Foo.||(a, b)` neither
/// short-circuits nor decides.
///
/// Matched by rule name: `dot` and `arguments` are aliased to several
/// ids each (grammar-dispatch §1).