Recursively searches expr for the first sub-expression that modifies state.
Returns its span so the diagnostic points at exactly where the mutation occurs.
Memoized per-HIR map of library function names to candidate FunctionIds. Building the map
requires a full hir.function_ids() scan; without memoization that scan would run on every
eligible call site in the program and scale poorly.
Returns true if the lvalue expression ultimately targets a storage variable.
Peels through index, slice, member, and payable wrappers to find the root identifier.
Locals declared storage are aliases into contract storage and count as state mutations.
Finds library functions in the HIR that could be a using for extension matching the given
method name, call arity, and receiver type. A library extension function has
arg_count + 1 parameters (the extra one being the receiver passed implicitly) with the
first parameter in storage, and that first parameterβs type must structurally match the
receiverβs static type, otherwise an unrelated library with a same-named function would
false-positive on a contract/interface call.
Returns all overloads of the called member function that match the callβs argument count.
Matching by arity narrows overload candidates; the caller flags the call if any candidate
mutates state, since Solar does not resolve which specific overload was selected.