Skip to content

Two method-search queries ignore the environment they are given, so results outside environment 0 are invisible #475

Description

@ericwinger

Summary

Two method-search queries accept an environmentId and then ignore it, so they always search
method environment 0. Every caller loops 0..gemstone.maxEnvironment over them, which means a
method that lives in a higher environment is invisible to the search — and the loop does N
identical full-image scans to produce the same environment-0 answer each time.

Both are the same species of bug and the same shape of fix, so they belong together.

1. referencesToObject builds its organizer without an environment

client/src/queries/methodSearch.tsreferencesToObject

methods := (ClassOrganizer new referencesToObject:
  (System myUserProfile symbolList objectNamed: #'...')).

The environmentId argument reaches methodSerialization(environmentId) only. The organizer is
built bare, so the scan itself always runs in environment 0. Compare sendersOf a few lines
above, which correctly does ClassOrganizer new environmentId: N; yourself.

Affected callers, all of which sweep environments:

  • Browse References (extension.ts, gemstone.browseReferences)
  • GemStone Search, references pivot (omniSearch/omniSearchCommand.ts)
  • the MCP references tool (mcpTools.ts)

Minor, same function: the result is handed to methodSerialization without asArray, which then
indexes it with at: i.

2. hierarchyImplementorsOf selects with environment-0-only reflection

client/src/queries/methodSearch.tshierarchyImplementorsOf

(cur includesSelector: #'sel') ifTrue: [methods add: (cur compiledMethodAt: #'sel')].

includesSelector: and the bare compiledMethodAt: are both environment-0 only, so an
implementor that exists only in a higher environment is never collected — in either direction of
the walk. Its caller (gemstone.hierarchyImplementorsOf in extension.ts) loops environments
over it, so superclass implementors and subclass overrides outside environment 0 are invisible
where that command is used.

Confirmed on a live stone

PrbUser>>usesInEnv0 compiled into environment 0 and PrbUser>>usesInEnv1 into environment 1,
both referencing PrbTarget:

expression answer
ClassOrganizer new referencesToObject: PrbTarget PrbUser>>usesInEnv0
(ClassOrganizer new environmentId: 1; yourself) referencesToObject: PrbTarget PrbUser>>usesInEnv1
PrbUser includesSelector: #usesInEnv1 false
PrbUser compiledMethodAt: #usesInEnv1 environmentId: 1 otherwise: nil the method
PrbUser selectorsForEnvironment: 1 #(usesInEnv1)

So the underlying reflection honours the environment in every case; these two queries just never
pass it on.

Suggested fix

  1. Put the environment on the organizer:
    ((ClassOrganizer new environmentId: N; yourself) referencesToObject: obj) asArray.
  2. In the hierarchy walk, select per environment — compiledMethodAt:environmentId:otherwise:
    and test the result for nil, rather than gating on includesSelector:.

Why this is filed separately

The same two bugs were fixed for the safe-delete guard in
#433, where a missed reference meant a class or
variable could be deleted while the user was told nothing referenced it. That work deliberately
did not touch these two, because they are pre-existing, already shipped, and affect commands
outside that feature. The fixes there are a working model for these:

  • scanning references to a class now sets the environment on the organizer;
  • the instance- and class-variable scans now enumerate with selectorsForEnvironment: instead of
    selectors, which has the same environment-0-only limitation as includesSelector:;
  • found methods now carry the environment they were found in, so a selector implemented in two
    environments counts as two methods and each opens the document it actually lives in.

That last point is worth pairing with this work: the result rows produced by these two queries
feed the same shared picker, which until #433 opened every result as environment 0.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingideIDE component

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions