# UNDF: UNDF-2026-000000266 From: agent-blackops Date: Thu, 26 Mar 2026 00:00:00 +0000 Subject: [PATCH] api_map/constants: remove skip.to_a conversion in inner_get_constants CWE-407: Algorithmic complexity via unnecessary Array conversion of a Set inside a recursive method in Constants#inner_get_constants. `skip` is already a Set throughout the call chain — it is created as `Set.new` in `collect_and_cache` and passed into `inner_qualify` as `Set.new` in `qualify_namespace`. However, inside `inner_get_constants` two lines call `pin.closure.gates - skip.to_a`: pre_fqns = resolve(pre.name, pin.closure.gates - skip.to_a) # line 262 inc_fqns = resolve(pin.name, pin.closure.gates - skip.to_a) # line 267 `skip.to_a` allocates a new Array on every call. `gates - array` performs an O(|gates| × |skip|) set-difference by linear scan. Because `inner_get_constants` is recursive (called for prepends, includes, and superclass chains), the total cost is O(depth × |gates| × |skip|²) per `collect` call. Fix: pass `skip` directly. `Array - Set` is supported in Ruby (Set responds to `include?` which Array#- uses internally via Enumerable), so `gates - skip` is O(|gates|) with O(1) per-element lookup. No `.to_a` allocation needed. Defect-Id: solargraph-0002 Severity: MEDIUM CWE: CWE-407 (Inefficient Algorithmic Complexity) --- lib/solargraph/api_map/constants.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/solargraph/api_map/constants.rb b/lib/solargraph/api_map/constants.rb index xxxxxxx..yyyyyyy 100644 --- a/lib/solargraph/api_map/constants.rb +++ b/lib/solargraph/api_map/constants.rb @@ -258,10 +258,10 @@ module Solargraph def inner_get_constants fqns, visibility, skip return [] if fqns.nil? || skip.include?(fqns) skip.add fqns result = [] store.get_prepends(fqns).each do |pre| - pre_fqns = resolve(pre.name, pre.closure.gates - skip.to_a) + pre_fqns = resolve(pre.name, pre.closure.gates - skip) # CWE-407 fix: skip is Set, no .to_a result.concat inner_get_constants(pre_fqns, [:public], skip) end result.concat(store.get_constants(fqns, visibility).sort { |a, b| a.name <=> b.name }) store.get_includes(fqns).each do |pin| - inc_fqns = resolve(pin.name, pin.closure.gates - skip.to_a) + inc_fqns = resolve(pin.name, pin.closure.gates - skip) # CWE-407 fix: skip is Set, no .to_a result.concat inner_get_constants(inc_fqns, [:public], skip) end