fix(config): deep-clone UsedChannel and TellTarget in Tab.Clone

Cherry-pick from ChatTwo upstream f35b7d3 (Infiziert90, 2026-05-12).

Tab.Clone() used to assign CurrentChannel = CurrentChannel and run
TellTarget.From(TellTarget). The first was a plain reference copy of
the UsedChannel — the clone and the source shared the same channel
state, so a channel switch or TellTarget update on a PopOut/Temp tab
also mutated its origin tab. The second was a static factory call
that read like a constructor where every other place uses Clone().

- TellTarget: static From(t) replaced by instance Clone(); only
  call-site swapped to TellTarget.Clone().
- UsedChannel: new Clone() that copies the scalar fields and runs
  Clone() on the two TellTarget references (null-safe).
- Tab.Clone(): CurrentChannel goes through UsedChannel.Clone().
This commit is contained in:
2026-05-12 20:38:12 +02:00
parent 28e4b30cd6
commit f8b5c14509
2 changed files with 32 additions and 3 deletions
+25 -2
View File
@@ -500,7 +500,7 @@ public class Tab
Opacity = Opacity,
Identifier = Identifier,
InputDisabled = InputDisabled,
CurrentChannel = CurrentChannel,
CurrentChannel = CurrentChannel.Clone(),
CanMove = CanMove,
CanResize = CanResize,
IndependentHide = IndependentHide,
@@ -512,7 +512,7 @@ public class Tab
HideWhenInactive = HideWhenInactive,
IsTempTab = IsTempTab,
AllSenderMessages = AllSenderMessages,
TellTarget = TellTarget.From(TellTarget),
TellTarget = TellTarget.Clone(),
IsGreeted = IsGreeted,
};
}
@@ -690,6 +690,29 @@ public class UsedChannel
{
Channel = channel;
}
// ---------------------------------------------------------------
// Cherry-picked from ChatTwo upstream f35b7d3 (Infiziert90, 2026-05-12)
// - Deep-clone the UsedChannel so Tab.Clone() no longer shares
// channel state (incl. TellTarget) with its origin Tab. Previously
// a reference copy: PopOut and Temp tabs mutated each other.
// - Name is intentionally a reference copy (matches upstream); it
// gets reassigned on every channel switch anyway.
// TEST-MIRROR: ../../Hellion Build test/_Helpers/UsedChannelCloneTests.cs
// ---------------------------------------------------------------
public UsedChannel Clone()
{
return new UsedChannel
{
Channel = Channel,
Name = Name,
TellTarget = TellTarget?.Clone(),
UseTempChannel = UseTempChannel,
TempChannel = TempChannel,
TempTellTarget = TempTellTarget?.Clone(),
};
}
}
[Serializable]
@@ -40,5 +40,11 @@ public class TellTarget
public static TellTarget Empty() => new(string.Empty, 0, 0, TellReason.Direct);
public static TellTarget From(TellTarget t) => new(t.Name, t.World, t.ContentId, t.Reason);
// ---------------------------------------------------------------
// Cherry-picked from ChatTwo upstream f35b7d3 (Infiziert90, 2026-05-12)
// - Replaced static From(t) with an instance-style Clone() so call
// sites read like a copy operation, not a factory.
// TEST-MIRROR: ../../../Hellion Build test/_Helpers/TellTargetCloneTests.cs
// ---------------------------------------------------------------
public TellTarget Clone() => new(Name, World, ContentId, Reason);
}